From 507b2860cfe0bb4a712064f1c503caa9a7325886 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 31 Jul 2013 16:12:13 -0700 Subject: Consistent style for comparisons of raw pointers to NULL Change-Id: Iec102a5ccb2fe69229887b5432cd1fb66f26f0cf --- media/libmedia/IAudioFlinger.cpp | 50 +++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 16 deletions(-) (limited to 'media') diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index be818c6..22ad453 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -132,7 +132,7 @@ public: lStatus = reply.readInt32(); track = interface_cast(reply.readStrongBinder()); } - if (status) { + if (status != NULL) { *status = lStatus; } return track; @@ -180,7 +180,7 @@ public: lStatus = reply.readInt32(); record = interface_cast(reply.readStrongBinder()); } - if (status) { + if (status != NULL) { *status = lStatus; } return record; @@ -397,15 +397,25 @@ public: audio_io_handle_t output = (audio_io_handle_t) reply.readInt32(); ALOGV("openOutput() returned output, %d", output); devices = (audio_devices_t)reply.readInt32(); - if (pDevices != NULL) *pDevices = devices; + if (pDevices != NULL) { + *pDevices = devices; + } samplingRate = reply.readInt32(); - if (pSamplingRate != NULL) *pSamplingRate = samplingRate; + if (pSamplingRate != NULL) { + *pSamplingRate = samplingRate; + } format = (audio_format_t) reply.readInt32(); - if (pFormat != NULL) *pFormat = format; + if (pFormat != NULL) { + *pFormat = format; + } channelMask = (audio_channel_mask_t)reply.readInt32(); - if (pChannelMask != NULL) *pChannelMask = channelMask; + if (pChannelMask != NULL) { + *pChannelMask = channelMask; + } latency = reply.readInt32(); - if (pLatencyMs != NULL) *pLatencyMs = latency; + if (pLatencyMs != NULL) { + *pLatencyMs = latency; + } return output; } @@ -469,13 +479,21 @@ public: remote()->transact(OPEN_INPUT, data, &reply); audio_io_handle_t input = (audio_io_handle_t) reply.readInt32(); devices = (audio_devices_t)reply.readInt32(); - if (pDevices != NULL) *pDevices = devices; + if (pDevices != NULL) { + *pDevices = devices; + } samplingRate = reply.readInt32(); - if (pSamplingRate != NULL) *pSamplingRate = samplingRate; + if (pSamplingRate != NULL) { + *pSamplingRate = samplingRate; + } format = (audio_format_t) reply.readInt32(); - if (pFormat != NULL) *pFormat = format; + if (pFormat != NULL) { + *pFormat = format; + } channelMask = (audio_channel_mask_t)reply.readInt32(); - if (pChannelMask != NULL) *pChannelMask = channelMask; + if (pChannelMask != NULL) { + *pChannelMask = channelMask; + } return input; } @@ -517,11 +535,11 @@ public: status_t status = reply.readInt32(); if (status == NO_ERROR) { uint32_t tmp = reply.readInt32(); - if (halFrames) { + if (halFrames != NULL) { *halFrames = tmp; } tmp = reply.readInt32(); - if (dspFrames) { + if (dspFrames != NULL) { *dspFrames = tmp; } } @@ -639,7 +657,7 @@ public: if (pDesc == NULL) { return effect; - if (status) { + if (status != NULL) { *status = BAD_VALUE; } } @@ -657,7 +675,7 @@ public: } else { lStatus = reply.readInt32(); int tmp = reply.readInt32(); - if (id) { + if (id != NULL) { *id = tmp; } tmp = reply.readInt32(); @@ -667,7 +685,7 @@ public: effect = interface_cast(reply.readStrongBinder()); reply.read(pDesc, sizeof(effect_descriptor_t)); } - if (status) { + if (status != NULL) { *status = lStatus; } -- cgit v1.1 From fffe959060c5c5a2aeb45709e10fb1cc426ec732 Mon Sep 17 00:00:00 2001 From: Sungsoo Lim Date: Thu, 29 Aug 2013 15:12:56 +0900 Subject: Fix test build for libstagefright_timedtext moudle Change-Id: Id113743c1531509fbca7a1fa7125056d6d7f1213 --- media/libstagefright/timedtext/test/Android.mk | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/timedtext/test/Android.mk b/media/libstagefright/timedtext/test/Android.mk index a5e7ba2..9a9fde2 100644 --- a/media/libstagefright/timedtext/test/Android.mk +++ b/media/libstagefright/timedtext/test/Android.mk @@ -2,7 +2,6 @@ LOCAL_PATH:= $(call my-dir) # ================================================================ # Unit tests for libstagefright_timedtext -# See also /development/testrunner/test_defs.xml # ================================================================ # ================================================================ @@ -18,10 +17,13 @@ LOCAL_SRC_FILES := TimedTextSRTSource_test.cpp LOCAL_C_INCLUDES := \ $(TOP)/external/expat/lib \ - $(TOP)/frameworks/base/media/libstagefright/timedtext + $(TOP)/frameworks/av/media/libstagefright/timedtext LOCAL_SHARED_LIBRARIES := \ + libbinder \ libexpat \ - libstagefright + libstagefright \ + libstagefright_foundation \ + libutils include $(BUILD_NATIVE_TEST) -- cgit v1.1 From d089c2540e4f0897c166693f4f13e2023241720e Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 29 Aug 2013 09:31:26 -0700 Subject: Fix decoder EOS handling Conceptually it should be the same whether EOS is signalled on the last buffer holding data, or an empty buffer that follows. Make it so that this actually behaves the same for mp3, AAC and Vorbis. b/8747869 Change-Id: Idece8ef45689a3ffaf70fb45d19862d7b93b2f92 --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 217 ++++++++++----------- media/libstagefright/codecs/aacdec/SoftAAC2.h | 2 + media/libstagefright/codecs/mp3dec/SoftMP3.cpp | 114 ++++++----- media/libstagefright/codecs/mp3dec/SoftMP3.h | 2 + .../codecs/vorbis/dec/SoftVorbis.cpp | 79 ++++---- .../libstagefright/codecs/vorbis/dec/SoftVorbis.h | 2 + 6 files changed, 213 insertions(+), 203 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 1b20cbb..c9b5d26 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -58,6 +58,8 @@ SoftAAC2::SoftAAC2( mIsADTS(false), mInputBufferCount(0), mSignalledError(false), + mSawInputEos(false), + mSignalledOutputEos(false), mAnchorTimeUs(0), mNumSamplesOutput(0), mOutputPortSettingsChange(NONE) { @@ -350,115 +352,83 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { return; } - while (!inQueue.empty() && !outQueue.empty()) { - BufferInfo *inInfo = *inQueue.begin(); - OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; + while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) { + BufferInfo *inInfo = NULL; + OMX_BUFFERHEADERTYPE *inHeader = NULL; + if (!inQueue.empty()) { + inInfo = *inQueue.begin(); + inHeader = inInfo->mHeader; + } BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; + outHeader->nFlags = 0; - if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { - inQueue.erase(inQueue.begin()); - inInfo->mOwnedByUs = false; - notifyEmptyBufferDone(inHeader); - - if (mDecoderHasData) { - // flush out the decoder's delayed data by calling DecodeFrame - // one more time, with the AACDEC_FLUSH flag set - INT_PCM *outBuffer = - reinterpret_cast( - outHeader->pBuffer + outHeader->nOffset); - - AAC_DECODER_ERROR decoderErr = - aacDecoder_DecodeFrame(mAACDecoder, - outBuffer, - outHeader->nAllocLen, - AACDEC_FLUSH); - mDecoderHasData = false; - - if (decoderErr != AAC_DEC_OK) { - mSignalledError = true; - - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, - NULL); - - return; - } - - outHeader->nFilledLen = - mStreamInfo->frameSize - * sizeof(int16_t) - * mStreamInfo->numChannels; - } else { - // we never submitted any data to the decoder, so there's nothing to flush out - outHeader->nFilledLen = 0; + if (inHeader) { + if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { + mSawInputEos = true; } - outHeader->nFlags = OMX_BUFFERFLAG_EOS; - - outQueue.erase(outQueue.begin()); - outInfo->mOwnedByUs = false; - notifyFillBufferDone(outHeader); - return; - } - - if (inHeader->nOffset == 0) { - mAnchorTimeUs = inHeader->nTimeStamp; - mNumSamplesOutput = 0; - } + if (inHeader->nOffset == 0 && inHeader->nFilledLen) { + mAnchorTimeUs = inHeader->nTimeStamp; + mNumSamplesOutput = 0; + } - size_t adtsHeaderSize = 0; - if (mIsADTS) { - // skip 30 bits, aac_frame_length follows. - // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? + if (mIsADTS) { + size_t adtsHeaderSize = 0; + // skip 30 bits, aac_frame_length follows. + // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? - const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset; + const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset; - bool signalError = false; - if (inHeader->nFilledLen < 7) { - ALOGE("Audio data too short to contain even the ADTS header. " - "Got %ld bytes.", inHeader->nFilledLen); - hexdump(adtsHeader, inHeader->nFilledLen); - signalError = true; - } else { - bool protectionAbsent = (adtsHeader[1] & 1); - - unsigned aac_frame_length = - ((adtsHeader[3] & 3) << 11) - | (adtsHeader[4] << 3) - | (adtsHeader[5] >> 5); - - if (inHeader->nFilledLen < aac_frame_length) { - ALOGE("Not enough audio data for the complete frame. " - "Got %ld bytes, frame size according to the ADTS " - "header is %u bytes.", - inHeader->nFilledLen, aac_frame_length); + bool signalError = false; + if (inHeader->nFilledLen < 7) { + ALOGE("Audio data too short to contain even the ADTS header. " + "Got %ld bytes.", inHeader->nFilledLen); hexdump(adtsHeader, inHeader->nFilledLen); signalError = true; } else { - adtsHeaderSize = (protectionAbsent ? 7 : 9); - - inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize; - inBufferLength[0] = aac_frame_length - adtsHeaderSize; - - inHeader->nOffset += adtsHeaderSize; - inHeader->nFilledLen -= adtsHeaderSize; + bool protectionAbsent = (adtsHeader[1] & 1); + + unsigned aac_frame_length = + ((adtsHeader[3] & 3) << 11) + | (adtsHeader[4] << 3) + | (adtsHeader[5] >> 5); + + if (inHeader->nFilledLen < aac_frame_length) { + ALOGE("Not enough audio data for the complete frame. " + "Got %ld bytes, frame size according to the ADTS " + "header is %u bytes.", + inHeader->nFilledLen, aac_frame_length); + hexdump(adtsHeader, inHeader->nFilledLen); + signalError = true; + } else { + adtsHeaderSize = (protectionAbsent ? 7 : 9); + + inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize; + inBufferLength[0] = aac_frame_length - adtsHeaderSize; + + inHeader->nOffset += adtsHeaderSize; + inHeader->nFilledLen -= adtsHeaderSize; + } } - } - if (signalError) { - mSignalledError = true; + if (signalError) { + mSignalledError = true; - notify(OMX_EventError, - OMX_ErrorStreamCorrupt, - ERROR_MALFORMED, - NULL); + notify(OMX_EventError, + OMX_ErrorStreamCorrupt, + ERROR_MALFORMED, + NULL); - return; + return; + } + } else { + inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; + inBufferLength[0] = inHeader->nFilledLen; } } else { - inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; - inBufferLength[0] = inHeader->nFilledLen; + inBufferLength[0] = 0; } // Fill and decode @@ -471,50 +441,66 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { int prevNumChannels = mStreamInfo->numChannels; AAC_DECODER_ERROR decoderErr = AAC_DEC_NOT_ENOUGH_BITS; - while (bytesValid[0] > 0 && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { + while ((bytesValid[0] > 0 || mSawInputEos) && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { + mDecoderHasData |= (bytesValid[0] > 0); aacDecoder_Fill(mAACDecoder, inBuffer, inBufferLength, bytesValid); - mDecoderHasData = true; decoderErr = aacDecoder_DecodeFrame(mAACDecoder, outBuffer, outHeader->nAllocLen, 0 /* flags */); - if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { - ALOGW("Not enough bits, bytesValid %d", bytesValid[0]); + if (mSawInputEos && bytesValid[0] <= 0) { + if (mDecoderHasData) { + // flush out the decoder's delayed data by calling DecodeFrame + // one more time, with the AACDEC_FLUSH flag set + decoderErr = aacDecoder_DecodeFrame(mAACDecoder, + outBuffer, + outHeader->nAllocLen, + AACDEC_FLUSH); + mDecoderHasData = false; + } + outHeader->nFlags = OMX_BUFFERFLAG_EOS; + mSignalledOutputEos = true; + break; + } else { + ALOGW("Not enough bits, bytesValid %d", bytesValid[0]); + } } } size_t numOutBytes = mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; - if (decoderErr == AAC_DEC_OK) { - UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; - inHeader->nFilledLen -= inBufferUsedLength; - inHeader->nOffset += inBufferUsedLength; - } else { - ALOGW("AAC decoder returned error %d, substituting silence", - decoderErr); + if (inHeader) { + if (decoderErr == AAC_DEC_OK) { + UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; + inHeader->nFilledLen -= inBufferUsedLength; + inHeader->nOffset += inBufferUsedLength; + } else { + ALOGW("AAC decoder returned error %d, substituting silence", + decoderErr); - memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes); + memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes); - // Discard input buffer. - inHeader->nFilledLen = 0; + // Discard input buffer. + inHeader->nFilledLen = 0; - aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); + aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); - // fall through - } + // fall through + } - if (inHeader->nFilledLen == 0) { - inInfo->mOwnedByUs = false; - inQueue.erase(inQueue.begin()); - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + inQueue.erase(inQueue.begin()); + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } } /* @@ -555,7 +541,6 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { // we've previously decoded valid data, in the latter case // (decode failed) we'll output a silent frame. outHeader->nFilledLen = numOutBytes; - outHeader->nFlags = 0; outHeader->nTimeStamp = mAnchorTimeUs @@ -606,6 +591,8 @@ void SoftAAC2::onReset() { mStreamInfo->sampleRate = 0; mSignalledError = false; + mSawInputEos = false; + mSignalledOutputEos = false; mOutputPortSettingsChange = NONE; } diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h index 2d960ab..a7ea1e2 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.h +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h @@ -55,6 +55,8 @@ private: bool mDecoderHasData; size_t mInputBufferCount; bool mSignalledError; + bool mSawInputEos; + bool mSignalledOutputEos; int64_t mAnchorTimeUs; int64_t mNumSamplesOutput; diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp index 7c382fb..877e3cb 100644 --- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp +++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp @@ -49,6 +49,8 @@ SoftMP3::SoftMP3( mNumChannels(2), mSamplingRate(44100), mSignalledError(false), + mSawInputEos(false), + mSignalledOutputEos(false), mOutputPortSettingsChange(NONE) { initPorts(); initDecoder(); @@ -194,48 +196,36 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) { List &inQueue = getPortQueue(0); List &outQueue = getPortQueue(1); - while (!inQueue.empty() && !outQueue.empty()) { - BufferInfo *inInfo = *inQueue.begin(); - OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; + while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) { + BufferInfo *inInfo = NULL; + OMX_BUFFERHEADERTYPE *inHeader = NULL; + if (!inQueue.empty()) { + inInfo = *inQueue.begin(); + inHeader = inInfo->mHeader; + } BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; + outHeader->nFlags = 0; - if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { - inQueue.erase(inQueue.begin()); - inInfo->mOwnedByUs = false; - notifyEmptyBufferDone(inHeader); - - if (!mIsFirst) { - // pad the end of the stream with 529 samples, since that many samples - // were trimmed off the beginning when decoding started - outHeader->nFilledLen = - kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t); + if (inHeader) { + if (inHeader->nOffset == 0 && inHeader->nFilledLen) { + mAnchorTimeUs = inHeader->nTimeStamp; + mNumFramesOutput = 0; + } - memset(outHeader->pBuffer, 0, outHeader->nFilledLen); - } else { - // Since we never discarded frames from the start, we won't have - // to add any padding at the end either. - outHeader->nFilledLen = 0; + if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { + mSawInputEos = true; } - outHeader->nFlags = OMX_BUFFERFLAG_EOS; + mConfig->pInputBuffer = + inHeader->pBuffer + inHeader->nOffset; - outQueue.erase(outQueue.begin()); - outInfo->mOwnedByUs = false; - notifyFillBufferDone(outHeader); - return; - } - - if (inHeader->nOffset == 0) { - mAnchorTimeUs = inHeader->nTimeStamp; - mNumFramesOutput = 0; + mConfig->inputBufferCurrentLength = inHeader->nFilledLen; + } else { + mConfig->pInputBuffer = NULL; + mConfig->inputBufferCurrentLength = 0; } - - mConfig->pInputBuffer = - inHeader->pBuffer + inHeader->nOffset; - - mConfig->inputBufferCurrentLength = inHeader->nFilledLen; mConfig->inputBufferMaxLength = 0; mConfig->inputBufferUsedLength = 0; @@ -262,13 +252,28 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) { mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t); } - // This is recoverable, just ignore the current frame and - // play silence instead. - memset(outHeader->pBuffer, - 0, - mConfig->outputFrameSize * sizeof(int16_t)); - - mConfig->inputBufferUsedLength = inHeader->nFilledLen; + if (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR && mSawInputEos) { + if (!mIsFirst) { + // pad the end of the stream with 529 samples, since that many samples + // were trimmed off the beginning when decoding started + outHeader->nOffset = 0; + outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t); + + memset(outHeader->pBuffer, 0, outHeader->nFilledLen); + } + outHeader->nFlags = OMX_BUFFERFLAG_EOS; + mSignalledOutputEos = true; + } else { + // This is recoverable, just ignore the current frame and + // play silence instead. + memset(outHeader->pBuffer, + 0, + mConfig->outputFrameSize * sizeof(int16_t)); + + if (inHeader) { + mConfig->inputBufferUsedLength = inHeader->nFilledLen; + } + } } else if (mConfig->samplingRate != mSamplingRate || mConfig->num_channels != mNumChannels) { mSamplingRate = mConfig->samplingRate; @@ -289,7 +294,7 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) { outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset; - } else { + } else if (!mSignalledOutputEos) { outHeader->nOffset = 0; outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t); } @@ -298,23 +303,24 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) { mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mConfig->samplingRate; - outHeader->nFlags = 0; - - CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength); + if (inHeader) { + CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength); - inHeader->nOffset += mConfig->inputBufferUsedLength; - inHeader->nFilledLen -= mConfig->inputBufferUsedLength; + inHeader->nOffset += mConfig->inputBufferUsedLength; + inHeader->nFilledLen -= mConfig->inputBufferUsedLength; - mNumFramesOutput += mConfig->outputFrameSize / mNumChannels; - if (inHeader->nFilledLen == 0) { - inInfo->mOwnedByUs = false; - inQueue.erase(inQueue.begin()); - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + inQueue.erase(inQueue.begin()); + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } } + mNumFramesOutput += mConfig->outputFrameSize / mNumChannels; + outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; @@ -362,6 +368,8 @@ void SoftMP3::onReset() { pvmp3_InitDecoder(mConfig, mDecoderBuf); mIsFirst = true; mSignalledError = false; + mSawInputEos = false; + mSignalledOutputEos = false; mOutputPortSettingsChange = NONE; } diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.h b/media/libstagefright/codecs/mp3dec/SoftMP3.h index 4af91ea..f9e7b53 100644 --- a/media/libstagefright/codecs/mp3dec/SoftMP3.h +++ b/media/libstagefright/codecs/mp3dec/SoftMP3.h @@ -61,6 +61,8 @@ private: bool mIsFirst; bool mSignalledError; + bool mSawInputEos; + bool mSignalledOutputEos; enum { NONE, diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp index 51bb958..515e4d3 100644 --- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp +++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp @@ -54,6 +54,8 @@ SoftVorbis::SoftVorbis( mAnchorTimeUs(0), mNumFramesOutput(0), mNumFramesLeftOnPage(-1), + mSawInputEos(false), + mSignalledOutputEos(false), mOutputPortSettingsChange(NONE) { initPorts(); CHECK_EQ(initDecoder(), (status_t)OK); @@ -290,48 +292,47 @@ void SoftVorbis::onQueueFilled(OMX_U32 portIndex) { return; } - while (!inQueue.empty() && !outQueue.empty()) { - BufferInfo *inInfo = *inQueue.begin(); - OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; + while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) { + BufferInfo *inInfo = NULL; + OMX_BUFFERHEADERTYPE *inHeader = NULL; + if (!inQueue.empty()) { + inInfo = *inQueue.begin(); + inHeader = inInfo->mHeader; + } BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; - if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { - inQueue.erase(inQueue.begin()); - inInfo->mOwnedByUs = false; - notifyEmptyBufferDone(inHeader); + int32_t numPageSamples = 0; - outHeader->nFilledLen = 0; - outHeader->nFlags = OMX_BUFFERFLAG_EOS; + if (inHeader) { + if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { + mSawInputEos = true; + } - outQueue.erase(outQueue.begin()); - outInfo->mOwnedByUs = false; - notifyFillBufferDone(outHeader); - return; - } + if (inHeader->nFilledLen || !mSawInputEos) { + CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples)); + memcpy(&numPageSamples, + inHeader->pBuffer + + inHeader->nOffset + inHeader->nFilledLen - 4, + sizeof(numPageSamples)); - int32_t numPageSamples; - CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples)); - memcpy(&numPageSamples, - inHeader->pBuffer - + inHeader->nOffset + inHeader->nFilledLen - 4, - sizeof(numPageSamples)); + if (inHeader->nOffset == 0) { + mAnchorTimeUs = inHeader->nTimeStamp; + mNumFramesOutput = 0; + } - if (numPageSamples >= 0) { - mNumFramesLeftOnPage = numPageSamples; + inHeader->nFilledLen -= sizeof(numPageSamples);; + } } - if (inHeader->nOffset == 0) { - mAnchorTimeUs = inHeader->nTimeStamp; - mNumFramesOutput = 0; + if (numPageSamples >= 0) { + mNumFramesLeftOnPage = numPageSamples; } - inHeader->nFilledLen -= sizeof(numPageSamples);; - ogg_buffer buf; - buf.data = inHeader->pBuffer + inHeader->nOffset; - buf.size = inHeader->nFilledLen; + buf.data = inHeader ? inHeader->pBuffer + inHeader->nOffset : NULL; + buf.size = inHeader ? inHeader->nFilledLen : 0; buf.refcount = 1; buf.ptr.owner = NULL; @@ -351,6 +352,7 @@ void SoftVorbis::onQueueFilled(OMX_U32 portIndex) { int numFrames = 0; + outHeader->nFlags = 0; int err = vorbis_dsp_synthesis(mState, &pack, 1); if (err != 0) { ALOGW("vorbis_dsp_synthesis returned %d", err); @@ -370,13 +372,16 @@ void SoftVorbis::onQueueFilled(OMX_U32 portIndex) { ALOGV("discarding %d frames at end of page", numFrames - mNumFramesLeftOnPage); numFrames = mNumFramesLeftOnPage; + if (mSawInputEos) { + outHeader->nFlags = OMX_BUFFERFLAG_EOS; + mSignalledOutputEos = true; + } } mNumFramesLeftOnPage -= numFrames; } outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels; outHeader->nOffset = 0; - outHeader->nFlags = 0; outHeader->nTimeStamp = mAnchorTimeUs @@ -384,11 +389,13 @@ void SoftVorbis::onQueueFilled(OMX_U32 portIndex) { mNumFramesOutput += numFrames; - inInfo->mOwnedByUs = false; - inQueue.erase(inQueue.begin()); - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; + if (inHeader) { + inInfo->mOwnedByUs = false; + inQueue.erase(inQueue.begin()); + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); @@ -425,6 +432,8 @@ void SoftVorbis::onReset() { mVi = NULL; } + mSawInputEos = false; + mSignalledOutputEos = false; mOutputPortSettingsChange = NONE; } diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h index cb628a0..1d00816 100644 --- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h +++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h @@ -59,6 +59,8 @@ private: int64_t mAnchorTimeUs; int64_t mNumFramesOutput; int32_t mNumFramesLeftOnPage; + bool mSawInputEos; + bool mSignalledOutputEos; enum { NONE, -- cgit v1.1 From a664d6b45777efb8f8b7c8a391d785f6152fa8db Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Sat, 7 Sep 2013 23:38:03 -0700 Subject: HDCP: use getCaps() to query HDCP caps Bug: 10609422 Change-Id: I8bfbd761b58d5b333db38f5e3cea806abb04443c --- media/libmediaplayerservice/HDCP.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/HDCP.cpp b/media/libmediaplayerservice/HDCP.cpp index c2ac1a3..afe3936 100644 --- a/media/libmediaplayerservice/HDCP.cpp +++ b/media/libmediaplayerservice/HDCP.cpp @@ -107,11 +107,7 @@ uint32_t HDCP::getCaps() { return NO_INIT; } - // TO-DO: - // Only support HDCP_CAPS_ENCRYPT (byte-array to byte-array) for now. - // use mHDCPModule->getCaps() when the HDCP libraries get updated. - //return mHDCPModule->getCaps(); - return HDCPModule::HDCP_CAPS_ENCRYPT; + return mHDCPModule->getCaps(); } status_t HDCP::encrypt( -- cgit v1.1 From a6cdabf38b29ee98bdb3e874b4e2978dbc409624 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 18 Sep 2013 12:46:59 -0700 Subject: Fully reset SkipCutBuffer state in clear() b/8543366 Change-Id: I1b90d56ba3d672fd12b4ee91fa9ba24c665126ed --- media/libstagefright/SkipCutBuffer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/SkipCutBuffer.cpp b/media/libstagefright/SkipCutBuffer.cpp index 773854f..e2e6d79 100644 --- a/media/libstagefright/SkipCutBuffer.cpp +++ b/media/libstagefright/SkipCutBuffer.cpp @@ -25,7 +25,7 @@ namespace android { SkipCutBuffer::SkipCutBuffer(int32_t skip, int32_t cut) { - mFrontPadding = skip; + mFrontPadding = mSkip = skip; mBackPadding = cut; mWriteHead = 0; mReadHead = 0; @@ -94,6 +94,7 @@ void SkipCutBuffer::submit(const sp& buffer) { void SkipCutBuffer::clear() { mWriteHead = mReadHead = 0; + mFrontPadding = mSkip; } void SkipCutBuffer::write(const char *src, size_t num) { -- cgit v1.1 From ca1b3ee97a82a91c650da664ea2f2c47dbfaf621 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 20 Sep 2013 07:18:21 -0700 Subject: Fix aac decoder flush b/8543366 Change-Id: I746ffed6289486b802a2292bfc492ea6c780ed0b --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index c9b5d26..f842e27 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -567,6 +567,12 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { // depend on fragments from the last one decoded. // drain all existing data drainDecoder(); + // force decoder loop to drop the first decoded buffer by resetting these state variables, + // but only if initialization has already happened. + if (mInputBufferCount != 0) { + mInputBufferCount = 1; + mStreamInfo->sampleRate = 0; + } } } -- cgit v1.1 From 397edb3377e5775f4df60afb8bf6d4711e5adc0e Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 30 Aug 2013 15:10:13 -0700 Subject: Fix AudioTrack pause followed by stop Now the stop is not a nop. Bug: 10993355 Change-Id: Idfbfd6d14897574578b80648a16e0fc73765cb6c --- media/libmedia/AudioTrack.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 754a4e3..8302d4a 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -436,8 +436,7 @@ status_t AudioTrack::start() void AudioTrack::stop() { AutoMutex lock(mLock); - // FIXME pause then stop should not be a nop - if (mState != STATE_ACTIVE) { + if (mState != STATE_ACTIVE && mState != STATE_PAUSED) { return; } -- cgit v1.1 From 96f04886d1c1bfbc422e2be033ea66be83e42441 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 20 Sep 2013 09:28:56 -0700 Subject: Simplify AudioTrack stream end and fix race Bug: 10994052 Change-Id: Ib2e38e7a600bcffef8cbc68c1722e40fbbc7ea67 --- media/libmedia/AudioTrack.cpp | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 754a4e3..5e805c9 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1416,6 +1416,7 @@ nsecs_t AudioTrack::processAudioBuffer(const sp& thread) } size_t misalignment = mProxy->getMisalignment(); uint32_t sequence = mSequence; + sp proxy = mProxy; // These fields don't need to be cached, because they are assigned only by set(): // mTransfer, mCbf, mUserData, mFormat, mFrameSize, mFrameSizeAF, mFlags @@ -1424,35 +1425,32 @@ nsecs_t AudioTrack::processAudioBuffer(const sp& thread) mLock.unlock(); if (waitStreamEnd) { - AutoMutex lock(mLock); - - sp proxy = mProxy; - sp iMem = mCblkMemory; - struct timespec timeout; timeout.tv_sec = WAIT_STREAM_END_TIMEOUT_SEC; timeout.tv_nsec = 0; - mLock.unlock(); - status_t status = mProxy->waitStreamEndDone(&timeout); - mLock.lock(); + status_t status = proxy->waitStreamEndDone(&timeout); switch (status) { case NO_ERROR: case DEAD_OBJECT: case TIMED_OUT: - mLock.unlock(); mCbf(EVENT_STREAM_END, mUserData, NULL); - mLock.lock(); - if (mState == STATE_STOPPING) { - mState = STATE_STOPPED; - if (status != DEAD_OBJECT) { - return NS_INACTIVE; + { + AutoMutex lock(mLock); + // The previously assigned value of waitStreamEnd is no longer valid, + // since the mutex has been unlocked and either the callback handler + // or another thread could have re-started the AudioTrack during that time. + waitStreamEnd = mState == STATE_STOPPING; + if (waitStreamEnd) { + mState = STATE_STOPPED; } } - return 0; - default: - return 0; + if (waitStreamEnd && status != DEAD_OBJECT) { + return NS_INACTIVE; + } + break; } + return 0; } // perform callbacks while unlocked -- cgit v1.1 From 462fd2fa9eef642b0574aa7409de0bde3fec8d43 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 14 Jan 2013 14:12:05 -0800 Subject: Assign blame for playback wakelocks. Set a work source for the playback wakelock, so that playback is counted against the requesting app instead of the media server. Change-Id: I7329f88a288a95a582a78005a1c3d16a5a611e31 --- media/libmedia/AudioTrack.cpp | 20 +++++++++++++++----- media/libmedia/IAudioFlinger.cpp | 5 ++++- media/libmediaplayerservice/MediaPlayerService.cpp | 19 ++++++++++++------- media/libmediaplayerservice/MediaPlayerService.h | 3 ++- 4 files changed, 33 insertions(+), 14 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index a50ed1f..df58909 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -101,7 +101,8 @@ AudioTrack::AudioTrack( int notificationFrames, int sessionId, transfer_type transferType, - const audio_offload_info_t *offloadInfo) + const audio_offload_info_t *offloadInfo, + int uid) : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), @@ -109,7 +110,8 @@ AudioTrack::AudioTrack( { mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, - 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo); + 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, + offloadInfo, uid); } AudioTrack::AudioTrack( @@ -124,7 +126,8 @@ AudioTrack::AudioTrack( int notificationFrames, int sessionId, transfer_type transferType, - const audio_offload_info_t *offloadInfo) + const audio_offload_info_t *offloadInfo, + int uid) : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), @@ -132,7 +135,7 @@ AudioTrack::AudioTrack( { mStatus = set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags, cbf, user, notificationFrames, - sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo); + sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, uid); } AudioTrack::~AudioTrack() @@ -169,7 +172,8 @@ status_t AudioTrack::set( bool threadCanCallJava, int sessionId, transfer_type transferType, - const audio_offload_info_t *offloadInfo) + const audio_offload_info_t *offloadInfo, + int uid) { switch (transferType) { case TRANSFER_DEFAULT: @@ -313,6 +317,11 @@ status_t AudioTrack::set( mNotificationFramesReq = notificationFrames; mNotificationFramesAct = 0; mSessionId = sessionId; + if (uid == -1 || (IPCThreadState::self()->getCallingPid() != getpid())) { + mClientUid = IPCThreadState::self()->getCallingUid(); + } else { + mClientUid = uid; + } mAuxEffectId = 0; mFlags = flags; mCbf = cbf; @@ -961,6 +970,7 @@ status_t AudioTrack::createTrack_l( tid, &mSessionId, mName, + mClientUid, &status); if (track == 0) { diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index f9f6779..9df10f0 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -96,6 +96,7 @@ public: pid_t tid, int *sessionId, String8& name, + int clientUid, status_t *status) { Parcel data, reply; @@ -121,6 +122,7 @@ public: lSessionId = *sessionId; } data.writeInt32(lSessionId); + data.writeInt32(clientUid); status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply); if (lStatus != NO_ERROR) { ALOGE("createTrack error: %s", strerror(-lStatus)); @@ -780,6 +782,7 @@ status_t BnAudioFlinger::onTransact( audio_io_handle_t output = (audio_io_handle_t) data.readInt32(); pid_t tid = (pid_t) data.readInt32(); int sessionId = data.readInt32(); + int clientUid = data.readInt32(); String8 name; status_t status; sp track; @@ -791,7 +794,7 @@ status_t BnAudioFlinger::onTransact( track = createTrack( (audio_stream_type_t) streamType, sampleRate, format, channelMask, frameCount, &flags, buffer, output, tid, - &sessionId, name, &status); + &sessionId, name, clientUid, &status); } reply->writeInt32(flags); reply->writeInt32(sessionId); diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 9553458..cd052e6 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -590,7 +590,7 @@ sp MediaPlayerService::Client::setDataSource_pre( } if (!p->hardwareOutput()) { - mAudioOutput = new AudioOutput(mAudioSessionId); + mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid()); static_cast(p.get())->setAudioSink(mAudioOutput); } @@ -1296,12 +1296,13 @@ Exit: #undef LOG_TAG #define LOG_TAG "AudioSink" -MediaPlayerService::AudioOutput::AudioOutput(int sessionId) +MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid) : mCallback(NULL), mCallbackCookie(NULL), mCallbackData(NULL), mBytesWritten(0), mSessionId(sessionId), + mUid(uid), mFlags(AUDIO_OUTPUT_FLAG_NONE) { ALOGV("AudioOutput(%d)", sessionId); mStreamType = AUDIO_STREAM_MUSIC; @@ -1549,7 +1550,8 @@ status_t MediaPlayerService::AudioOutput::open( 0, // notification frames mSessionId, AudioTrack::TRANSFER_CALLBACK, - offloadInfo); + offloadInfo, + mUid); } else { t = new AudioTrack( mStreamType, @@ -1558,10 +1560,13 @@ status_t MediaPlayerService::AudioOutput::open( channelMask, frameCount, flags, - NULL, - NULL, - 0, - mSessionId); + NULL, // callback + NULL, // user data + 0, // notification frames + mSessionId, + AudioTrack::TRANSFER_DEFAULT, + NULL, // offload info + mUid); } if ((t == 0) || (t->initCheck() != NO_ERROR)) { diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 21f4117..05d44d4 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -72,7 +72,7 @@ class MediaPlayerService : public BnMediaPlayerService class CallbackData; public: - AudioOutput(int sessionId); + AudioOutput(int sessionId, int uid); virtual ~AudioOutput(); virtual bool ready() const { return mTrack != 0; } @@ -135,6 +135,7 @@ class MediaPlayerService : public BnMediaPlayerService uint32_t mSampleRateHz; // sample rate of the content, as set in open() float mMsecsPerFrame; int mSessionId; + int mUid; float mSendLevel; int mAuxEffectId; static bool mIsOnEmulator; -- cgit v1.1 From 79c5786cf5a5d572cfcf21c3d40613d86bb4093a Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 30 Oct 2013 09:47:17 -0700 Subject: Clean up channel mask handling Use type audio_channel_mask_t instead of uint32_t. Use function audio_channel_out_mask_from_count() to convert from channel count to channel mask instead of hard-coded assumption. Rename 'channels' to 'channelMask' to avoid confusion with channel count. Change-Id: I21a85e668458b773d108f95c2381eef9c4816251 --- media/libmedia/SoundPool.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp index 22e9fad..b420c95 100644 --- a/media/libmedia/SoundPool.cpp +++ b/media/libmedia/SoundPool.cpp @@ -600,16 +600,15 @@ void SoundChannel::play(const sp& sample, int nextChannelID, float leftV // wrong audio audio buffer size (mAudioBufferSize) unsigned long toggle = mToggle ^ 1; void *userData = (void *)((unsigned long)this | toggle); - uint32_t channels = (numChannels == 2) ? - AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO; + audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(numChannels); // do not create a new audio track if current track is compatible with sample parameters #ifdef USE_SHARED_MEM_BUFFER newTrack = new AudioTrack(streamType, sampleRate, sample->format(), - channels, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData); + channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData); #else newTrack = new AudioTrack(streamType, sampleRate, sample->format(), - channels, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData, + channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData, bufferFrames); #endif oldTrack = mAudioTrack; -- cgit v1.1 From 774eb18c40c3a7da0bc1636a9779f02315ddbad8 Mon Sep 17 00:00:00 2001 From: Changwan Ryu Date: Tue, 29 Oct 2013 14:31:00 +0900 Subject: Support for MPEG2 video Change-Id: If1f4e20939c96c87c65c84d56e529501facb8597 --- media/libstagefright/ACodec.cpp | 2 ++ media/libstagefright/OMXCodec.cpp | 2 ++ 2 files changed, 4 insertions(+) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 1adab38..901533c 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -965,6 +965,8 @@ status_t ACodec::setComponentRole( "audio_decoder.flac", "audio_encoder.flac" }, { MEDIA_MIMETYPE_AUDIO_MSGSM, "audio_decoder.gsm", "audio_encoder.gsm" }, + { MEDIA_MIMETYPE_VIDEO_MPEG2, + "video_decoder.mpeg2", "video_encoder.mpeg2" }, }; static const size_t kNumMimeToRole = diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 7f56af8..9f483c9 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1400,6 +1400,8 @@ void OMXCodec::setComponentRole( "audio_decoder.flac", "audio_encoder.flac" }, { MEDIA_MIMETYPE_AUDIO_MSGSM, "audio_decoder.gsm", "audio_encoder.gsm" }, + { MEDIA_MIMETYPE_VIDEO_MPEG2, + "video_decoder.mpeg2", "video_encoder.mpeg2" }, }; static const size_t kNumMimeToRole = -- cgit v1.1 From 97358c3e1adaf4a744cad78891a16d12e3e9c88e Mon Sep 17 00:00:00 2001 From: Changwan Ryu Date: Mon, 28 Oct 2013 10:53:48 +0900 Subject: Support AC3 in stagefright Change-Id: I12016b424bd069413bd6e380ff11484e175e05f3 --- media/libstagefright/ACodec.cpp | 71 +++++++++++++++++++++++++++++++++++++- media/libstagefright/MediaDefs.cpp | 1 + 2 files changed, 71 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 901533c..2d1802b 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -35,7 +35,9 @@ #include +#include #include +#include #include "include/avc_utils.h" @@ -967,6 +969,8 @@ status_t ACodec::setComponentRole( "audio_decoder.gsm", "audio_encoder.gsm" }, { MEDIA_MIMETYPE_VIDEO_MPEG2, "video_decoder.mpeg2", "video_encoder.mpeg2" }, + { MEDIA_MIMETYPE_AUDIO_AC3, + "audio_decoder.ac3", "audio_encoder.ac3" }, }; static const size_t kNumMimeToRole = @@ -1258,6 +1262,15 @@ status_t ACodec::configureCodec( } else { err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels); } + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)) { + int32_t numChannels; + int32_t sampleRate; + if (!msg->findInt32("channel-count", &numChannels) + || !msg->findInt32("sample-rate", &sampleRate)) { + err = INVALID_OPERATION; + } else { + err = setupAC3Codec(encoder, numChannels, sampleRate); + } } if (err != OK) { @@ -1454,6 +1467,44 @@ status_t ACodec::setupAACCodec( mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); } +status_t ACodec::setupAC3Codec( + bool encoder, int32_t numChannels, int32_t sampleRate) { + status_t err = setupRawAudioFormat( + encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels); + + if (err != OK) { + return err; + } + + if (encoder) { + ALOGW("AC3 encoding is not supported."); + return INVALID_OPERATION; + } + + OMX_AUDIO_PARAM_ANDROID_AC3TYPE def; + InitOMXParams(&def); + def.nPortIndex = kPortIndexInput; + + err = mOMX->getParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, + &def, + sizeof(def)); + + if (err != OK) { + return err; + } + + def.nChannels = numChannels; + def.nSampleRate = sampleRate; + + return mOMX->setParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, + &def, + sizeof(def)); +} + static OMX_AUDIO_AMRBANDMODETYPE pickModeFromBitRate( bool isAMRWB, int32_t bps) { if (isAMRWB) { @@ -2532,7 +2583,7 @@ void ACodec::sendFormatChange(const sp &reply) { { OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio; - switch (audioDef->eEncoding) { + switch ((int)audioDef->eEncoding) { case OMX_AUDIO_CodingPCM: { OMX_AUDIO_PARAM_PCMMODETYPE params; @@ -2638,6 +2689,24 @@ void ACodec::sendFormatChange(const sp &reply) { break; } + case OMX_AUDIO_CodingAndroidAC3: + { + OMX_AUDIO_PARAM_ANDROID_AC3TYPE params; + InitOMXParams(¶ms); + params.nPortIndex = kPortIndexOutput; + + CHECK_EQ((status_t)OK, mOMX->getParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, + ¶ms, + sizeof(params))); + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_AC3); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSampleRate); + break; + } + default: TRESPASS(); } diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp index b5d4e44..340cba7 100644 --- a/media/libstagefright/MediaDefs.cpp +++ b/media/libstagefright/MediaDefs.cpp @@ -42,6 +42,7 @@ const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw"; const char *MEDIA_MIMETYPE_AUDIO_FLAC = "audio/flac"; const char *MEDIA_MIMETYPE_AUDIO_AAC_ADTS = "audio/aac-adts"; const char *MEDIA_MIMETYPE_AUDIO_MSGSM = "audio/gsm"; +const char *MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3"; const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4"; const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/x-wav"; -- cgit v1.1 From d3c079ae9859011d118f94616d0069c2987013ed Mon Sep 17 00:00:00 2001 From: Changwan Ryu Date: Mon, 28 Oct 2013 11:08:44 +0900 Subject: Support TS + AC3 for ATSC standard Change-Id: I141667f3f54b242bafdf0ab9db86852c56f49ffa --- media/libstagefright/OMXCodec.cpp | 51 ++++++++ media/libstagefright/mpeg2ts/ATSParser.cpp | 6 + media/libstagefright/mpeg2ts/ATSParser.h | 4 + media/libstagefright/mpeg2ts/ESQueue.cpp | 190 +++++++++++++++++++++++++++++ media/libstagefright/mpeg2ts/ESQueue.h | 2 + 5 files changed, 253 insertions(+) (limited to 'media') diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 9f483c9..063ab49 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -40,7 +40,9 @@ #include #include +#include #include +#include #include "include/avc_utils.h" @@ -533,6 +535,17 @@ status_t OMXCodec::configureCodec(const sp &meta) { sampleRate, numChannels); } + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mMIME)) { + int32_t numChannels; + int32_t sampleRate; + CHECK(meta->findInt32(kKeyChannelCount, &numChannels)); + CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); + + status_t err = setAC3Format(numChannels, sampleRate); + if (err != OK) { + CODEC_LOGE("setAC3Format() failed (err = %d)", err); + return err; + } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_ALAW, mMIME) || !strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_MLAW, mMIME)) { // These are PCM-like formats with a fixed sample rate but @@ -1402,6 +1415,8 @@ void OMXCodec::setComponentRole( "audio_decoder.gsm", "audio_encoder.gsm" }, { MEDIA_MIMETYPE_VIDEO_MPEG2, "video_decoder.mpeg2", "video_encoder.mpeg2" }, + { MEDIA_MIMETYPE_AUDIO_AC3, + "audio_decoder.ac3", "audio_encoder.ac3" }, }; static const size_t kNumMimeToRole = @@ -3497,6 +3512,31 @@ status_t OMXCodec::setAACFormat( return OK; } +status_t OMXCodec::setAC3Format(int32_t numChannels, int32_t sampleRate) { + OMX_AUDIO_PARAM_ANDROID_AC3TYPE def; + InitOMXParams(&def); + def.nPortIndex = kPortIndexInput; + + status_t err = mOMX->getParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, + &def, + sizeof(def)); + + if (err != OK) { + return err; + } + + def.nChannels = numChannels; + def.nSampleRate = sampleRate; + + return mOMX->setParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, + &def, + sizeof(def)); +} + void OMXCodec::setG711Format(int32_t numChannels) { CHECK(!mIsEncoder); setRawAudioFormat(kPortIndexInput, 8000, numChannels); @@ -4430,6 +4470,17 @@ void OMXCodec::initOutputFormat(const sp &inputFormat) { mOutputFormat->setInt32(kKeyChannelCount, numChannels); mOutputFormat->setInt32(kKeySampleRate, sampleRate); mOutputFormat->setInt32(kKeyBitRate, bitRate); + } else if (audio_def->eEncoding == + (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidAC3) { + mOutputFormat->setCString( + kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3); + int32_t numChannels, sampleRate, bitRate; + inputFormat->findInt32(kKeyChannelCount, &numChannels); + inputFormat->findInt32(kKeySampleRate, &sampleRate); + inputFormat->findInt32(kKeyBitRate, &bitRate); + mOutputFormat->setInt32(kKeyChannelCount, numChannels); + mOutputFormat->setInt32(kKeySampleRate, sampleRate); + mOutputFormat->setInt32(kKeyBitRate, bitRate); } else { CHECK(!"Should not be here. Unknown audio encoding."); } diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index 9850a46..f87b9da 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -506,6 +506,11 @@ ATSParser::Stream::Stream( ElementaryStreamQueue::PCM_AUDIO); break; + case STREAMTYPE_AC3: + mQueue = new ElementaryStreamQueue( + ElementaryStreamQueue::AC3); + break; + default: break; } @@ -614,6 +619,7 @@ bool ATSParser::Stream::isAudio() const { case STREAMTYPE_MPEG2_AUDIO: case STREAMTYPE_MPEG2_AUDIO_ADTS: case STREAMTYPE_PCM_AUDIO: + case STREAMTYPE_AC3: return true; default: diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h index a10edc9..d4e30b4 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.h +++ b/media/libstagefright/mpeg2ts/ATSParser.h @@ -88,6 +88,10 @@ struct ATSParser : public RefBase { STREAMTYPE_MPEG2_AUDIO_ADTS = 0x0f, STREAMTYPE_MPEG4_VIDEO = 0x10, STREAMTYPE_H264 = 0x1b, + + // From ATSC A/53 Part 3:2009, 6.7.1 + STREAMTYPE_AC3 = 0x81, + STREAMTYPE_PCM_AUDIO = 0x83, }; diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp index 8f9c9c8..ea79885 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.cpp +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp @@ -56,6 +56,122 @@ void ElementaryStreamQueue::clear(bool clearFormat) { } } +// Parse AC3 header assuming the current ptr is start position of syncframe, +// update metadata only applicable, and return the payload size +static unsigned parseAC3SyncFrame( + const uint8_t *ptr, size_t size, sp *metaData) { + static const unsigned channelCountTable[] = {2, 1, 2, 3, 4, 4, 5, 6}; + static const unsigned samplingRateTable[] = {48000, 44100, 32000}; + static const unsigned rates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, + 320, 384, 448, 512, 576, 640}; + + static const unsigned frameSizeTable[19][3] = { + { 64, 69, 96 }, + { 80, 87, 120 }, + { 96, 104, 144 }, + { 112, 121, 168 }, + { 128, 139, 192 }, + { 160, 174, 240 }, + { 192, 208, 288 }, + { 224, 243, 336 }, + { 256, 278, 384 }, + { 320, 348, 480 }, + { 384, 417, 576 }, + { 448, 487, 672 }, + { 512, 557, 768 }, + { 640, 696, 960 }, + { 768, 835, 1152 }, + { 896, 975, 1344 }, + { 1024, 1114, 1536 }, + { 1152, 1253, 1728 }, + { 1280, 1393, 1920 }, + }; + + ABitReader bits(ptr, size); + unsigned syncStartPos = 0; // in bytes + if (bits.numBitsLeft() < 16) { + return 0; + } + if (bits.getBits(16) != 0x0B77) { + return 0; + } + + if (bits.numBitsLeft() < 16 + 2 + 6 + 5 + 3 + 3) { + ALOGV("Not enough bits left for further parsing"); + return 0; + } + bits.skipBits(16); // crc1 + + unsigned fscod = bits.getBits(2); + if (fscod == 3) { + ALOGW("Incorrect fscod in AC3 header"); + return 0; + } + + unsigned frmsizecod = bits.getBits(6); + if (frmsizecod > 37) { + ALOGW("Incorrect frmsizecod in AC3 header"); + return 0; + } + + unsigned bsid = bits.getBits(5); + if (bsid > 8) { + ALOGW("Incorrect bsid in AC3 header. Possibly E-AC-3?"); + return 0; + } + + unsigned bsmod = bits.getBits(3); + unsigned acmod = bits.getBits(3); + unsigned cmixlev = 0; + unsigned surmixlev = 0; + unsigned dsurmod = 0; + + if ((acmod & 1) > 0 && acmod != 1) { + if (bits.numBitsLeft() < 2) { + return 0; + } + cmixlev = bits.getBits(2); + } + if ((acmod & 4) > 0) { + if (bits.numBitsLeft() < 2) { + return 0; + } + surmixlev = bits.getBits(2); + } + if (acmod == 2) { + if (bits.numBitsLeft() < 2) { + return 0; + } + dsurmod = bits.getBits(2); + } + + if (bits.numBitsLeft() < 1) { + return 0; + } + unsigned lfeon = bits.getBits(1); + + unsigned samplingRate = samplingRateTable[fscod]; + unsigned payloadSize = frameSizeTable[frmsizecod >> 1][fscod]; + if (fscod == 1) { + payloadSize += frmsizecod & 1; + } + payloadSize <<= 1; // convert from 16-bit words to bytes + + unsigned channelCount = channelCountTable[acmod] + lfeon; + + if (metaData != NULL) { + (*metaData)->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3); + (*metaData)->setInt32(kKeyChannelCount, channelCount); + (*metaData)->setInt32(kKeySampleRate, samplingRate); + } + + return payloadSize; +} + +static bool IsSeeminglyValidAC3Header(const uint8_t *ptr, size_t size) { + return parseAC3SyncFrame(ptr, size, NULL) > 0; +} + static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) { if (size < 3) { // Not enough data to verify header. @@ -224,6 +340,33 @@ status_t ElementaryStreamQueue::appendData( break; } + case AC3: + { + uint8_t *ptr = (uint8_t *)data; + + ssize_t startOffset = -1; + for (size_t i = 0; i < size; ++i) { + if (IsSeeminglyValidAC3Header(&ptr[i], size - i)) { + startOffset = i; + break; + } + } + + if (startOffset < 0) { + return ERROR_MALFORMED; + } + + if (startOffset > 0) { + ALOGI("found something resembling an AC3 syncword at " + "offset %d", + startOffset); + } + + data = &ptr[startOffset]; + size -= startOffset; + break; + } + case MPEG_AUDIO: { uint8_t *ptr = (uint8_t *)data; @@ -328,6 +471,8 @@ sp ElementaryStreamQueue::dequeueAccessUnit() { return dequeueAccessUnitH264(); case AAC: return dequeueAccessUnitAAC(); + case AC3: + return dequeueAccessUnitAC3(); case MPEG_VIDEO: return dequeueAccessUnitMPEGVideo(); case MPEG4_VIDEO: @@ -340,6 +485,51 @@ sp ElementaryStreamQueue::dequeueAccessUnit() { } } +sp ElementaryStreamQueue::dequeueAccessUnitAC3() { + unsigned syncStartPos = 0; // in bytes + unsigned payloadSize = 0; + sp format = new MetaData; + while (true) { + if (syncStartPos + 2 >= mBuffer->size()) { + return NULL; + } + + payloadSize = parseAC3SyncFrame( + mBuffer->data() + syncStartPos, + mBuffer->size() - syncStartPos, + &format); + if (payloadSize > 0) { + break; + } + ++syncStartPos; + } + + if (mBuffer->size() < syncStartPos + payloadSize) { + ALOGV("Not enough buffer size for AC3"); + return NULL; + } + + if (mFormat == NULL) { + mFormat = format; + } + + sp accessUnit = new ABuffer(syncStartPos + payloadSize); + memcpy(accessUnit->data(), mBuffer->data(), syncStartPos + payloadSize); + + int64_t timeUs = fetchTimestamp(syncStartPos + payloadSize); + CHECK_GE(timeUs, 0ll); + accessUnit->meta()->setInt64("timeUs", timeUs); + + memmove( + mBuffer->data(), + mBuffer->data() + syncStartPos + payloadSize, + mBuffer->size() - syncStartPos - payloadSize); + + mBuffer->setRange(0, mBuffer->size() - syncStartPos - payloadSize); + + return accessUnit; +} + sp ElementaryStreamQueue::dequeueAccessUnitPCMAudio() { if (mBuffer->size() < 4) { return NULL; diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h index 66a8087..a2cca77 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.h +++ b/media/libstagefright/mpeg2ts/ESQueue.h @@ -32,6 +32,7 @@ struct ElementaryStreamQueue { enum Mode { H264, AAC, + AC3, MPEG_AUDIO, MPEG_VIDEO, MPEG4_VIDEO, @@ -67,6 +68,7 @@ private: sp dequeueAccessUnitH264(); sp dequeueAccessUnitAAC(); + sp dequeueAccessUnitAC3(); sp dequeueAccessUnitMPEGAudio(); sp dequeueAccessUnitMPEGVideo(); sp dequeueAccessUnitMPEG4Video(); -- cgit v1.1 From 8ba90326d683b035d99e24db669093e4602a7149 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 30 Oct 2013 11:29:27 -0700 Subject: Remove default channel mask for AudioTrack It doesn't make sense to have a default channel mask, since the caller needs to know what format it will use when supplying data, and there is currently no API to return the channel mask of an AudioTrack. audio_is_output_channel() does not allow 0, so it will catch any stragglers (I'm not aware of any). Also move channel mask validation earlier. Change-Id: Ia018ded8711455581a2a935f37432b049422d492 --- media/libmedia/AudioTrack.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index df58909..8319dcd 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -250,9 +250,6 @@ status_t AudioTrack::set( if (format == AUDIO_FORMAT_DEFAULT) { format = AUDIO_FORMAT_PCM_16_BIT; } - if (channelMask == 0) { - channelMask = AUDIO_CHANNEL_OUT_STEREO; - } // validate parameters if (!audio_is_valid_format(format)) { @@ -260,6 +257,11 @@ status_t AudioTrack::set( return BAD_VALUE; } + if (!audio_is_output_channel(channelMask)) { + ALOGE("Invalid channel mask %#x", channelMask); + return BAD_VALUE; + } + // AudioFlinger does not currently support 8-bit data in shared memory if (format == AUDIO_FORMAT_PCM_8_BIT && sharedBuffer != 0) { ALOGE("8-bit data in shared memory is not supported"); @@ -282,10 +284,6 @@ status_t AudioTrack::set( flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER); } - if (!audio_is_output_channel(channelMask)) { - ALOGE("Invalid channel mask %#x", channelMask); - return BAD_VALUE; - } mChannelMask = channelMask; uint32_t channelCount = popcount(channelMask); mChannelCount = channelCount; -- cgit v1.1 From 377fce69297a0e5b7c3b266a7602b17146785635 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 6 Nov 2013 10:50:17 -0800 Subject: Only initialize sniffers once, don't hold mutex while sniffing b/11482896 Change-Id: Ie036554b4c9e7e8863cb07901d414ea457f1b2f1 --- media/libstagefright/DataSource.cpp | 43 +++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 16 deletions(-) (limited to 'media') diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index fc6fd9c..97987e2 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -107,6 +107,7 @@ status_t DataSource::getSize(off64_t *size) { Mutex DataSource::gSnifferMutex; List DataSource::gSniffers; +bool DataSource::gSniffersRegistered = false; bool DataSource::sniff( String8 *mimeType, float *confidence, sp *meta) { @@ -114,7 +115,13 @@ bool DataSource::sniff( *confidence = 0.0f; meta->clear(); - Mutex::Autolock autoLock(gSnifferMutex); + { + Mutex::Autolock autoLock(gSnifferMutex); + if (!gSniffersRegistered) { + return false; + } + } + for (List::iterator it = gSniffers.begin(); it != gSniffers.end(); ++it) { String8 newMimeType; @@ -133,9 +140,7 @@ bool DataSource::sniff( } // static -void DataSource::RegisterSniffer(SnifferFunc func) { - Mutex::Autolock autoLock(gSnifferMutex); - +void DataSource::RegisterSniffer_l(SnifferFunc func) { for (List::iterator it = gSniffers.begin(); it != gSniffers.end(); ++it) { if (*it == func) { @@ -148,23 +153,29 @@ void DataSource::RegisterSniffer(SnifferFunc func) { // static void DataSource::RegisterDefaultSniffers() { - RegisterSniffer(SniffMPEG4); - RegisterSniffer(SniffMatroska); - RegisterSniffer(SniffOgg); - RegisterSniffer(SniffWAV); - RegisterSniffer(SniffFLAC); - RegisterSniffer(SniffAMR); - RegisterSniffer(SniffMPEG2TS); - RegisterSniffer(SniffMP3); - RegisterSniffer(SniffAAC); - RegisterSniffer(SniffMPEG2PS); - RegisterSniffer(SniffWVM); + Mutex::Autolock autoLock(gSnifferMutex); + if (gSniffersRegistered) { + return; + } + + RegisterSniffer_l(SniffMPEG4); + RegisterSniffer_l(SniffMatroska); + RegisterSniffer_l(SniffOgg); + RegisterSniffer_l(SniffWAV); + RegisterSniffer_l(SniffFLAC); + RegisterSniffer_l(SniffAMR); + RegisterSniffer_l(SniffMPEG2TS); + RegisterSniffer_l(SniffMP3); + RegisterSniffer_l(SniffAAC); + RegisterSniffer_l(SniffMPEG2PS); + RegisterSniffer_l(SniffWVM); char value[PROPERTY_VALUE_MAX]; if (property_get("drm.service.enabled", value, NULL) && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { - RegisterSniffer(SniffDRM); + RegisterSniffer_l(SniffDRM); } + gSniffersRegistered = true; } // static -- cgit v1.1 From 4db37cedd4db8230f3ec6191d8d7ba2b0036886e Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Mon, 11 Nov 2013 21:14:30 -0800 Subject: Fixed StagefrightRecorder::setupVideoEncoder to use the clipped bitrate value mVideoBitRate; removed unused arguments after refactoring. Bug: 11074303 Change-Id: Ieb5dd7dc67e5bc16b6e580ba11b157e4365f3cd6 --- .../libmediaplayerservice/StagefrightRecorder.cpp | 28 ++++++++-------------- media/libmediaplayerservice/StagefrightRecorder.h | 12 ++-------- 2 files changed, 12 insertions(+), 28 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 095d5ca..0e828f7 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -972,7 +972,7 @@ status_t StagefrightRecorder::startRTPRecording() { return err; } - err = setupVideoEncoder(mediaSource, mVideoBitRate, &source); + err = setupVideoEncoder(mediaSource, &source); if (err != OK) { return err; } @@ -1016,7 +1016,7 @@ status_t StagefrightRecorder::startMPEG2TSRecording() { } sp encoder; - err = setupVideoEncoder(mediaSource, mVideoBitRate, &encoder); + err = setupVideoEncoder(mediaSource, &encoder); if (err != OK) { return err; @@ -1364,12 +1364,11 @@ status_t StagefrightRecorder::setupCameraSource( status_t StagefrightRecorder::setupVideoEncoder( sp cameraSource, - int32_t videoBitRate, sp *source) { source->clear(); sp enc_meta = new MetaData; - enc_meta->setInt32(kKeyBitRate, videoBitRate); + enc_meta->setInt32(kKeyBitRate, mVideoBitRate); enc_meta->setInt32(kKeyFrameRate, mFrameRate); switch (mVideoEncoder) { @@ -1476,16 +1475,11 @@ status_t StagefrightRecorder::setupAudioEncoder(const sp& writer) { return OK; } -status_t StagefrightRecorder::setupMPEG4Recording( - int outputFd, - int32_t videoWidth, int32_t videoHeight, - int32_t videoBitRate, - int32_t *totalBitRate, - sp *mediaWriter) { - mediaWriter->clear(); +status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) { + mWriter.clear(); *totalBitRate = 0; status_t err = OK; - sp writer = new MPEG4Writer(outputFd); + sp writer = new MPEG4Writer(mOutputFd); if (mVideoSource < VIDEO_SOURCE_LIST_END) { @@ -1496,13 +1490,13 @@ status_t StagefrightRecorder::setupMPEG4Recording( } sp encoder; - err = setupVideoEncoder(mediaSource, videoBitRate, &encoder); + err = setupVideoEncoder(mediaSource, &encoder); if (err != OK) { return err; } writer->addSource(encoder); - *totalBitRate += videoBitRate; + *totalBitRate += mVideoBitRate; } // Audio source is added at the end if it exists. @@ -1536,7 +1530,7 @@ status_t StagefrightRecorder::setupMPEG4Recording( } writer->setListener(mListener); - *mediaWriter = writer; + mWriter = writer; return OK; } @@ -1559,9 +1553,7 @@ void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalB status_t StagefrightRecorder::startMPEG4Recording() { int32_t totalBitRate; - status_t err = setupMPEG4Recording( - mOutputFd, mVideoWidth, mVideoHeight, - mVideoBitRate, &totalBitRate, &mWriter); + status_t err = setupMPEG4Recording(&totalBitRate); if (err != OK) { return err; } diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index c864207..ce85957 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -124,12 +124,7 @@ private: // frame buffers will be queued and dequeued sp mSurfaceMediaSource; - status_t setupMPEG4Recording( - int outputFd, - int32_t videoWidth, int32_t videoHeight, - int32_t videoBitRate, - int32_t *totalBitRate, - sp *mediaWriter); + status_t setupMPEG4Recording(int32_t *totalBitRate); void setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate, sp *meta); status_t startMPEG4Recording(); @@ -150,10 +145,7 @@ private: status_t setupSurfaceMediaSource(); status_t setupAudioEncoder(const sp& writer); - status_t setupVideoEncoder( - sp cameraSource, - int32_t videoBitRate, - sp *source); + status_t setupVideoEncoder(sp cameraSource, sp *source); // Encoding parameter handling utilities status_t setParameter(const String8 &key, const String8 &value); -- cgit v1.1 From 16117ab436e1de4ca494cad58662cdc2ecf6797a Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Mon, 18 Nov 2013 15:55:21 -0800 Subject: The member mRefreshState was removed in commit and the printout causes build failure when verbose logging is enabled. patch contributed by "Bertil Akesson" Change-Id: I1520e24be67d35cd42571ec6211c909a6be76604 related-to-bug: 11056200 --- media/libstagefright/httplive/LiveSession.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index bd12ddc..233db44 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -632,9 +632,6 @@ sp LiveSession::fetchPlaylist( // playlist unchanged *unchanged = true; - ALOGV("Playlist unchanged, refresh state is now %d", - (int)mRefreshState); - return NULL; } -- cgit v1.1 From 4bdda35319d5f46efea2089b865c8a64816389cd Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 18 Nov 2013 16:35:17 -0800 Subject: Only send a format change if the buffer has data b/11696552 Change-Id: I31aba6e01a7b4d288f4d85d9e2ddec0aac1c2d1f --- media/libstagefright/ACodec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 37cad63..eb274a8 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -3413,7 +3413,7 @@ bool ACodec::BaseState::onOMXFillBufferDone( sp reply = new AMessage(kWhatOutputBufferDrained, mCodec->id()); - if (!mCodec->mSentFormat) { + if (!mCodec->mSentFormat && rangeLength > 0) { mCodec->sendFormatChange(reply); } -- cgit v1.1 From a1d401d9f4a6ba477f0e07204e0b9481befcc928 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 20 Nov 2013 14:37:13 -0800 Subject: Check all server-provided sp If the sp from server is non-0, make sure it also has a non-NULL pointer(). If it is NULL, treat it as if the sp<> was 0. Change-Id: I6d0bd786587eb73fac38af787c11eba541880685 --- media/libmedia/IAudioRecord.cpp | 3 +++ media/libmedia/IAudioTrack.cpp | 6 ++++++ media/libmedia/IEffect.cpp | 3 +++ 3 files changed, 12 insertions(+) (limited to 'media') diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp index 4a7de65..9866d70 100644 --- a/media/libmedia/IAudioRecord.cpp +++ b/media/libmedia/IAudioRecord.cpp @@ -50,6 +50,9 @@ public: status_t status = remote()->transact(GET_CBLK, data, &reply); if (status == NO_ERROR) { cblk = interface_cast(reply.readStrongBinder()); + if (cblk != 0 && cblk->pointer() == NULL) { + cblk.clear(); + } } return cblk; } diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp index 3cd9cfd..ffc21fc 100644 --- a/media/libmedia/IAudioTrack.cpp +++ b/media/libmedia/IAudioTrack.cpp @@ -60,6 +60,9 @@ public: status_t status = remote()->transact(GET_CBLK, data, &reply); if (status == NO_ERROR) { cblk = interface_cast(reply.readStrongBinder()); + if (cblk != 0 && cblk->pointer() == NULL) { + cblk.clear(); + } } return cblk; } @@ -122,6 +125,9 @@ public: status = reply.readInt32(); if (status == NO_ERROR) { *buffer = interface_cast(reply.readStrongBinder()); + if (*buffer != 0 && (*buffer)->pointer() == NULL) { + (*buffer).clear(); + } } } return status; diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp index a303a8f..b94012a 100644 --- a/media/libmedia/IEffect.cpp +++ b/media/libmedia/IEffect.cpp @@ -117,6 +117,9 @@ public: status_t status = remote()->transact(GET_CBLK, data, &reply); if (status == NO_ERROR) { cblk = interface_cast(reply.readStrongBinder()); + if (cblk != 0 && cblk->pointer() == NULL) { + cblk.clear(); + } } return cblk; } -- cgit v1.1 From 6f59db12a64f4496866952a251122ccb77a36c6b Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 26 Jul 2013 17:16:50 -0700 Subject: update offloaded audio track sampling rate AudioPlayer must read the sampling rate from offloaded audio sinks whenever a new time position is computed as the decoder can update the sampling rate on the fly. Change-Id: I997e5248cfd4017aeceb4e11689324ded2a5bc88 --- media/libmedia/AudioTrack.cpp | 13 +++++++++++++ media/libmediaplayerservice/MediaPlayerService.cpp | 14 ++++++++++++++ media/libmediaplayerservice/MediaPlayerService.h | 2 ++ media/libstagefright/AudioPlayer.cpp | 15 +++++++++++++-- 4 files changed, 42 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 8319dcd..4b93714 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -600,6 +600,19 @@ uint32_t AudioTrack::getSampleRate() const } AutoMutex lock(mLock); + + // sample rate can be updated during playback by the offloaded decoder so we need to + // query the HAL and update if needed. +// FIXME use Proxy return channel to update the rate from server and avoid polling here + if (isOffloaded()) { + if (mOutput != 0) { + uint32_t sampleRate = 0; + status_t status = AudioSystem::getSamplingRate(mOutput, mStreamType, &sampleRate); + if (status == NO_ERROR) { + mSampleRate = sampleRate; + } + } + } return mSampleRate; } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index cd052e6..9ac9105 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1813,6 +1813,12 @@ int MediaPlayerService::AudioOutput::getSessionId() const return mSessionId; } +uint32_t MediaPlayerService::AudioOutput::getSampleRate() const +{ + if (mTrack == 0) return 0; + return mTrack->getSampleRate(); +} + #undef LOG_TAG #define LOG_TAG "AudioCache" MediaPlayerService::AudioCache::AudioCache(const sp& heap) : @@ -2015,6 +2021,14 @@ int MediaPlayerService::AudioCache::getSessionId() const return 0; } +uint32_t MediaPlayerService::AudioCache::getSampleRate() const +{ + if (mMsecsPerFrame == 0) { + return 0; + } + return (uint32_t)(1.e3 / mMsecsPerFrame); +} + void MediaPlayerService::addBatteryData(uint32_t params) { Mutex::Autolock lock(mLock); diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index a486cb5..9c084e1 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -86,6 +86,7 @@ class MediaPlayerService : public BnMediaPlayerService virtual status_t getPosition(uint32_t *position) const; virtual status_t getFramesWritten(uint32_t *frameswritten) const; virtual int getSessionId() const; + virtual uint32_t getSampleRate() const; virtual status_t open( uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask, @@ -195,6 +196,7 @@ class MediaPlayerService : public BnMediaPlayerService virtual status_t getPosition(uint32_t *position) const; virtual status_t getFramesWritten(uint32_t *frameswritten) const; virtual int getSessionId() const; + virtual uint32_t getSampleRate() const; virtual status_t open( uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask, diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index a8a8786..05ee34e 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -721,16 +721,27 @@ int64_t AudioPlayer::getRealTimeUsLocked() const { return result + diffUs; } -int64_t AudioPlayer::getOutputPlayPositionUs_l() const +int64_t AudioPlayer::getOutputPlayPositionUs_l() { uint32_t playedSamples = 0; + uint32_t sampleRate; if (mAudioSink != NULL) { mAudioSink->getPosition(&playedSamples); + sampleRate = mAudioSink->getSampleRate(); } else { mAudioTrack->getPosition(&playedSamples); + sampleRate = mAudioTrack->getSampleRate(); + } + if (sampleRate != 0) { + mSampleRate = sampleRate; } - const int64_t playedUs = (static_cast(playedSamples) * 1000000 ) / mSampleRate; + int64_t playedUs; + if (mSampleRate != 0) { + playedUs = (static_cast(playedSamples) * 1000000 ) / mSampleRate; + } else { + playedUs = 0; + } // HAL position is relative to the first buffer we sent at mStartPosUs const int64_t renderedDuration = mStartPosUs + playedUs; -- cgit v1.1 From 9bb976e1c78048081cf9df4d8a1db67311413e5b Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 22 Nov 2013 12:58:43 -0800 Subject: Avoid the call to CameraSourceTimeLapse::trySettingVideoSize if initialization failed in the parent class ctor CameraSource::CameraSource. Bug: 11636771 Change-Id: I5e6bffc1ebeeb1c2b84d6ed2049b2b3676ac046a --- media/libstagefright/CameraSourceTimeLapse.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp index 20214e8..07f0271 100644 --- a/media/libstagefright/CameraSourceTimeLapse.cpp +++ b/media/libstagefright/CameraSourceTimeLapse.cpp @@ -81,7 +81,8 @@ CameraSourceTimeLapse::CameraSourceTimeLapse( mVideoWidth = videoSize.width; mVideoHeight = videoSize.height; - if (!trySettingVideoSize(videoSize.width, videoSize.height)) { + if (OK == mInitCheck && !trySettingVideoSize(videoSize.width, videoSize.height)) { + releaseCamera(); mInitCheck = NO_INIT; } -- cgit v1.1 From b31788687736666e58b852e744a93f772d3f7148 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 27 Nov 2013 14:29:13 -0800 Subject: AudioTrack: fix position callback after restore When restoring an AudioTrack, the next position callback point should not be modified and set ahead of current buffer head. Otherwise, as frames are dropped, the new position is never reached and an application relying on position callbacks to reload the buffer would be stalled. Bug: 11868603. Change-Id: I93b2a311642a0c89944b78bcc0482d4ceed98ae4 --- media/libmedia/AudioTrack.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 4b93714..0f4d490 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1685,7 +1685,6 @@ status_t AudioTrack::restoreTrack_l(const char *from) // take the frames that will be lost by track recreation into account in saved position size_t position = mProxy->getPosition() + mProxy->getFramesFilled(); - mNewPosition = position + mUpdatePeriod; size_t bufferPosition = mStaticProxy != NULL ? mStaticProxy->getBufferPosition() : 0; result = createTrack_l(mStreamType, mSampleRate, -- cgit v1.1 From 481fb67a595f23c5b7f5be84b06db9b84a41a42f Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 30 Sep 2013 14:39:28 -0700 Subject: Add RecordThread media.log and deferred deallocation This change allows a media.log buffer for RecordThread. Unlike playback threads which stick around forever, the RecordThread comes and goes for every capture session. This means that the media.log buffer for a RecordThread would disappear too, and so was useless. Now when a thread exits, it's associated media.log buffer is just marked for deferred deallocation. It is only actually freed when the memory is needed. Other changes: - Fix bug in unregistering comparison, it was comparing the wrong pointers - Increased size of log area so we can log for RecordThread also Change-Id: If45d4c03a793b86390a0112ec3acc5d41b2e3635 --- media/libnbaio/NBLog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp index 045bf64..ba8d0b4 100644 --- a/media/libnbaio/NBLog.cpp +++ b/media/libnbaio/NBLog.cpp @@ -441,7 +441,7 @@ void NBLog::Reader::dump(int fd, size_t indent) bool NBLog::Reader::isIMemory(const sp& iMemory) const { - return iMemory.get() == mIMemory.get(); + return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer(); } } // namespace android -- cgit v1.1 From aef04853de0ce27222cf6250b2ba4fa9fc6a72a8 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 6 Dec 2013 10:11:32 -0800 Subject: stagefright: fix TimedEventQueue wakelock If an event is taking a wakelock, the wakelock must be released after the event is fired. If the wakelock is released before and the event execution implies some sleeps or I/O the system can go idle as no wakelock is held anymore. Bug: 11976087. Change-Id: Ie7df8ed4834952ff818ff27d6be415c0b1794a9f --- media/libstagefright/TimedEventQueue.cpp | 11 +++++------ media/libstagefright/include/TimedEventQueue.h | 12 ++++++++++-- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'media') diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp index 1a9a26b..da23fea 100644 --- a/media/libstagefright/TimedEventQueue.cpp +++ b/media/libstagefright/TimedEventQueue.cpp @@ -127,7 +127,6 @@ TimedEventQueue::event_id TimedEventQueue::postTimedEvent( QueueItem item; item.event = event; item.realtime_us = realtime_us; - item.has_wakelock = false; if (it == mQueue.begin()) { mQueueHeadChangedCondition.signal(); @@ -135,7 +134,7 @@ TimedEventQueue::event_id TimedEventQueue::postTimedEvent( if (realtime_us > ALooper::GetNowUs() + kWakelockMinDelay) { acquireWakeLock_l(); - item.has_wakelock = true; + event->setWakeLock(); } mQueue.insert(it, item); @@ -191,7 +190,7 @@ void TimedEventQueue::cancelEvents( ALOGV("cancelling event %d", (*it).event->eventID()); (*it).event->setEventID(0); - if ((*it).has_wakelock) { + if ((*it).event->hasWakeLock()) { releaseWakeLock_l(); } it = mQueue.erase(it); @@ -289,6 +288,9 @@ void TimedEventQueue::threadEntry() { if (event != NULL) { // Fire event with the lock NOT held. event->fire(this, now_us); + if (event->hasWakeLock()) { + releaseWakeLock_l(); + } } } } @@ -300,9 +302,6 @@ sp TimedEventQueue::removeEventFromQueue_l( if ((*it).event->eventID() == id) { sp event = (*it).event; event->setEventID(0); - if ((*it).has_wakelock) { - releaseWakeLock_l(); - } mQueue.erase(it); return event; } diff --git a/media/libstagefright/include/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h index 38a08b1..4e8912d 100644 --- a/media/libstagefright/include/TimedEventQueue.h +++ b/media/libstagefright/include/TimedEventQueue.h @@ -33,7 +33,7 @@ struct TimedEventQueue { struct Event : public RefBase { Event() - : mEventID(0) { + : mEventID(0), mHasWakeLock(false) { } virtual ~Event() {} @@ -42,6 +42,14 @@ struct TimedEventQueue { return mEventID; } + void setWakeLock() { + mHasWakeLock = true; + } + + bool hasWakeLock() { + return mHasWakeLock; + } + protected: virtual void fire(TimedEventQueue *queue, int64_t now_us) = 0; @@ -49,6 +57,7 @@ struct TimedEventQueue { friend class TimedEventQueue; event_id mEventID; + bool mHasWakeLock; void setEventID(event_id id) { mEventID = id; @@ -118,7 +127,6 @@ private: struct QueueItem { sp event; int64_t realtime_us; - bool has_wakelock; }; struct StopEvent : public TimedEventQueue::Event { -- cgit v1.1 From 2acc8b3833c7bdeca13f1f1a68d212d0cd5d750f Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 10 Dec 2013 17:20:46 -0800 Subject: Revert "stagefright: fix TimedEventQueue wakelock" This reverts commit aef04853de0ce27222cf6250b2ba4fa9fc6a72a8. --- media/libstagefright/TimedEventQueue.cpp | 11 ++++++----- media/libstagefright/include/TimedEventQueue.h | 12 ++---------- 2 files changed, 8 insertions(+), 15 deletions(-) (limited to 'media') diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp index da23fea..1a9a26b 100644 --- a/media/libstagefright/TimedEventQueue.cpp +++ b/media/libstagefright/TimedEventQueue.cpp @@ -127,6 +127,7 @@ TimedEventQueue::event_id TimedEventQueue::postTimedEvent( QueueItem item; item.event = event; item.realtime_us = realtime_us; + item.has_wakelock = false; if (it == mQueue.begin()) { mQueueHeadChangedCondition.signal(); @@ -134,7 +135,7 @@ TimedEventQueue::event_id TimedEventQueue::postTimedEvent( if (realtime_us > ALooper::GetNowUs() + kWakelockMinDelay) { acquireWakeLock_l(); - event->setWakeLock(); + item.has_wakelock = true; } mQueue.insert(it, item); @@ -190,7 +191,7 @@ void TimedEventQueue::cancelEvents( ALOGV("cancelling event %d", (*it).event->eventID()); (*it).event->setEventID(0); - if ((*it).event->hasWakeLock()) { + if ((*it).has_wakelock) { releaseWakeLock_l(); } it = mQueue.erase(it); @@ -288,9 +289,6 @@ void TimedEventQueue::threadEntry() { if (event != NULL) { // Fire event with the lock NOT held. event->fire(this, now_us); - if (event->hasWakeLock()) { - releaseWakeLock_l(); - } } } } @@ -302,6 +300,9 @@ sp TimedEventQueue::removeEventFromQueue_l( if ((*it).event->eventID() == id) { sp event = (*it).event; event->setEventID(0); + if ((*it).has_wakelock) { + releaseWakeLock_l(); + } mQueue.erase(it); return event; } diff --git a/media/libstagefright/include/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h index 4e8912d..38a08b1 100644 --- a/media/libstagefright/include/TimedEventQueue.h +++ b/media/libstagefright/include/TimedEventQueue.h @@ -33,7 +33,7 @@ struct TimedEventQueue { struct Event : public RefBase { Event() - : mEventID(0), mHasWakeLock(false) { + : mEventID(0) { } virtual ~Event() {} @@ -42,14 +42,6 @@ struct TimedEventQueue { return mEventID; } - void setWakeLock() { - mHasWakeLock = true; - } - - bool hasWakeLock() { - return mHasWakeLock; - } - protected: virtual void fire(TimedEventQueue *queue, int64_t now_us) = 0; @@ -57,7 +49,6 @@ struct TimedEventQueue { friend class TimedEventQueue; event_id mEventID; - bool mHasWakeLock; void setEventID(event_id id) { mEventID = id; @@ -127,6 +118,7 @@ private: struct QueueItem { sp event; int64_t realtime_us; + bool has_wakelock; }; struct StopEvent : public TimedEventQueue::Event { -- cgit v1.1 From 1c2a66fea852cb8a5228fabef17f85cac1bef5ec Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Fri, 6 Dec 2013 11:31:57 -0800 Subject: libstagefright: Delay release of wakelock in TimedEventQueue Delay release of wakelock in the TimedEventQueue to after an event has been processed. This ensures AP shutdown does not happen while an event is ready but hasn't been processed yet. Bug: 11976087. Change-Id: I71a5f3ac4a57e1d05dd5d9ab5c6f91ed7bb64c87 --- media/libstagefright/TimedEventQueue.cpp | 13 ++++++++----- media/libstagefright/include/TimedEventQueue.h | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp index 1a9a26b..dedd186 100644 --- a/media/libstagefright/TimedEventQueue.cpp +++ b/media/libstagefright/TimedEventQueue.cpp @@ -217,6 +217,7 @@ void TimedEventQueue::threadEntry() { for (;;) { int64_t now_us = 0; sp event; + bool wakeLocked = false; { Mutex::Autolock autoLock(mLock); @@ -283,26 +284,28 @@ void TimedEventQueue::threadEntry() { // removeEventFromQueue_l will return NULL. // Otherwise, the QueueItem will be removed // from the queue and the referenced event returned. - event = removeEventFromQueue_l(eventID); + event = removeEventFromQueue_l(eventID, &wakeLocked); } if (event != NULL) { // Fire event with the lock NOT held. event->fire(this, now_us); + if (wakeLocked) { + Mutex::Autolock autoLock(mLock); + releaseWakeLock_l(); + } } } } sp TimedEventQueue::removeEventFromQueue_l( - event_id id) { + event_id id, bool *wakeLocked) { for (List::iterator it = mQueue.begin(); it != mQueue.end(); ++it) { if ((*it).event->eventID() == id) { sp event = (*it).event; event->setEventID(0); - if ((*it).has_wakelock) { - releaseWakeLock_l(); - } + *wakeLocked = (*it).has_wakelock; mQueue.erase(it); return event; } diff --git a/media/libstagefright/include/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h index 38a08b1..3e84256 100644 --- a/media/libstagefright/include/TimedEventQueue.h +++ b/media/libstagefright/include/TimedEventQueue.h @@ -145,7 +145,7 @@ private: static void *ThreadWrapper(void *me); void threadEntry(); - sp removeEventFromQueue_l(event_id id); + sp removeEventFromQueue_l(event_id id, bool *wakeLocked); void acquireWakeLock_l(); void releaseWakeLock_l(bool force = false); -- cgit v1.1 From 544ad2be674423238c47650d2c8588ba7dfc9ed2 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 13 Nov 2013 14:18:21 -0800 Subject: Better character set encoding detection Id3 tags are supposed to be ISO-8859-1 or unicode, but often aren't. To better detect the real encoding we now use ICU to detect possible encodings for a given byte sequence, then apply additional heuristics to determine the most likely one. b/5564857 Change-Id: I53bc83b006433da5c2f2ccfcd770ddb3a26b64d0 --- media/libmedia/Android.mk | 5 +- media/libmedia/CharacterEncodingDetector.cpp | 364 ++++ media/libmedia/CharacterEncodingDetector.h | 61 + media/libmedia/CharacterEncodingDetectorTables.h | 2092 ++++++++++++++++++++++ media/libmedia/MediaScannerClient.cpp | 202 +-- media/libmedia/autodetect.cpp | 885 --------- media/libmedia/autodetect.h | 37 - media/libstagefright/id3/ID3.cpp | 79 +- 8 files changed, 2570 insertions(+), 1155 deletions(-) create mode 100644 media/libmedia/CharacterEncodingDetector.cpp create mode 100644 media/libmedia/CharacterEncodingDetector.h create mode 100644 media/libmedia/CharacterEncodingDetectorTables.h delete mode 100644 media/libmedia/autodetect.cpp delete mode 100644 media/libmedia/autodetect.h (limited to 'media') diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index 56e7787..8aa54dc 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -44,7 +44,7 @@ LOCAL_SRC_FILES:= \ IAudioPolicyService.cpp \ MediaScanner.cpp \ MediaScannerClient.cpp \ - autodetect.cpp \ + CharacterEncodingDetector.cpp \ IMediaDeathNotifier.cpp \ MediaProfiles.cpp \ IEffect.cpp \ @@ -65,7 +65,7 @@ LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiat # Consider a separate a library for SingleStateQueueInstantiations. LOCAL_SHARED_LIBRARIES := \ - libui liblog libcutils libutils libbinder libsonivox libicuuc libexpat \ + libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \ libcamera_client libstagefright_foundation \ libgui libdl libaudioutils @@ -77,6 +77,7 @@ LOCAL_C_INCLUDES := \ $(call include-path-for, graphics corecg) \ $(TOP)/frameworks/native/include/media/openmax \ external/icu4c/common \ + external/icu4c/i18n \ $(call include-path-for, audio-effects) \ $(call include-path-for, audio-utils) diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp new file mode 100644 index 0000000..eb091ac --- /dev/null +++ b/media/libmedia/CharacterEncodingDetector.cpp @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "CharacterEncodingDector" +#include + +#include "CharacterEncodingDetector.h" +#include "CharacterEncodingDetectorTables.h" + +#include "utils/Vector.h" +#include "StringArray.h" + +#include "unicode/ucnv.h" +#include "unicode/ucsdet.h" +#include "unicode/ustring.h" + +namespace android { + +CharacterEncodingDetector::CharacterEncodingDetector() { + + UErrorCode status = U_ZERO_ERROR; + mUtf8Conv = ucnv_open("UTF-8", &status); + if (U_FAILURE(status)) { + ALOGE("could not create UConverter for UTF-8"); + mUtf8Conv = NULL; + } +} + +CharacterEncodingDetector::~CharacterEncodingDetector() { + ucnv_close(mUtf8Conv); +} + +void CharacterEncodingDetector::addTag(const char *name, const char *value) { + mNames.push_back(name); + mValues.push_back(value); +} + +size_t CharacterEncodingDetector::size() { + return mNames.size(); +} + +status_t CharacterEncodingDetector::getTag(int index, const char **name, const char**value) { + if (index >= mNames.size()) { + return BAD_VALUE; + } + + *name = mNames.getEntry(index); + *value = mValues.getEntry(index); + return OK; +} + +static bool isPrintableAscii(const char *value, size_t len) { + for (size_t i = 0; i < len; i++) { + if ((value[i] & 0x80) || value[i] < 0x20 || value[i] == 0x7f) { + return false; + } + } + return true; +} + +void CharacterEncodingDetector::detectAndConvert() { + + int size = mNames.size(); + ALOGV("%d tags before conversion", size); + for (int i = 0; i < size; i++) { + ALOGV("%s: %s", mNames.getEntry(i), mValues.getEntry(i)); + } + + if (size && mUtf8Conv) { + + UErrorCode status = U_ZERO_ERROR; + UCharsetDetector *csd = ucsdet_open(&status); + const UCharsetMatch *ucm; + + // try combined detection of artist/album/title etc. + char buf[1024]; + buf[0] = 0; + int idx; + for (int i = 0; i < size; i++) { + const char *name = mNames.getEntry(i); + const char *value = mValues.getEntry(i); + if (!isPrintableAscii(value, strlen(value)) && ( + !strcmp(name, "artist") || + !strcmp(name, "albumartist") || + !strcmp(name, "composer") || + !strcmp(name, "genre") || + !strcmp(name, "album") || + !strcmp(name, "title"))) { + strlcat(buf, value, sizeof(buf)); + // separate tags by space so ICU's ngram detector can do its job + strlcat(buf, " ", sizeof(buf)); + } + } + ucsdet_setText(csd, buf, strlen(buf), &status); + + int32_t matches; + const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status); + const char *combinedenc = "???"; + + const UCharsetMatch* bestCombinedMatch = getPreferred(buf, strlen(buf), ucma, matches); + + if (bestCombinedMatch != NULL) { + combinedenc = ucsdet_getName(bestCombinedMatch, &status); + } + + for (int i = 0; i < size; i++) { + const char *name = mNames.getEntry(i); + uint8_t* src = (uint8_t *)mValues.getEntry(i); + int len = strlen((char *)src); + uint8_t* dest = src; + + ALOGV("@@@ checking %s", name); + const char *s = mValues.getEntry(i); + int32_t inputLength = strlen(s); + const char *enc; + + if (!strcmp(name, "artist") || + !strcmp(name, "albumartist") || + !strcmp(name, "composer") || + !strcmp(name, "genre") || + !strcmp(name, "album") || + !strcmp(name, "title")) { + // use encoding determined from the combination of artist/album/title etc. + enc = combinedenc; + } else { + ucsdet_setText(csd, s, inputLength, &status); + ucm = ucsdet_detect(csd, &status); + if (!ucm) { + mValues.setEntry(i, "???"); + continue; + } + enc = ucsdet_getName(ucm, &status); + ALOGV("@@@@ recognized charset: %s for %s confidence %d", + enc, mNames.getEntry(i), ucsdet_getConfidence(ucm, &status)); + } + + if (strcmp(enc,"UTF-8") != 0) { + // only convert if the source encoding isn't already UTF-8 + ALOGV("@@@ using converter %s for %s", enc, mNames.getEntry(i)); + UConverter *conv = ucnv_open(enc, &status); + if (U_FAILURE(status)) { + ALOGE("could not create UConverter for %s", enc); + continue; + } + + // convert from native encoding to UTF-8 + const char* source = mValues.getEntry(i); + int targetLength = len * 3 + 1; + char* buffer = new char[targetLength]; + // don't normally check for NULL, but in this case targetLength may be large + if (!buffer) + break; + char* target = buffer; + + ucnv_convertEx(mUtf8Conv, conv, &target, target + targetLength, + &source, source + strlen(source), + NULL, NULL, NULL, NULL, TRUE, TRUE, &status); + + if (U_FAILURE(status)) { + ALOGE("ucnv_convertEx failed: %d", status); + mValues.setEntry(i, "???"); + } else { + // zero terminate + *target = 0; + mValues.setEntry(i, buffer); + } + + delete[] buffer; + + ucnv_close(conv); + } + } + + for (int i = size - 1; i >= 0; --i) { + if (strlen(mValues.getEntry(i)) == 0) { + ALOGV("erasing %s because entry is empty", mNames.getEntry(i)); + mNames.erase(i); + mValues.erase(i); + } + } + + ucsdet_close(csd); + } +} + +/* + * When ICU detects multiple encoding matches, apply additional heuristics to determine + * which one is the best match, since ICU can't always be trusted to make the right choice. + * + * What this method does is: + * - decode the input using each of the matches found + * - recalculate the starting confidence level for multibyte encodings using a different + * algorithm and larger frequent character lists than ICU + * - devalue encoding where the conversion contains unlikely characters (symbols, reserved, etc) + * - pick the highest match + */ +const UCharsetMatch *CharacterEncodingDetector::getPreferred( + const char *input, size_t len, const UCharsetMatch** ucma, size_t nummatches) { + + Vector matches; + UErrorCode status = U_ZERO_ERROR; + + ALOGV("%d matches", nummatches); + for (size_t i = 0; i < nummatches; i++) { + const char *encname = ucsdet_getName(ucma[i], &status); + int confidence = ucsdet_getConfidence(ucma[i], &status); + ALOGV("%d: %s %d", i, encname, confidence); + matches.push_back(ucma[i]); + } + + size_t num = matches.size(); + if (num == 0) { + return NULL; + } + if (num == 1) { + return matches[0]; + } + + ALOGV("considering %d matches", num); + + // keep track of how many "special" characters result when converting the input using each + // encoding + Vector newconfidence; + for (size_t i = 0; i < num; i++) { + const uint16_t *freqdata = NULL; + float freqcoverage = 0; + status = U_ZERO_ERROR; + const char *encname = ucsdet_getName(matches[i], &status); + int confidence = ucsdet_getConfidence(matches[i], &status); + if (!strcmp("GB18030", encname)) { + freqdata = frequent_zhCN; + freqcoverage = frequent_zhCN_coverage; + } else if (!strcmp("Big5", encname)) { + freqdata = frequent_zhTW; + freqcoverage = frequent_zhTW_coverage; + } else if (!strcmp("EUC-KR", encname)) { + freqdata = frequent_ko; + freqcoverage = frequent_ko_coverage; + } else if (!strcmp("EUC-JP", encname)) { + freqdata = frequent_ja; + freqcoverage = frequent_ja_coverage; + } else if (!strcmp("Shift_JIS", encname)) { + freqdata = frequent_ja; + freqcoverage = frequent_ja_coverage; + } + + ALOGV("%d: %s %d", i, encname, confidence); + UConverter *conv = ucnv_open(encname, &status); + const char *source = input; + const char *sourceLimit = input + len; + status = U_ZERO_ERROR; + int demerit = 0; + int frequentchars = 0; + int totalchars = 0; + while (true) { + // demerit the current encoding for each "special" character found after conversion. + // The amount of demerit is somewhat arbitrarily chosen. + int inchar; + if (source != sourceLimit) { + inchar = (source[0] << 8) + source[1]; + } + UChar32 c = ucnv_getNextUChar(conv, &source, sourceLimit, &status); + if (!U_SUCCESS(status)) { + break; + } + if (c < 0x20 || (c >= 0x7f && c <= 0x009f)) { + ALOGV("control character %x", c); + demerit += 100; + } else if ((c >= 0xa0 && c <= 0xbe) // symbols, superscripts + || (c == 0xd7) || (c == 0xf7) // multiplication and division signs + || (c >= 0x2000 && c <= 0x209f)) { // punctuation, superscripts + ALOGV("unlikely character %x", c); + demerit += 10; + } else if (c >= 0xe000 && c <= 0xf8ff) { + ALOGV("private use character %x", c); + demerit += 30; + } else if (c >= 0x2190 && c <= 0x2bff) { + // this range comprises various symbol ranges that are unlikely to appear in + // music file metadata. + ALOGV("symbol %x", c); + demerit += 10; + } else if (c == 0xfffd) { + ALOGV("replacement character"); + demerit += 50; + } else if (c >= 0xfff0 && c <= 0xfffc) { + ALOGV("unicode special %x", c); + demerit += 50; + } else if (freqdata != NULL) { + totalchars++; + if (isFrequent(freqdata, c)) { + frequentchars++; + } + } + } + if (freqdata != NULL && totalchars != 0) { + int myconfidence = 10 + float((100 * frequentchars) / totalchars) / freqcoverage; + ALOGV("ICU confidence: %d, my confidence: %d (%d %d)", confidence, myconfidence, + totalchars, frequentchars); + if (myconfidence > 100) myconfidence = 100; + if (myconfidence < 0) myconfidence = 0; + confidence = myconfidence; + } + ALOGV("%d-%d=%d", confidence, demerit, confidence - demerit); + newconfidence.push_back(confidence - demerit); + ucnv_close(conv); + if (i == 0 && (confidence - demerit) == 100) { + // no need to check any further, we'll end up using this match anyway + break; + } + } + + // find match with highest confidence after adjusting for unlikely characters + int highest = newconfidence[0]; + size_t highestidx = 0; + num = newconfidence.size(); + for (size_t i = 1; i < num; i++) { + if (newconfidence[i] > highest) { + highest = newconfidence[i]; + highestidx = i; + } + } + status = U_ZERO_ERROR; + ALOGV("selecting '%s' w/ %d confidence", ucsdet_getName(matches[highestidx], &status), highest); + return matches[highestidx]; +} + + +bool CharacterEncodingDetector::isFrequent(const uint16_t *values, uint32_t c) { + + int start = 0; + int end = 511; // All the tables have 512 entries + int mid = (start+end)/2; + + while(start <= end) { + if(c == values[mid]) { + return true; + } else if (c > values[mid]) { + start = mid + 1; + } else { + end = mid - 1; + } + + mid = (start + end) / 2; + } + + return false; +} + + +} // namespace android diff --git a/media/libmedia/CharacterEncodingDetector.h b/media/libmedia/CharacterEncodingDetector.h new file mode 100644 index 0000000..3655a91 --- /dev/null +++ b/media/libmedia/CharacterEncodingDetector.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 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 _CHARACTER_ENCODING_DETECTOR_H +#define _CHARACTER_ENCODING_DETECTOR_H + +#include + +#include "StringArray.h" + +#include "unicode/ucnv.h" +#include "unicode/ucsdet.h" +#include "unicode/ustring.h" + +namespace android { + +class CharacterEncodingDetector { + + public: + CharacterEncodingDetector(); + ~CharacterEncodingDetector(); + + void addTag(const char *name, const char *value); + size_t size(); + + void detectAndConvert(); + status_t getTag(int index, const char **name, const char**value); + + private: + const UCharsetMatch *getPreferred( + const char *input, size_t len, const UCharsetMatch** ucma, size_t matches); + + bool isFrequent(const uint16_t *values, uint32_t c); + + // cached name and value strings, for native encoding support. + // TODO: replace these with byte blob arrays that don't require the data to be + // singlenullbyte-terminated + StringArray mNames; + StringArray mValues; + + UConverter* mUtf8Conv; +}; + + + +}; // namespace android + +#endif diff --git a/media/libmedia/CharacterEncodingDetectorTables.h b/media/libmedia/CharacterEncodingDetectorTables.h new file mode 100644 index 0000000..1fe1137 --- /dev/null +++ b/media/libmedia/CharacterEncodingDetectorTables.h @@ -0,0 +1,2092 @@ +/* + * Copyright (C) 2013 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. + */ + +// The 512 most frequently occuring characters for the zhCN language in a sample of the Internet. +// Ordered by codepoint, comment shows character and ranking by frequency +const uint16_t frequent_zhCN[] = { + 0x4E00, // 一, #2 + 0x4E07, // 万, #306 + 0x4E09, // 三, #138 + 0x4E0A, // 上, #16 + 0x4E0B, // 下, #25 + 0x4E0D, // 不, #7 + 0x4E0E, // 与, #133 + 0x4E13, // 专, #151 + 0x4E16, // 世, #346 + 0x4E1A, // 业, #39 + 0x4E1C, // 东, #197 + 0x4E24, // 两, #376 + 0x4E2A, // 个, #23 + 0x4E2D, // 中, #4 + 0x4E3A, // 为, #31 + 0x4E3B, // 主, #95 + 0x4E3E, // 举, #418 + 0x4E48, // 么, #93 + 0x4E4B, // 之, #131 + 0x4E50, // 乐, #130 + 0x4E5F, // 也, #145 + 0x4E66, // 书, #283 + 0x4E70, // 买, #483 + 0x4E86, // 了, #13 + 0x4E8B, // 事, #168 + 0x4E8C, // 二, #218 + 0x4E8E, // 于, #64 + 0x4E94, // 五, #430 + 0x4E9A, // 亚, #468 + 0x4E9B, // 些, #366 + 0x4EA4, // 交, #243 + 0x4EA7, // 产, #86 + 0x4EAB, // 享, #345 + 0x4EAC, // 京, #206 + 0x4EBA, // 人, #3 + 0x4EC0, // 什, #287 + 0x4ECB, // 介, #478 + 0x4ECE, // 从, #381 + 0x4ED6, // 他, #129 + 0x4EE3, // 代, #241 + 0x4EE5, // 以, #51 + 0x4EEC, // 们, #83 + 0x4EF6, // 件, #141 + 0x4EF7, // 价, #140 + 0x4EFB, // 任, #383 + 0x4F01, // 企, #439 + 0x4F18, // 优, #374 + 0x4F1A, // 会, #29 + 0x4F20, // 传, #222 + 0x4F46, // 但, #451 + 0x4F4D, // 位, #208 + 0x4F53, // 体, #98 + 0x4F55, // 何, #339 + 0x4F5C, // 作, #44 + 0x4F60, // 你, #76 + 0x4F7F, // 使, #272 + 0x4F9B, // 供, #375 + 0x4FDD, // 保, #180 + 0x4FE1, // 信, #84 + 0x4FEE, // 修, #437 + 0x503C, // 值, #450 + 0x505A, // 做, #368 + 0x5065, // 健, #484 + 0x50CF, // 像, #487 + 0x513F, // 儿, #326 + 0x5143, // 元, #202 + 0x5148, // 先, #485 + 0x5149, // 光, #254 + 0x514B, // 克, #503 + 0x514D, // 免, #349 + 0x5165, // 入, #156 + 0x5168, // 全, #47 + 0x516C, // 公, #35 + 0x5171, // 共, #448 + 0x5173, // 关, #49 + 0x5176, // 其, #195 + 0x5177, // 具, #329 + 0x5185, // 内, #109 + 0x518C, // 册, #225 + 0x519B, // 军, #466 + 0x51FA, // 出, #53 + 0x51FB, // 击, #359 + 0x5206, // 分, #22 + 0x5217, // 列, #410 + 0x521B, // 创, #399 + 0x5229, // 利, #296 + 0x522B, // 别, #372 + 0x5230, // 到, #33 + 0x5236, // 制, #192 + 0x524D, // 前, #117 + 0x529B, // 力, #173 + 0x529E, // 办, #436 + 0x529F, // 功, #455 + 0x52A0, // 加, #97 + 0x52A1, // 务, #100 + 0x52A8, // 动, #46 + 0x52A9, // 助, #365 + 0x5305, // 包, #331 + 0x5316, // 化, #155 + 0x5317, // 北, #194 + 0x533A, // 区, #105 + 0x533B, // 医, #234 + 0x5341, // 十, #294 + 0x534E, // 华, #205 + 0x5355, // 单, #259 + 0x5357, // 南, #182 + 0x535A, // 博, #153 + 0x5361, // 卡, #332 + 0x539F, // 原, #271 + 0x53BB, // 去, #282 + 0x53C2, // 参, #500 + 0x53CA, // 及, #255 + 0x53CB, // 友, #186 + 0x53CD, // 反, #422 + 0x53D1, // 发, #15 + 0x53D7, // 受, #507 + 0x53D8, // 变, #395 + 0x53E3, // 口, #293 + 0x53EA, // 只, #340 + 0x53EF, // 可, #45 + 0x53F0, // 台, #267 + 0x53F7, // 号, #121 + 0x53F8, // 司, #150 + 0x5404, // 各, #491 + 0x5408, // 合, #115 + 0x540C, // 同, #189 + 0x540D, // 名, #127 + 0x540E, // 后, #75 + 0x5411, // 向, #459 + 0x5427, // 吧, #353 + 0x544A, // 告, #318 + 0x5458, // 员, #232 + 0x5468, // 周, #347 + 0x548C, // 和, #43 + 0x54C1, // 品, #36 + 0x5546, // 商, #148 + 0x5668, // 器, #228 + 0x56DB, // 四, #352 + 0x56DE, // 回, #38 + 0x56E0, // 因, #355 + 0x56E2, // 团, #412 + 0x56ED, // 园, #470 + 0x56FD, // 国, #12 + 0x56FE, // 图, #32 + 0x5728, // 在, #10 + 0x5730, // 地, #30 + 0x573A, // 场, #177 + 0x575B, // 坛, #364 + 0x578B, // 型, #274 + 0x57CE, // 城, #172 + 0x57FA, // 基, #315 + 0x58EB, // 士, #434 + 0x58F0, // 声, #397 + 0x5904, // 处, #416 + 0x5907, // 备, #270 + 0x590D, // 复, #122 + 0x5916, // 外, #190 + 0x591A, // 多, #40 + 0x5927, // 大, #8 + 0x5929, // 天, #52 + 0x592A, // 太, #456 + 0x5934, // 头, #258 + 0x5973, // 女, #65 + 0x597D, // 好, #62 + 0x5982, // 如, #135 + 0x5A31, // 娱, #452 + 0x5B50, // 子, #37 + 0x5B57, // 字, #285 + 0x5B66, // 学, #19 + 0x5B89, // 安, #144 + 0x5B8C, // 完, #469 + 0x5B9A, // 定, #179 + 0x5B9D, // 宝, #188 + 0x5B9E, // 实, #154 + 0x5BA2, // 客, #174 + 0x5BB6, // 家, #26 + 0x5BB9, // 容, #307 + 0x5BC6, // 密, #471 + 0x5BF9, // 对, #90 + 0x5BFC, // 导, #348 + 0x5C06, // 将, #265 + 0x5C0F, // 小, #28 + 0x5C11, // 少, #379 + 0x5C14, // 尔, #490 + 0x5C31, // 就, #101 + 0x5C55, // 展, #291 + 0x5C71, // 山, #239 + 0x5DDE, // 州, #227 + 0x5DE5, // 工, #73 + 0x5DF1, // 己, #480 + 0x5DF2, // 已, #310 + 0x5E02, // 市, #78 + 0x5E03, // 布, #350 + 0x5E08, // 师, #277 + 0x5E16, // 帖, #396 + 0x5E26, // 带, #449 + 0x5E2E, // 帮, #461 + 0x5E38, // 常, #319 + 0x5E73, // 平, #217 + 0x5E74, // 年, #20 + 0x5E76, // 并, #440 + 0x5E7F, // 广, #166 + 0x5E93, // 库, #446 + 0x5E94, // 应, #187 + 0x5E97, // 店, #320 + 0x5EA6, // 度, #114 + 0x5EB7, // 康, #499 + 0x5EFA, // 建, #211 + 0x5F00, // 开, #72 + 0x5F0F, // 式, #207 + 0x5F15, // 引, #495 + 0x5F20, // 张, #385 + 0x5F3A, // 强, #404 + 0x5F53, // 当, #233 + 0x5F55, // 录, #146 + 0x5F62, // 形, #494 + 0x5F69, // 彩, #356 + 0x5F71, // 影, #214 + 0x5F88, // 很, #300 + 0x5F97, // 得, #193 + 0x5FAE, // 微, #245 + 0x5FC3, // 心, #70 + 0x5FEB, // 快, #324 + 0x6001, // 态, #508 + 0x600E, // 怎, #370 + 0x6027, // 性, #99 + 0x603B, // 总, #398 + 0x606F, // 息, #176 + 0x60A8, // 您, #251 + 0x60C5, // 情, #87 + 0x60F3, // 想, #290 + 0x610F, // 意, #184 + 0x611F, // 感, #253 + 0x620F, // 戏, #237 + 0x6210, // 成, #71 + 0x6211, // 我, #11 + 0x6216, // 或, #321 + 0x6218, // 战, #369 + 0x6237, // 户, #215 + 0x623F, // 房, #236 + 0x6240, // 所, #147 + 0x624B, // 手, #55 + 0x624D, // 才, #407 + 0x6253, // 打, #281 + 0x6280, // 技, #203 + 0x6295, // 投, #408 + 0x62A4, // 护, #502 + 0x62A5, // 报, #113 + 0x62DB, // 招, #363 + 0x6301, // 持, #403 + 0x6307, // 指, #414 + 0x636E, // 据, #409 + 0x6392, // 排, #377 + 0x63A5, // 接, #266 + 0x63A8, // 推, #244 + 0x63D0, // 提, #181 + 0x641C, // 搜, #301 + 0x64AD, // 播, #401 + 0x652F, // 支, #400 + 0x6536, // 收, #158 + 0x653E, // 放, #317 + 0x653F, // 政, #380 + 0x6548, // 效, #496 + 0x6559, // 教, #170 + 0x6570, // 数, #136 + 0x6587, // 文, #21 + 0x6599, // 料, #295 + 0x65AF, // 斯, #473 + 0x65B0, // 新, #14 + 0x65B9, // 方, #68 + 0x65C5, // 旅, #457 + 0x65E0, // 无, #164 + 0x65E5, // 日, #50 + 0x65F6, // 时, #18 + 0x660E, // 明, #132 + 0x6613, // 易, #428 + 0x661F, // 星, #240 + 0x662F, // 是, #6 + 0x663E, // 显, #486 + 0x66F4, // 更, #103 + 0x6700, // 最, #61 + 0x6708, // 月, #80 + 0x6709, // 有, #5 + 0x670D, // 服, #94 + 0x671F, // 期, #139 + 0x672C, // 本, #56 + 0x672F, // 术, #216 + 0x673A, // 机, #27 + 0x6743, // 权, #250 + 0x6761, // 条, #309 + 0x6765, // 来, #42 + 0x677F, // 板, #505 + 0x6797, // 林, #475 + 0x679C, // 果, #212 + 0x67E5, // 查, #165 + 0x6807, // 标, #269 + 0x6821, // 校, #462 + 0x6837, // 样, #314 + 0x683C, // 格, #238 + 0x6848, // 案, #378 + 0x697C, // 楼, #342 + 0x6A21, // 模, #413 + 0x6B21, // 次, #263 + 0x6B22, // 欢, #443 + 0x6B3E, // 款, #358 + 0x6B63, // 正, #219 + 0x6B64, // 此, #362 + 0x6BD4, // 比, #298 + 0x6C11, // 民, #279 + 0x6C14, // 气, #303 + 0x6C34, // 水, #163 + 0x6C42, // 求, #373 + 0x6C5F, // 江, #336 + 0x6CA1, // 没, #229 + 0x6CBB, // 治, #425 + 0x6CD5, // 法, #85 + 0x6CE8, // 注, #119 + 0x6D3B, // 活, #231 + 0x6D41, // 流, #280 + 0x6D4B, // 测, #460 + 0x6D77, // 海, #124 + 0x6D88, // 消, #415 + 0x6DF1, // 深, #477 + 0x6E05, // 清, #311 + 0x6E38, // 游, #81 + 0x6E90, // 源, #325 + 0x706B, // 火, #498 + 0x70B9, // 点, #58 + 0x70ED, // 热, #183 + 0x7136, // 然, #308 + 0x7167, // 照, #431 + 0x7231, // 爱, #223 + 0x7247, // 片, #128 + 0x7248, // 版, #91 + 0x724C, // 牌, #429 + 0x7269, // 物, #169 + 0x7279, // 特, #224 + 0x738B, // 王, #351 + 0x73A9, // 玩, #476 + 0x73B0, // 现, #125 + 0x7403, // 球, #367 + 0x7406, // 理, #69 + 0x751F, // 生, #24 + 0x7528, // 用, #17 + 0x7531, // 由, #441 + 0x7535, // 电, #34 + 0x7537, // 男, #275 + 0x754C, // 界, #419 + 0x75C5, // 病, #371 + 0x767B, // 登, #204 + 0x767D, // 白, #338 + 0x767E, // 百, #157 + 0x7684, // 的, #1 + 0x76D8, // 盘, #493 + 0x76EE, // 目, #261 + 0x76F4, // 直, #391 + 0x76F8, // 相, #143 + 0x7701, // 省, #464 + 0x770B, // 看, #54 + 0x771F, // 真, #249 + 0x7740, // 着, #302 + 0x77E5, // 知, #142 + 0x7801, // 码, #257 + 0x7814, // 研, #387 + 0x793A, // 示, #334 + 0x793E, // 社, #343 + 0x795E, // 神, #330 + 0x798F, // 福, #509 + 0x79BB, // 离, #454 + 0x79CD, // 种, #278 + 0x79D1, // 科, #126 + 0x79EF, // 积, #390 + 0x7A0B, // 程, #209 + 0x7A76, // 究, #504 + 0x7A7A, // 空, #312 + 0x7ACB, // 立, #393 + 0x7AD9, // 站, #107 + 0x7AE0, // 章, #304 + 0x7B2C, // 第, #96 + 0x7B49, // 等, #210 + 0x7B54, // 答, #256 + 0x7B80, // 简, #474 + 0x7BA1, // 管, #221 + 0x7C7B, // 类, #246 + 0x7CBE, // 精, #226 + 0x7CFB, // 系, #89 + 0x7D22, // 索, #354 + 0x7EA2, // 红, #417 + 0x7EA7, // 级, #178 + 0x7EBF, // 线, #108 + 0x7EC4, // 组, #389 + 0x7EC6, // 细, #442 + 0x7ECF, // 经, #74 + 0x7ED3, // 结, #333 + 0x7ED9, // 给, #384 + 0x7EDC, // 络, #472 + 0x7EDF, // 统, #344 + 0x7F16, // 编, #424 + 0x7F51, // 网, #9 + 0x7F6E, // 置, #411 + 0x7F8E, // 美, #60 + 0x8001, // 老, #292 + 0x8003, // 考, #288 + 0x8005, // 者, #106 + 0x800C, // 而, #297 + 0x8054, // 联, #159 + 0x80B2, // 育, #327 + 0x80FD, // 能, #59 + 0x81EA, // 自, #77 + 0x8272, // 色, #198 + 0x8282, // 节, #361 + 0x82B1, // 花, #299 + 0x82F1, // 英, #316 + 0x8350, // 荐, #402 + 0x836F, // 药, #481 + 0x8425, // 营, #394 + 0x85CF, // 藏, #337 + 0x884C, // 行, #41 + 0x8868, // 表, #104 + 0x88AB, // 被, #289 + 0x88C5, // 装, #161 + 0x897F, // 西, #199 + 0x8981, // 要, #48 + 0x89C1, // 见, #360 + 0x89C2, // 观, #423 + 0x89C4, // 规, #453 + 0x89C6, // 视, #120 + 0x89E3, // 解, #264 + 0x8A00, // 言, #433 + 0x8BA1, // 计, #191 + 0x8BA4, // 认, #482 + 0x8BA9, // 让, #421 + 0x8BAE, // 议, #427 + 0x8BAF, // 讯, #388 + 0x8BB0, // 记, #273 + 0x8BBA, // 论, #66 + 0x8BBE, // 设, #162 + 0x8BC1, // 证, #201 + 0x8BC4, // 评, #111 + 0x8BC6, // 识, #463 + 0x8BD5, // 试, #323 + 0x8BDD, // 话, #247 + 0x8BE2, // 询, #432 + 0x8BE5, // 该, #447 + 0x8BE6, // 详, #497 + 0x8BED, // 语, #268 + 0x8BF4, // 说, #112 + 0x8BF7, // 请, #213 + 0x8BFB, // 读, #341 + 0x8C03, // 调, #438 + 0x8D22, // 财, #488 + 0x8D28, // 质, #386 + 0x8D2D, // 购, #260 + 0x8D34, // 贴, #510 + 0x8D39, // 费, #242 + 0x8D44, // 资, #116 + 0x8D77, // 起, #220 + 0x8D85, // 超, #406 + 0x8DEF, // 路, #235 + 0x8EAB, // 身, #262 + 0x8F66, // 车, #82 + 0x8F6C, // 转, #322 + 0x8F7D, // 载, #175 + 0x8FBE, // 达, #435 + 0x8FC7, // 过, #118 + 0x8FD0, // 运, #357 + 0x8FD1, // 近, #492 + 0x8FD8, // 还, #171 + 0x8FD9, // 这, #57 + 0x8FDB, // 进, #160 + 0x8FDE, // 连, #489 + 0x9009, // 选, #328 + 0x901A, // 通, #137 + 0x901F, // 速, #458 + 0x9020, // 造, #511 + 0x9053, // 道, #79 + 0x90A3, // 那, #305 + 0x90E8, // 部, #102 + 0x90FD, // 都, #167 + 0x914D, // 配, #479 + 0x9152, // 酒, #444 + 0x91CC, // 里, #196 + 0x91CD, // 重, #230 + 0x91CF, // 量, #248 + 0x91D1, // 金, #134 + 0x9500, // 销, #465 + 0x957F, // 长, #152 + 0x95E8, // 门, #185 + 0x95EE, // 问, #92 + 0x95F4, // 间, #88 + 0x95FB, // 闻, #313 + 0x9605, // 阅, #467 + 0x9633, // 阳, #420 + 0x9645, // 际, #501 + 0x9650, // 限, #286 + 0x9662, // 院, #276 + 0x96C6, // 集, #284 + 0x9700, // 需, #405 + 0x9762, // 面, #123 + 0x97F3, // 音, #335 + 0x9875, // 页, #63 + 0x9879, // 项, #506 + 0x9891, // 频, #200 + 0x9898, // 题, #110 + 0x98CE, // 风, #252 + 0x98DF, // 食, #445 + 0x9996, // 首, #149 + 0x9999, // 香, #512 + 0x9A6C, // 马, #392 + 0x9A8C, // 验, #382 + 0x9AD8, // 高, #67 + 0x9F99, // 龙, #426 +}; +// the percentage of the sample covered by the above characters +static const float frequent_zhCN_coverage=0.718950369339973; + +// The 512 most frequently occuring characters for the zhTW language in a sample of the Internet. +// Ordered by codepoint, comment shows character and ranking by frequency +const uint16_t frequent_zhTW[] = { + 0x4E00, // 一, #2 + 0x4E09, // 三, #131 + 0x4E0A, // 上, #12 + 0x4E0B, // 下, #37 + 0x4E0D, // 不, #6 + 0x4E16, // 世, #312 + 0x4E26, // 並, #434 + 0x4E2D, // 中, #9 + 0x4E3B, // 主, #97 + 0x4E4B, // 之, #55 + 0x4E5F, // 也, #95 + 0x4E86, // 了, #19 + 0x4E8B, // 事, #128 + 0x4E8C, // 二, #187 + 0x4E94, // 五, #339 + 0x4E9B, // 些, #435 + 0x4E9E, // 亞, #432 + 0x4EA4, // 交, #264 + 0x4EAB, // 享, #160 + 0x4EBA, // 人, #3 + 0x4EC0, // 什, #483 + 0x4ECA, // 今, #380 + 0x4ECB, // 介, #468 + 0x4ED6, // 他, #65 + 0x4EE3, // 代, #284 + 0x4EE5, // 以, #26 + 0x4EF6, // 件, #234 + 0x4EFB, // 任, #381 + 0x4EFD, // 份, #447 + 0x4F46, // 但, #281 + 0x4F4D, // 位, #202 + 0x4F4F, // 住, #471 + 0x4F55, // 何, #334 + 0x4F5C, // 作, #56 + 0x4F60, // 你, #64 + 0x4F7F, // 使, #236 + 0x4F86, // 來, #38 + 0x4F9B, // 供, #397 + 0x4FBF, // 便, #440 + 0x4FC2, // 係, #506 + 0x4FDD, // 保, #161 + 0x4FE1, // 信, #268 + 0x4FEE, // 修, #473 + 0x500B, // 個, #27 + 0x5011, // 們, #109 + 0x505A, // 做, #383 + 0x5065, // 健, #415 + 0x5099, // 備, #461 + 0x50B3, // 傳, #277 + 0x50CF, // 像, #403 + 0x50F9, // 價, #93 + 0x512A, // 優, #396 + 0x5143, // 元, #158 + 0x5148, // 先, #382 + 0x5149, // 光, #216 + 0x514D, // 免, #321 + 0x5152, // 兒, #374 + 0x5165, // 入, #58 + 0x5167, // 內, #106 + 0x5168, // 全, #67 + 0x5169, // 兩, #322 + 0x516C, // 公, #53 + 0x516D, // 六, #493 + 0x5171, // 共, #456 + 0x5176, // 其, #148 + 0x5177, // 具, #328 + 0x518A, // 冊, #360 + 0x518D, // 再, #311 + 0x51FA, // 出, #44 + 0x5206, // 分, #15 + 0x5217, // 列, #259 + 0x5225, // 別, #361 + 0x5229, // 利, #251 + 0x5230, // 到, #29 + 0x5247, // 則, #511 + 0x524D, // 前, #82 + 0x5275, // 創, #409 + 0x529B, // 力, #176 + 0x529F, // 功, #430 + 0x52A0, // 加, #87 + 0x52A9, // 助, #465 + 0x52D5, // 動, #48 + 0x52D9, // 務, #102 + 0x5305, // 包, #248 + 0x5316, // 化, #223 + 0x5317, // 北, #145 + 0x5340, // 區, #60 + 0x5341, // 十, #242 + 0x5357, // 南, #261 + 0x535A, // 博, #484 + 0x5361, // 卡, #327 + 0x5370, // 印, #498 + 0x5373, // 即, #351 + 0x539F, // 原, #237 + 0x53BB, // 去, #190 + 0x53C3, // 參, #444 + 0x53C8, // 又, #426 + 0x53CA, // 及, #136 + 0x53CB, // 友, #142 + 0x53D6, // 取, #422 + 0x53D7, // 受, #410 + 0x53E3, // 口, #357 + 0x53EA, // 只, #250 + 0x53EF, // 可, #35 + 0x53F0, // 台, #34 + 0x53F8, // 司, #226 + 0x5403, // 吃, #362 + 0x5404, // 各, #454 + 0x5408, // 合, #147 + 0x540C, // 同, #173 + 0x540D, // 名, #108 + 0x544A, // 告, #186 + 0x548C, // 和, #130 + 0x54C1, // 品, #23 + 0x54E1, // 員, #150 + 0x5546, // 商, #75 + 0x554F, // 問, #120 + 0x559C, // 喜, #502 + 0x55AE, // 單, #210 + 0x55CE, // 嗎, #443 + 0x5668, // 器, #305 + 0x56DB, // 四, #318 + 0x56DE, // 回, #59 + 0x56E0, // 因, #253 + 0x570B, // 國, #21 + 0x5712, // 園, #345 + 0x5716, // 圖, #73 + 0x5718, // 團, #338 + 0x5728, // 在, #11 + 0x5730, // 地, #50 + 0x578B, // 型, #270 + 0x57CE, // 城, #466 + 0x57FA, // 基, #349 + 0x5831, // 報, #127 + 0x5834, // 場, #165 + 0x58EB, // 士, #372 + 0x5916, // 外, #152 + 0x591A, // 多, #54 + 0x5927, // 大, #8 + 0x5929, // 天, #43 + 0x592A, // 太, #343 + 0x5947, // 奇, #325 + 0x5973, // 女, #85 + 0x5979, // 她, #420 + 0x597D, // 好, #22 + 0x5982, // 如, #144 + 0x5B50, // 子, #46 + 0x5B57, // 字, #275 + 0x5B78, // 學, #49 + 0x5B89, // 安, #239 + 0x5B8C, // 完, #320 + 0x5B9A, // 定, #159 + 0x5BA2, // 客, #188 + 0x5BB6, // 家, #31 + 0x5BB9, // 容, #244 + 0x5BE6, // 實, #198 + 0x5BF6, // 寶, #367 + 0x5C07, // 將, #232 + 0x5C08, // 專, #133 + 0x5C0B, // 尋, #352 + 0x5C0D, // 對, #126 + 0x5C0E, // 導, #418 + 0x5C0F, // 小, #20 + 0x5C11, // 少, #368 + 0x5C31, // 就, #63 + 0x5C55, // 展, #341 + 0x5C71, // 山, #273 + 0x5DE5, // 工, #121 + 0x5DF1, // 己, #402 + 0x5DF2, // 已, #299 + 0x5E02, // 市, #81 + 0x5E2B, // 師, #262 + 0x5E36, // 帶, #470 + 0x5E38, // 常, #303 + 0x5E73, // 平, #297 + 0x5E74, // 年, #30 + 0x5E97, // 店, #171 + 0x5EA6, // 度, #220 + 0x5EB7, // 康, #441 + 0x5EE3, // 廣, #279 + 0x5EFA, // 建, #254 + 0x5F0F, // 式, #155 + 0x5F15, // 引, #346 + 0x5F35, // 張, #366 + 0x5F37, // 強, #437 + 0x5F71, // 影, #94 + 0x5F88, // 很, #177 + 0x5F8C, // 後, #66 + 0x5F97, // 得, #113 + 0x5F9E, // 從, #436 + 0x5FC3, // 心, #57 + 0x5FEB, // 快, #292 + 0x6027, // 性, #175 + 0x606F, // 息, #378 + 0x60A8, // 您, #252 + 0x60C5, // 情, #123 + 0x60F3, // 想, #178 + 0x610F, // 意, #168 + 0x611B, // 愛, #125 + 0x611F, // 感, #211 + 0x61C9, // 應, #164 + 0x6210, // 成, #86 + 0x6211, // 我, #7 + 0x6216, // 或, #199 + 0x6230, // 戰, #438 + 0x6232, // 戲, #309 + 0x6236, // 戶, #497 + 0x623F, // 房, #274 + 0x6240, // 所, #79 + 0x624B, // 手, #68 + 0x624D, // 才, #400 + 0x6253, // 打, #278 + 0x627E, // 找, #449 + 0x6280, // 技, #332 + 0x6295, // 投, #425 + 0x62C9, // 拉, #500 + 0x62CD, // 拍, #398 + 0x6307, // 指, #407 + 0x6392, // 排, #458 + 0x63A5, // 接, #326 + 0x63A8, // 推, #153 + 0x63D0, // 提, #235 + 0x641C, // 搜, #314 + 0x6469, // 摩, #472 + 0x6536, // 收, #249 + 0x6539, // 改, #508 + 0x653E, // 放, #331 + 0x653F, // 政, #295 + 0x6559, // 教, #184 + 0x6574, // 整, #394 + 0x6578, // 數, #134 + 0x6587, // 文, #16 + 0x6599, // 料, #167 + 0x65AF, // 斯, #476 + 0x65B0, // 新, #10 + 0x65B9, // 方, #96 + 0x65BC, // 於, #70 + 0x65C5, // 旅, #289 + 0x65E5, // 日, #18 + 0x660E, // 明, #118 + 0x6613, // 易, #482 + 0x661F, // 星, #205 + 0x662F, // 是, #5 + 0x6642, // 時, #13 + 0x66F4, // 更, #149 + 0x66F8, // 書, #209 + 0x6700, // 最, #51 + 0x6703, // 會, #14 + 0x6708, // 月, #25 + 0x6709, // 有, #4 + 0x670D, // 服, #99 + 0x671F, // 期, #139 + 0x672A, // 未, #404 + 0x672C, // 本, #45 + 0x6771, // 東, #221 + 0x677F, // 板, #364 + 0x6797, // 林, #330 + 0x679C, // 果, #179 + 0x67E5, // 查, #283 + 0x683C, // 格, #157 + 0x6848, // 案, #392 + 0x689D, // 條, #406 + 0x696D, // 業, #103 + 0x6A02, // 樂, #116 + 0x6A13, // 樓, #411 + 0x6A19, // 標, #384 + 0x6A23, // 樣, #306 + 0x6A5F, // 機, #40 + 0x6AA2, // 檢, #359 + 0x6B0A, // 權, #228 + 0x6B21, // 次, #227 + 0x6B3E, // 款, #276 + 0x6B4C, // 歌, #496 + 0x6B61, // 歡, #427 + 0x6B63, // 正, #206 + 0x6B64, // 此, #247 + 0x6BCF, // 每, #391 + 0x6BD4, // 比, #257 + 0x6C11, // 民, #230 + 0x6C23, // 氣, #200 + 0x6C34, // 水, #140 + 0x6C42, // 求, #501 + 0x6C92, // 沒, #162 + 0x6CD5, // 法, #89 + 0x6D3B, // 活, #124 + 0x6D41, // 流, #315 + 0x6D77, // 海, #258 + 0x6D88, // 消, #342 + 0x6E05, // 清, #329 + 0x6E2F, // 港, #293 + 0x6F14, // 演, #491 + 0x7063, // 灣, #195 + 0x70BA, // 為, #39 + 0x7121, // 無, #107 + 0x7136, // 然, #215 + 0x7167, // 照, #376 + 0x71B1, // 熱, #245 + 0x7247, // 片, #90 + 0x7248, // 版, #112 + 0x724C, // 牌, #467 + 0x7269, // 物, #110 + 0x7279, // 特, #183 + 0x738B, // 王, #287 + 0x73A9, // 玩, #354 + 0x73FE, // 現, #143 + 0x7403, // 球, #350 + 0x7406, // 理, #105 + 0x751F, // 生, #24 + 0x7522, // 產, #201 + 0x7528, // 用, #17 + 0x7531, // 由, #288 + 0x7537, // 男, #298 + 0x754C, // 界, #399 + 0x7559, // 留, #218 + 0x756B, // 畫, #412 + 0x7576, // 當, #185 + 0x767B, // 登, #138 + 0x767C, // 發, #28 + 0x767D, // 白, #377 + 0x767E, // 百, #393 + 0x7684, // 的, #1 + 0x76EE, // 目, #271 + 0x76F4, // 直, #379 + 0x76F8, // 相, #98 + 0x770B, // 看, #52 + 0x771F, // 真, #180 + 0x773C, // 眼, #433 + 0x77E5, // 知, #170 + 0x78BC, // 碼, #481 + 0x793A, // 示, #353 + 0x793E, // 社, #333 + 0x795E, // 神, #304 + 0x7968, // 票, #477 + 0x798F, // 福, #494 + 0x79C1, // 私, #507 + 0x79D1, // 科, #280 + 0x7A0B, // 程, #272 + 0x7A2E, // 種, #337 + 0x7A4D, // 積, #385 + 0x7A7A, // 空, #324 + 0x7ACB, // 立, #286 + 0x7AD9, // 站, #117 + 0x7AE0, // 章, #141 + 0x7B2C, // 第, #135 + 0x7B49, // 等, #240 + 0x7BA1, // 管, #340 + 0x7BC0, // 節, #431 + 0x7BC7, // 篇, #479 + 0x7C21, // 簡, #499 + 0x7CBE, // 精, #213 + 0x7CFB, // 系, #212 + 0x7D04, // 約, #462 + 0x7D05, // 紅, #452 + 0x7D1A, // 級, #267 + 0x7D30, // 細, #486 + 0x7D44, // 組, #335 + 0x7D50, // 結, #243 + 0x7D66, // 給, #355 + 0x7D71, // 統, #375 + 0x7D93, // 經, #111 + 0x7DB2, // 網, #32 + 0x7DDA, // 線, #151 + 0x7E23, // 縣, #439 + 0x7E3D, // 總, #370 + 0x7F8E, // 美, #41 + 0x7FA9, // 義, #504 + 0x8001, // 老, #290 + 0x8003, // 考, #428 + 0x8005, // 者, #92 + 0x800C, // 而, #217 + 0x805E, // 聞, #181 + 0x806F, // 聯, #310 + 0x8072, // 聲, #413 + 0x80A1, // 股, #390 + 0x80B2, // 育, #453 + 0x80FD, // 能, #71 + 0x8166, // 腦, #408 + 0x81EA, // 自, #61 + 0x81F3, // 至, #344 + 0x8207, // 與, #84 + 0x8209, // 舉, #463 + 0x8272, // 色, #192 + 0x82B1, // 花, #255 + 0x82F1, // 英, #348 + 0x83EF, // 華, #196 + 0x842C, // 萬, #316 + 0x843D, // 落, #308 + 0x8457, // 著, #233 + 0x85A6, // 薦, #401 + 0x85CF, // 藏, #503 + 0x85DD, // 藝, #488 + 0x8655, // 處, #419 + 0x865F, // 號, #191 + 0x884C, // 行, #47 + 0x8853, // 術, #395 + 0x8868, // 表, #77 + 0x88AB, // 被, #291 + 0x88DD, // 裝, #256 + 0x88E1, // 裡, #369 + 0x88FD, // 製, #510 + 0x897F, // 西, #300 + 0x8981, // 要, #36 + 0x898B, // 見, #307 + 0x8996, // 視, #204 + 0x89BA, // 覺, #450 + 0x89BD, // 覽, #387 + 0x89C0, // 觀, #365 + 0x89E3, // 解, #323 + 0x8A00, // 言, #169 + 0x8A02, // 訂, #423 + 0x8A08, // 計, #225 + 0x8A0A, // 訊, #156 + 0x8A0E, // 討, #373 + 0x8A18, // 記, #222 + 0x8A2D, // 設, #174 + 0x8A3B, // 註, #356 + 0x8A55, // 評, #246 + 0x8A66, // 試, #448 + 0x8A71, // 話, #229 + 0x8A72, // 該, #446 + 0x8A8D, // 認, #464 + 0x8A9E, // 語, #371 + 0x8AAA, // 說, #91 + 0x8ABF, // 調, #509 + 0x8ACB, // 請, #119 + 0x8AD6, // 論, #114 + 0x8B1D, // 謝, #389 + 0x8B49, // 證, #429 + 0x8B58, // 識, #416 + 0x8B70, // 議, #485 + 0x8B77, // 護, #475 + 0x8B80, // 讀, #386 + 0x8B8A, // 變, #388 + 0x8B93, // 讓, #336 + 0x8CA8, // 貨, #313 + 0x8CB7, // 買, #260 + 0x8CBB, // 費, #203 + 0x8CC7, // 資, #62 + 0x8CE3, // 賣, #294 + 0x8CEA, // 質, #457 + 0x8CFC, // 購, #189 + 0x8D77, // 起, #214 + 0x8D85, // 超, #296 + 0x8DDF, // 跟, #489 + 0x8DEF, // 路, #137 + 0x8EAB, // 身, #197 + 0x8ECA, // 車, #76 + 0x8F09, // 載, #301 + 0x8F49, // 轉, #282 + 0x8FD1, // 近, #414 + 0x9001, // 送, #363 + 0x9019, // 這, #42 + 0x901A, // 通, #207 + 0x901F, // 速, #495 + 0x9020, // 造, #455 + 0x9023, // 連, #285 + 0x9032, // 進, #231 + 0x904A, // 遊, #132 + 0x904B, // 運, #219 + 0x904E, // 過, #101 + 0x9053, // 道, #146 + 0x9054, // 達, #417 + 0x9078, // 選, #182 + 0x9084, // 還, #154 + 0x908A, // 邊, #487 + 0x90A3, // 那, #269 + 0x90E8, // 部, #78 + 0x90FD, // 都, #104 + 0x914D, // 配, #421 + 0x9152, // 酒, #512 + 0x91AB, // 醫, #358 + 0x91CD, // 重, #224 + 0x91CF, // 量, #319 + 0x91D1, // 金, #115 + 0x9304, // 錄, #302 + 0x9577, // 長, #172 + 0x9580, // 門, #193 + 0x958B, // 開, #72 + 0x9593, // 間, #80 + 0x95B1, // 閱, #405 + 0x95DC, // 關, #74 + 0x963F, // 阿, #460 + 0x9650, // 限, #265 + 0x9662, // 院, #474 + 0x9664, // 除, #478 + 0x969B, // 際, #459 + 0x96C6, // 集, #347 + 0x96E2, // 離, #442 + 0x96FB, // 電, #33 + 0x9700, // 需, #445 + 0x975E, // 非, #451 + 0x9762, // 面, #129 + 0x97F3, // 音, #194 + 0x9801, // 頁, #83 + 0x982D, // 頭, #238 + 0x984C, // 題, #122 + 0x985E, // 類, #163 + 0x98A8, // 風, #266 + 0x98DF, // 食, #208 + 0x9910, // 餐, #469 + 0x9928, // 館, #424 + 0x9996, // 首, #166 + 0x9999, // 香, #263 + 0x99AC, // 馬, #317 + 0x9A57, // 驗, #492 + 0x9AD4, // 體, #100 + 0x9AD8, // 高, #88 + 0x9EBC, // 麼, #241 + 0x9EC3, // 黃, #480 + 0x9ED1, // 黑, #490 + 0x9EDE, // 點, #69 + 0x9F8D, // 龍, #505 +}; +// the percentage of the sample covered by the above characters +static const float frequent_zhTW_coverage=0.704841200026877; + +// The 512 most frequently occuring characters for the ja language in a sample of the Internet. +// Ordered by codepoint, comment shows character and ranking by frequency +const uint16_t frequent_ja[] = { + 0x3005, // 々, #352 + 0x3041, // ぁ, #486 + 0x3042, // あ, #50 + 0x3044, // い, #2 + 0x3046, // う, #33 + 0x3048, // え, #83 + 0x304A, // お, #37 + 0x304B, // か, #21 + 0x304C, // が, #17 + 0x304D, // き, #51 + 0x304E, // ぎ, #324 + 0x304F, // く, #38 + 0x3050, // ぐ, #334 + 0x3051, // け, #60 + 0x3052, // げ, #296 + 0x3053, // こ, #34 + 0x3054, // ご, #100 + 0x3055, // さ, #31 + 0x3056, // ざ, #378 + 0x3057, // し, #4 + 0x3058, // じ, #121 + 0x3059, // す, #12 + 0x305A, // ず, #215 + 0x305B, // せ, #86 + 0x305D, // そ, #68 + 0x305F, // た, #11 + 0x3060, // だ, #42 + 0x3061, // ち, #67 + 0x3063, // っ, #23 + 0x3064, // つ, #73 + 0x3066, // て, #7 + 0x3067, // で, #6 + 0x3068, // と, #14 + 0x3069, // ど, #75 + 0x306A, // な, #8 + 0x306B, // に, #5 + 0x306D, // ね, #123 + 0x306E, // の, #1 + 0x306F, // は, #16 + 0x3070, // ば, #150 + 0x3071, // ぱ, #259 + 0x3072, // ひ, #364 + 0x3073, // び, #266 + 0x3075, // ふ, #484 + 0x3076, // ぶ, #330 + 0x3078, // へ, #146 + 0x3079, // べ, #207 + 0x307B, // ほ, #254 + 0x307E, // ま, #18 + 0x307F, // み, #74 + 0x3080, // む, #285 + 0x3081, // め, #78 + 0x3082, // も, #32 + 0x3083, // ゃ, #111 + 0x3084, // や, #85 + 0x3086, // ゆ, #392 + 0x3087, // ょ, #224 + 0x3088, // よ, #63 + 0x3089, // ら, #29 + 0x308A, // り, #28 + 0x308B, // る, #9 + 0x308C, // れ, #35 + 0x308D, // ろ, #127 + 0x308F, // わ, #88 + 0x3092, // を, #19 + 0x3093, // ん, #22 + 0x30A1, // ァ, #193 + 0x30A2, // ア, #27 + 0x30A3, // ィ, #70 + 0x30A4, // イ, #15 + 0x30A6, // ウ, #89 + 0x30A7, // ェ, #134 + 0x30A8, // エ, #81 + 0x30A9, // ォ, #225 + 0x30AA, // オ, #76 + 0x30AB, // カ, #52 + 0x30AC, // ガ, #147 + 0x30AD, // キ, #66 + 0x30AE, // ギ, #246 + 0x30AF, // ク, #25 + 0x30B0, // グ, #39 + 0x30B1, // ケ, #137 + 0x30B2, // ゲ, #200 + 0x30B3, // コ, #46 + 0x30B4, // ゴ, #183 + 0x30B5, // サ, #64 + 0x30B6, // ザ, #221 + 0x30B7, // シ, #48 + 0x30B8, // ジ, #55 + 0x30B9, // ス, #13 + 0x30BA, // ズ, #103 + 0x30BB, // セ, #109 + 0x30BC, // ゼ, #499 + 0x30BD, // ソ, #175 + 0x30BF, // タ, #45 + 0x30C0, // ダ, #104 + 0x30C1, // チ, #71 + 0x30C3, // ッ, #20 + 0x30C4, // ツ, #119 + 0x30C6, // テ, #59 + 0x30C7, // デ, #82 + 0x30C8, // ト, #10 + 0x30C9, // ド, #44 + 0x30CA, // ナ, #102 + 0x30CB, // ニ, #72 + 0x30CD, // ネ, #117 + 0x30CE, // ノ, #192 + 0x30CF, // ハ, #164 + 0x30D0, // バ, #62 + 0x30D1, // パ, #90 + 0x30D2, // ヒ, #398 + 0x30D3, // ビ, #77 + 0x30D4, // ピ, #135 + 0x30D5, // フ, #47 + 0x30D6, // ブ, #56 + 0x30D7, // プ, #43 + 0x30D8, // ヘ, #268 + 0x30D9, // ベ, #157 + 0x30DA, // ペ, #125 + 0x30DB, // ホ, #155 + 0x30DC, // ボ, #168 + 0x30DD, // ポ, #114 + 0x30DE, // マ, #57 + 0x30DF, // ミ, #97 + 0x30E0, // ム, #69 + 0x30E1, // メ, #53 + 0x30E2, // モ, #142 + 0x30E3, // ャ, #93 + 0x30E4, // ヤ, #258 + 0x30E5, // ュ, #79 + 0x30E6, // ユ, #405 + 0x30E7, // ョ, #98 + 0x30E9, // ラ, #26 + 0x30EA, // リ, #30 + 0x30EB, // ル, #24 + 0x30EC, // レ, #41 + 0x30ED, // ロ, #40 + 0x30EF, // ワ, #144 + 0x30F3, // ン, #3 + 0x30F4, // ヴ, #483 + 0x30FD, // ヽ, #501 + 0x4E00, // 一, #84 + 0x4E07, // 万, #337 + 0x4E09, // 三, #323 + 0x4E0A, // 上, #133 + 0x4E0B, // 下, #180 + 0x4E0D, // 不, #277 + 0x4E16, // 世, #385 + 0x4E2D, // 中, #87 + 0x4E3B, // 主, #432 + 0x4E88, // 予, #326 + 0x4E8B, // 事, #95 + 0x4E8C, // 二, #394 + 0x4E95, // 井, #468 + 0x4EA4, // 交, #410 + 0x4EAC, // 京, #260 + 0x4EBA, // 人, #61 + 0x4ECA, // 今, #184 + 0x4ECB, // 介, #358 + 0x4ED5, // 仕, #391 + 0x4ED6, // 他, #256 + 0x4ED8, // 付, #243 + 0x4EE3, // 代, #280 + 0x4EE5, // 以, #216 + 0x4EF6, // 件, #190 + 0x4F1A, // 会, #105 + 0x4F4D, // 位, #177 + 0x4F4F, // 住, #376 + 0x4F53, // 体, #223 + 0x4F55, // 何, #294 + 0x4F5C, // 作, #154 + 0x4F7F, // 使, #233 + 0x4F9B, // 供, #503 + 0x4FA1, // 価, #217 + 0x4FBF, // 便, #511 + 0x4FDD, // 保, #279 + 0x4FE1, // 信, #271 + 0x500B, // 個, #415 + 0x50CF, // 像, #178 + 0x512A, // 優, #403 + 0x5143, // 元, #384 + 0x5148, // 先, #311 + 0x5149, // 光, #488 + 0x5165, // 入, #115 + 0x5168, // 全, #173 + 0x516C, // 公, #287 + 0x5177, // 具, #447 + 0x5185, // 内, #169 + 0x5186, // 円, #131 + 0x5199, // 写, #275 + 0x51FA, // 出, #110 + 0x5206, // 分, #130 + 0x5207, // 切, #401 + 0x521D, // 初, #319 + 0x5225, // 別, #290 + 0x5229, // 利, #226 + 0x5236, // 制, #507 + 0x524D, // 前, #124 + 0x529B, // 力, #272 + 0x52A0, // 加, #249 + 0x52D5, // 動, #120 + 0x52D9, // 務, #421 + 0x52DF, // 募, #476 + 0x5316, // 化, #308 + 0x5317, // 北, #341 + 0x533A, // 区, #348 + 0x539F, // 原, #321 + 0x53C2, // 参, #452 + 0x53CB, // 友, #451 + 0x53D6, // 取, #237 + 0x53D7, // 受, #354 + 0x53E3, // 口, #289 + 0x53E4, // 古, #339 + 0x53EF, // 可, #298 + 0x53F0, // 台, #439 + 0x53F7, // 号, #361 + 0x5408, // 合, #118 + 0x540C, // 同, #263 + 0x540D, // 名, #65 + 0x5411, // 向, #434 + 0x544A, // 告, #386 + 0x5468, // 周, #393 + 0x5473, // 味, #299 + 0x548C, // 和, #350 + 0x54C1, // 品, #96 + 0x54E1, // 員, #293 + 0x5546, // 商, #198 + 0x554F, // 問, #158 + 0x55B6, // 営, #438 + 0x5668, // 器, #366 + 0x56DE, // 回, #143 + 0x56F3, // 図, #444 + 0x56FD, // 国, #153 + 0x5712, // 園, #435 + 0x571F, // 土, #239 + 0x5728, // 在, #351 + 0x5730, // 地, #163 + 0x578B, // 型, #430 + 0x5831, // 報, #112 + 0x5834, // 場, #139 + 0x58F2, // 売, #232 + 0x5909, // 変, #306 + 0x5916, // 外, #222 + 0x591A, // 多, #336 + 0x5927, // 大, #80 + 0x5929, // 天, #278 + 0x5973, // 女, #161 + 0x597D, // 好, #349 + 0x5A5A, // 婚, #479 + 0x5B50, // 子, #113 + 0x5B57, // 字, #492 + 0x5B66, // 学, #132 + 0x5B89, // 安, #295 + 0x5B9A, // 定, #145 + 0x5B9F, // 実, #220 + 0x5BA4, // 室, #482 + 0x5BAE, // 宮, #487 + 0x5BB6, // 家, #211 + 0x5BB9, // 容, #333 + 0x5BFE, // 対, #252 + 0x5C02, // 専, #474 + 0x5C0F, // 小, #212 + 0x5C11, // 少, #377 + 0x5C4B, // 屋, #284 + 0x5C71, // 山, #206 + 0x5CA1, // 岡, #429 + 0x5CF6, // 島, #297 + 0x5DDD, // 川, #253 + 0x5DE5, // 工, #374 + 0x5E02, // 市, #159 + 0x5E2F, // 帯, #416 + 0x5E38, // 常, #437 + 0x5E73, // 平, #390 + 0x5E74, // 年, #54 + 0x5E83, // 広, #367 + 0x5E97, // 店, #149 + 0x5EA6, // 度, #269 + 0x5EAB, // 庫, #380 + 0x5F0F, // 式, #265 + 0x5F15, // 引, #345 + 0x5F37, // 強, #446 + 0x5F53, // 当, #240 + 0x5F62, // 形, #502 + 0x5F8C, // 後, #230 + 0x5F97, // 得, #490 + 0x5FC3, // 心, #307 + 0x5FC5, // 必, #422 + 0x5FDC, // 応, #356 + 0x601D, // 思, #189 + 0x6027, // 性, #201 + 0x6075, // 恵, #400 + 0x60C5, // 情, #140 + 0x60F3, // 想, #477 + 0x610F, // 意, #305 + 0x611B, // 愛, #273 + 0x611F, // 感, #257 + 0x6210, // 成, #262 + 0x6226, // 戦, #365 + 0x6240, // 所, #236 + 0x624B, // 手, #160 + 0x6295, // 投, #129 + 0x6301, // 持, #355 + 0x6307, // 指, #425 + 0x63A2, // 探, #369 + 0x63B2, // 掲, #399 + 0x643A, // 携, #459 + 0x652F, // 支, #512 + 0x653E, // 放, #469 + 0x6559, // 教, #270 + 0x6570, // 数, #181 + 0x6587, // 文, #202 + 0x6599, // 料, #106 + 0x65B0, // 新, #99 + 0x65B9, // 方, #126 + 0x65C5, // 旅, #445 + 0x65E5, // 日, #36 + 0x660E, // 明, #300 + 0x6620, // 映, #418 + 0x6642, // 時, #107 + 0x66F4, // 更, #359 + 0x66F8, // 書, #174 + 0x6700, // 最, #152 + 0x6708, // 月, #49 + 0x6709, // 有, #302 + 0x671F, // 期, #332 + 0x6728, // 木, #203 + 0x672C, // 本, #92 + 0x6750, // 材, #489 + 0x6751, // 村, #466 + 0x6765, // 来, #267 + 0x6771, // 東, #191 + 0x677F, // 板, #411 + 0x679C, // 果, #441 + 0x6821, // 校, #327 + 0x682A, // 株, #412 + 0x683C, // 格, #228 + 0x691C, // 検, #179 + 0x696D, // 業, #166 + 0x697D, // 楽, #172 + 0x69D8, // 様, #255 + 0x6A5F, // 機, #235 + 0x6B21, // 次, #318 + 0x6B62, // 止, #475 + 0x6B63, // 正, #312 + 0x6C17, // 気, #116 + 0x6C34, // 水, #165 + 0x6C42, // 求, #465 + 0x6C7A, // 決, #370 + 0x6CBB, // 治, #505 + 0x6CC1, // 況, #462 + 0x6CD5, // 法, #227 + 0x6CE8, // 注, #372 + 0x6D3B, // 活, #303 + 0x6D41, // 流, #480 + 0x6D77, // 海, #274 + 0x6E08, // 済, #417 + 0x6F14, // 演, #504 + 0x706B, // 火, #264 + 0x70B9, // 点, #331 + 0x7121, // 無, #58 + 0x7248, // 版, #409 + 0x7269, // 物, #170 + 0x7279, // 特, #242 + 0x72B6, // 状, #458 + 0x73FE, // 現, #322 + 0x7406, // 理, #162 + 0x751F, // 生, #122 + 0x7523, // 産, #320 + 0x7528, // 用, #94 + 0x7530, // 田, #195 + 0x7537, // 男, #373 + 0x753A, // 町, #314 + 0x753B, // 画, #91 + 0x754C, // 界, #436 + 0x756A, // 番, #261 + 0x75C5, // 病, #428 + 0x767A, // 発, #194 + 0x767B, // 登, #231 + 0x767D, // 白, #419 + 0x7684, // 的, #251 + 0x76EE, // 目, #197 + 0x76F4, // 直, #497 + 0x76F8, // 相, #286 + 0x770C, // 県, #199 + 0x771F, // 真, #219 + 0x7740, // 着, #283 + 0x77E5, // 知, #185 + 0x77F3, // 石, #500 + 0x78BA, // 確, #383 + 0x793A, // 示, #241 + 0x793E, // 社, #167 + 0x795E, // 神, #315 + 0x798F, // 福, #423 + 0x79C1, // 私, #347 + 0x79D1, // 科, #420 + 0x7A0E, // 税, #368 + 0x7A2E, // 種, #455 + 0x7A3F, // 稿, #148 + 0x7A7A, // 空, #427 + 0x7ACB, // 立, #309 + 0x7B11, // 笑, #454 + 0x7B2C, // 第, #317 + 0x7B49, // 等, #457 + 0x7B54, // 答, #426 + 0x7BA1, // 管, #481 + 0x7CFB, // 系, #408 + 0x7D04, // 約, #276 + 0x7D20, // 素, #407 + 0x7D22, // 索, #214 + 0x7D30, // 細, #381 + 0x7D39, // 紹, #471 + 0x7D42, // 終, #456 + 0x7D44, // 組, #424 + 0x7D4C, // 経, #360 + 0x7D50, // 結, #291 + 0x7D9A, // 続, #357 + 0x7DCF, // 総, #467 + 0x7DDA, // 線, #338 + 0x7DE8, // 編, #453 + 0x7F8E, // 美, #204 + 0x8003, // 考, #387 + 0x8005, // 者, #151 + 0x805E, // 聞, #463 + 0x8077, // 職, #363 + 0x80B2, // 育, #433 + 0x80FD, // 能, #250 + 0x8179, // 腹, #396 + 0x81EA, // 自, #156 + 0x826F, // 良, #329 + 0x8272, // 色, #402 + 0x82B1, // 花, #440 + 0x82B8, // 芸, #413 + 0x82F1, // 英, #485 + 0x8449, // 葉, #472 + 0x884C, // 行, #128 + 0x8853, // 術, #460 + 0x8868, // 表, #209 + 0x88FD, // 製, #431 + 0x897F, // 西, #406 + 0x8981, // 要, #313 + 0x898B, // 見, #101 + 0x898F, // 規, #375 + 0x89A7, // 覧, #171 + 0x89E3, // 解, #388 + 0x8A00, // 言, #210 + 0x8A08, // 計, #343 + 0x8A18, // 記, #136 + 0x8A2D, // 設, #292 + 0x8A71, // 話, #213 + 0x8A73, // 詳, #371 + 0x8A8D, // 認, #404 + 0x8A9E, // 語, #234 + 0x8AAC, // 説, #494 + 0x8AAD, // 読, #301 + 0x8ABF, // 調, #443 + 0x8AC7, // 談, #448 + 0x8B77, // 護, #509 + 0x8C37, // 谷, #506 + 0x8CA9, // 販, #362 + 0x8CB7, // 買, #346 + 0x8CC7, // 資, #473 + 0x8CEA, // 質, #281 + 0x8CFC, // 購, #495 + 0x8EAB, // 身, #470 + 0x8ECA, // 車, #205 + 0x8EE2, // 転, #335 + 0x8F09, // 載, #342 + 0x8FBC, // 込, #229 + 0x8FD1, // 近, #304 + 0x8FD4, // 返, #461 + 0x8FFD, // 追, #379 + 0x9001, // 送, #186 + 0x901A, // 通, #182 + 0x901F, // 速, #340 + 0x9023, // 連, #244 + 0x904B, // 運, #382 + 0x904E, // 過, #498 + 0x9053, // 道, #282 + 0x9054, // 達, #450 + 0x9055, // 違, #414 + 0x9078, // 選, #288 + 0x90E8, // 部, #208 + 0x90FD, // 都, #344 + 0x914D, // 配, #389 + 0x91CD, // 重, #478 + 0x91CE, // 野, #245 + 0x91D1, // 金, #138 + 0x9332, // 録, #238 + 0x9577, // 長, #247 + 0x9580, // 門, #508 + 0x958B, // 開, #248 + 0x9593, // 間, #141 + 0x95A2, // 関, #188 + 0x962A, // 阪, #496 + 0x9650, // 限, #395 + 0x9662, // 院, #449 + 0x9664, // 除, #510 + 0x969B, // 際, #493 + 0x96C6, // 集, #196 + 0x96D1, // 雑, #442 + 0x96FB, // 電, #187 + 0x9762, // 面, #328 + 0x97F3, // 音, #325 + 0x984C, // 題, #310 + 0x985E, // 類, #491 + 0x98A8, // 風, #353 + 0x98DF, // 食, #218 + 0x9928, // 館, #464 + 0x99C5, // 駅, #316 + 0x9A13, // 験, #397 + 0x9AD8, // 高, #176 + 0xFF57, // w, #108 +}; +// the percentage of the sample covered by the above characters +static const float frequent_ja_coverage=0.880569589120162; + +// The 512 most frequently occuring characters for the ko language in a sample of the Internet. +// Ordered by codepoint, comment shows character and ranking by frequency +const uint16_t frequent_ko[] = { + 0x314B, // ㅋ, #148 + 0x314E, // ㅎ, #390 + 0x3160, // ㅠ, #354 + 0x318D, // ㆍ, #439 + 0xAC00, // 가, #6 + 0xAC01, // 각, #231 + 0xAC04, // 간, #106 + 0xAC08, // 갈, #362 + 0xAC10, // 감, #122 + 0xAC11, // 갑, #493 + 0xAC15, // 강, #155 + 0xAC19, // 같, #264 + 0xAC1C, // 개, #87 + 0xAC1D, // 객, #198 + 0xAC24, // 갤, #457 + 0xAC70, // 거, #91 + 0xAC74, // 건, #161 + 0xAC78, // 걸, #338 + 0xAC80, // 검, #184 + 0xAC83, // 것, #116 + 0xAC8C, // 게, #36 + 0xACA0, // 겠, #233 + 0xACA8, // 겨, #341 + 0xACA9, // 격, #245 + 0xACAC, // 견, #413 + 0xACB0, // 결, #202 + 0xACBD, // 경, #62 + 0xACC4, // 계, #142 + 0xACE0, // 고, #12 + 0xACE1, // 곡, #444 + 0xACE8, // 골, #379 + 0xACF3, // 곳, #388 + 0xACF5, // 공, #59 + 0xACFC, // 과, #69 + 0xAD00, // 관, #95 + 0xAD11, // 광, #235 + 0xAD50, // 교, #128 + 0xAD6C, // 구, #52 + 0xAD6D, // 국, #85 + 0xAD70, // 군, #293 + 0xAD74, // 굴, #487 + 0xAD81, // 궁, #441 + 0xAD8C, // 권, #192 + 0xADC0, // 귀, #386 + 0xADDC, // 규, #367 + 0xADF8, // 그, #30 + 0xADF9, // 극, #424 + 0xADFC, // 근, #241 + 0xAE00, // 글, #61 + 0xAE08, // 금, #138 + 0xAE09, // 급, #269 + 0xAE30, // 기, #3 + 0xAE34, // 긴, #465 + 0xAE38, // 길, #297 + 0xAE40, // 김, #205 + 0xAE4C, // 까, #171 + 0xAED8, // 께, #273 + 0xAF43, // 꽃, #475 + 0xB05D, // 끝, #505 + 0xB07C, // 끼, #490 + 0xB098, // 나, #39 + 0xB09C, // 난, #274 + 0xB0A0, // 날, #292 + 0xB0A8, // 남, #139 + 0xB0B4, // 내, #56 + 0xB108, // 너, #272 + 0xB110, // 널, #476 + 0xB118, // 넘, #492 + 0xB124, // 네, #100 + 0xB137, // 넷, #329 + 0xB140, // 녀, #288 + 0xB144, // 년, #151 + 0xB178, // 노, #149 + 0xB17C, // 논, #491 + 0xB180, // 놀, #464 + 0xB18D, // 농, #442 + 0xB204, // 누, #319 + 0xB208, // 눈, #383 + 0xB274, // 뉴, #173 + 0xB290, // 느, #368 + 0xB294, // 는, #5 + 0xB298, // 늘, #322 + 0xB2A5, // 능, #190 + 0xB2C8, // 니, #16 + 0xB2D8, // 님, #153 + 0xB2E4, // 다, #2 + 0xB2E8, // 단, #134 + 0xB2EB, // 닫, #195 + 0xB2EC, // 달, #243 + 0xB2F4, // 담, #254 + 0xB2F5, // 답, #287 + 0xB2F9, // 당, #159 + 0xB300, // 대, #33 + 0xB313, // 댓, #303 + 0xB354, // 더, #140 + 0xB358, // 던, #252 + 0xB367, // 덧, #463 + 0xB370, // 데, #104 + 0xB378, // 델, #429 + 0xB3C4, // 도, #25 + 0xB3C5, // 독, #301 + 0xB3CC, // 돌, #309 + 0xB3D9, // 동, #58 + 0xB418, // 되, #82 + 0xB41C, // 된, #189 + 0xB420, // 될, #408 + 0xB429, // 됩, #332 + 0xB450, // 두, #199 + 0xB4A4, // 뒤, #496 + 0xB4DC, // 드, #40 + 0xB4E0, // 든, #283 + 0xB4E4, // 들, #54 + 0xB4EF, // 듯, #478 + 0xB4F1, // 등, #90 + 0xB514, // 디, #133 + 0xB529, // 딩, #462 + 0xB530, // 따, #333 + 0xB54C, // 때, #240 + 0xB610, // 또, #313 + 0xB77C, // 라, #42 + 0xB77D, // 락, #355 + 0xB780, // 란, #290 + 0xB78C, // 람, #246 + 0xB78D, // 랍, #420 + 0xB791, // 랑, #270 + 0xB798, // 래, #174 + 0xB799, // 랙, #381 + 0xB79C, // 랜, #357 + 0xB7A8, // 램, #359 + 0xB7A9, // 랩, #402 + 0xB7C9, // 량, #346 + 0xB7EC, // 러, #130 + 0xB7F0, // 런, #312 + 0xB7FC, // 럼, #327 + 0xB7FD, // 럽, #447 + 0xB807, // 렇, #412 + 0xB808, // 레, #114 + 0xB80C, // 렌, #395 + 0xB824, // 려, #158 + 0xB825, // 력, #194 + 0xB828, // 련, #326 + 0xB839, // 령, #389 + 0xB85C, // 로, #4 + 0xB85D, // 록, #84 + 0xB860, // 론, #366 + 0xB8CC, // 료, #154 + 0xB8E8, // 루, #236 + 0xB958, // 류, #265 + 0xB974, // 르, #212 + 0xB978, // 른, #250 + 0xB97C, // 를, #35 + 0xB984, // 름, #276 + 0xB9AC, // 리, #19 + 0xB9AD, // 릭, #394 + 0xB9B0, // 린, #259 + 0xB9B4, // 릴, #485 + 0xB9BC, // 림, #305 + 0xB9BD, // 립, #217 + 0xB9C1, // 링, #351 + 0xB9C8, // 마, #67 + 0xB9C9, // 막, #310 + 0xB9CC, // 만, #65 + 0xB9CE, // 많, #257 + 0xB9D0, // 말, #188 + 0xB9DB, // 맛, #397 + 0xB9DD, // 망, #370 + 0xB9DE, // 맞, #399 + 0xB9E4, // 매, #125 + 0xB9E8, // 맨, #422 + 0xBA38, // 머, #311 + 0xBA39, // 먹, #377 + 0xBA3C, // 먼, #469 + 0xBA54, // 메, #147 + 0xBA70, // 며, #191 + 0xBA74, // 면, #72 + 0xBA85, // 명, #131 + 0xBAA8, // 모, #73 + 0xBAA9, // 목, #157 + 0xBAB0, // 몰, #401 + 0xBAB8, // 몸, #437 + 0xBABB, // 못, #336 + 0xBB34, // 무, #80 + 0xBB38, // 문, #57 + 0xBB3C, // 물, #94 + 0xBBA4, // 뮤, #431 + 0xBBF8, // 미, #76 + 0xBBFC, // 민, #200 + 0xBC00, // 밀, #308 + 0xBC0F, // 및, #249 + 0xBC14, // 바, #89 + 0xBC15, // 박, #226 + 0xBC18, // 반, #175 + 0xBC1B, // 받, #248 + 0xBC1C, // 발, #164 + 0xBC29, // 방, #92 + 0xBC30, // 배, #162 + 0xBC31, // 백, #256 + 0xBC84, // 버, #111 + 0xBC88, // 번, #167 + 0xBC8C, // 벌, #423 + 0xBC94, // 범, #427 + 0xBC95, // 법, #207 + 0xBCA0, // 베, #281 + 0xBCA4, // 벤, #378 + 0xBCA8, // 벨, #387 + 0xBCC0, // 변, #253 + 0xBCC4, // 별, #262 + 0xBCD1, // 병, #340 + 0xBCF4, // 보, #20 + 0xBCF5, // 복, #204 + 0xBCF8, // 본, #182 + 0xBCFC, // 볼, #385 + 0xBD09, // 봉, #405 + 0xBD80, // 부, #46 + 0xBD81, // 북, #261 + 0xBD84, // 분, #105 + 0xBD88, // 불, #225 + 0xBDF0, // 뷰, #350 + 0xBE0C, // 브, #214 + 0xBE14, // 블, #99 + 0xBE44, // 비, #55 + 0xBE4C, // 빌, #510 + 0xBE60, // 빠, #398 + 0xC0AC, // 사, #14 + 0xC0AD, // 삭, #342 + 0xC0B0, // 산, #121 + 0xC0B4, // 살, #279 + 0xC0BC, // 삼, #348 + 0xC0C1, // 상, #41 + 0xC0C8, // 새, #282 + 0xC0C9, // 색, #181 + 0xC0DD, // 생, #109 + 0xC11C, // 서, #21 + 0xC11D, // 석, #234 + 0xC120, // 선, #107 + 0xC124, // 설, #170 + 0xC131, // 성, #50 + 0xC138, // 세, #60 + 0xC139, // 섹, #456 + 0xC13C, // 센, #267 + 0xC154, // 셔, #455 + 0xC158, // 션, #237 + 0xC15C, // 셜, #448 + 0xC168, // 셨, #421 + 0xC18C, // 소, #51 + 0xC18D, // 속, #219 + 0xC190, // 손, #323 + 0xC1A1, // 송, #203 + 0xC1C4, // 쇄, #501 + 0xC1FC, // 쇼, #364 + 0xC218, // 수, #27 + 0xC219, // 숙, #467 + 0xC21C, // 순, #258 + 0xC220, // 술, #302 + 0xC26C, // 쉬, #511 + 0xC288, // 슈, #384 + 0xC2A4, // 스, #11 + 0xC2AC, // 슬, #438 + 0xC2B4, // 슴, #504 + 0xC2B5, // 습, #77 + 0xC2B9, // 승, #299 + 0xC2DC, // 시, #13 + 0xC2DD, // 식, #137 + 0xC2E0, // 신, #47 + 0xC2E4, // 실, #132 + 0xC2EC, // 심, #196 + 0xC2ED, // 십, #482 + 0xC2F6, // 싶, #352 + 0xC2F8, // 싸, #419 + 0xC4F0, // 쓰, #278 + 0xC528, // 씨, #360 + 0xC544, // 아, #23 + 0xC545, // 악, #296 + 0xC548, // 안, #71 + 0xC54A, // 않, #209 + 0xC54C, // 알, #222 + 0xC554, // 암, #460 + 0xC558, // 았, #349 + 0xC559, // 앙, #473 + 0xC55E, // 앞, #434 + 0xC560, // 애, #271 + 0xC561, // 액, #415 + 0xC571, // 앱, #477 + 0xC57C, // 야, #124 + 0xC57D, // 약, #229 + 0xC591, // 양, #177 + 0xC5B4, // 어, #24 + 0xC5B5, // 억, #407 + 0xC5B8, // 언, #294 + 0xC5BC, // 얼, #356 + 0xC5C4, // 엄, #426 + 0xC5C5, // 업, #118 + 0xC5C6, // 없, #178 + 0xC5C8, // 었, #165 + 0xC5D0, // 에, #9 + 0xC5D4, // 엔, #375 + 0xC5D8, // 엘, #506 + 0xC5EC, // 여, #66 + 0xC5ED, // 역, #186 + 0xC5EE, // 엮, #488 + 0xC5F0, // 연, #96 + 0xC5F4, // 열, #266 + 0xC5FC, // 염, #449 + 0xC600, // 였, #374 + 0xC601, // 영, #83 + 0xC608, // 예, #168 + 0xC624, // 오, #75 + 0xC628, // 온, #300 + 0xC62C, // 올, #306 + 0xC640, // 와, #119 + 0xC644, // 완, #361 + 0xC654, // 왔, #489 + 0xC655, // 왕, #418 + 0xC678, // 외, #218 + 0xC694, // 요, #43 + 0xC695, // 욕, #479 + 0xC6A9, // 용, #48 + 0xC6B0, // 우, #64 + 0xC6B1, // 욱, #503 + 0xC6B4, // 운, #108 + 0xC6B8, // 울, #223 + 0xC6C0, // 움, #317 + 0xC6C3, // 웃, #404 + 0xC6CC, // 워, #280 + 0xC6D0, // 원, #45 + 0xC6D4, // 월, #150 + 0xC6E8, // 웨, #446 + 0xC6F9, // 웹, #500 + 0xC704, // 위, #78 + 0xC720, // 유, #81 + 0xC721, // 육, #321 + 0xC724, // 윤, #416 + 0xC73C, // 으, #49 + 0xC740, // 은, #31 + 0xC744, // 을, #17 + 0xC74C, // 음, #112 + 0xC751, // 응, #461 + 0xC758, // 의, #8 + 0xC774, // 이, #1 + 0xC775, // 익, #403 + 0xC778, // 인, #18 + 0xC77C, // 일, #28 + 0xC784, // 임, #160 + 0xC785, // 입, #93 + 0xC788, // 있, #44 + 0xC790, // 자, #22 + 0xC791, // 작, #88 + 0xC798, // 잘, #347 + 0xC7A1, // 잡, #372 + 0xC7A5, // 장, #53 + 0xC7AC, // 재, #120 + 0xC7C1, // 쟁, #483 + 0xC800, // 저, #98 + 0xC801, // 적, #97 + 0xC804, // 전, #34 + 0xC808, // 절, #320 + 0xC810, // 점, #201 + 0xC811, // 접, #331 + 0xC815, // 정, #26 + 0xC81C, // 제, #29 + 0xC838, // 져, #414 + 0xC870, // 조, #86 + 0xC871, // 족, #373 + 0xC874, // 존, #432 + 0xC880, // 좀, #470 + 0xC885, // 종, #208 + 0xC88B, // 좋, #239 + 0xC8E0, // 죠, #451 + 0xC8FC, // 주, #38 + 0xC8FD, // 죽, #471 + 0xC900, // 준, #286 + 0xC904, // 줄, #392 + 0xC911, // 중, #103 + 0xC988, // 즈, #255 + 0xC98C, // 즌, #507 + 0xC990, // 즐, #371 + 0xC99D, // 증, #260 + 0xC9C0, // 지, #10 + 0xC9C1, // 직, #216 + 0xC9C4, // 진, #79 + 0xC9C8, // 질, #238 + 0xC9D1, // 집, #206 + 0xC9DC, // 짜, #411 + 0xC9F8, // 째, #494 + 0xCABD, // 쪽, #435 + 0xCC28, // 차, #146 + 0xCC29, // 착, #443 + 0xCC2C, // 찬, #481 + 0xCC30, // 찰, #440 + 0xCC38, // 참, #343 + 0xCC3D, // 창, #304 + 0xCC3E, // 찾, #335 + 0xCC44, // 채, #284 + 0xCC45, // 책, #298 + 0xCC98, // 처, #242 + 0xCC9C, // 천, #143 + 0xCCA0, // 철, #380 + 0xCCA8, // 첨, #452 + 0xCCAB, // 첫, #484 + 0xCCAD, // 청, #197 + 0xCCB4, // 체, #126 + 0xCCD0, // 쳐, #472 + 0xCD08, // 초, #220 + 0xCD1D, // 총, #406 + 0xCD5C, // 최, #179 + 0xCD94, // 추, #136 + 0xCD95, // 축, #337 + 0xCD9C, // 출, #166 + 0xCDA9, // 충, #369 + 0xCDE8, // 취, #210 + 0xCE20, // 츠, #215 + 0xCE21, // 측, #468 + 0xCE35, // 층, #512 + 0xCE58, // 치, #102 + 0xCE5C, // 친, #325 + 0xCE68, // 침, #263 + 0xCE74, // 카, #115 + 0xCE7C, // 칼, #466 + 0xCE90, // 캐, #454 + 0xCEE4, // 커, #285 + 0xCEE8, // 컨, #328 + 0xCEF4, // 컴, #417 + 0xCF00, // 케, #339 + 0xCF13, // 켓, #509 + 0xCF1C, // 켜, #508 + 0xCF54, // 코, #193 + 0xCF58, // 콘, #391 + 0xCFE0, // 쿠, #393 + 0xD035, // 퀵, #453 + 0xD06C, // 크, #101 + 0xD070, // 큰, #495 + 0xD074, // 클, #289 + 0xD0A4, // 키, #230 + 0xD0C0, // 타, #127 + 0xD0C1, // 탁, #314 + 0xD0C4, // 탄, #450 + 0xD0C8, // 탈, #436 + 0xD0DC, // 태, #221 + 0xD0DD, // 택, #275 + 0xD130, // 터, #70 + 0xD14C, // 테, #213 + 0xD150, // 텐, #324 + 0xD154, // 텔, #430 + 0xD15C, // 템, #382 + 0xD1A0, // 토, #145 + 0xD1B5, // 통, #156 + 0xD22C, // 투, #227 + 0xD2B8, // 트, #37 + 0xD2B9, // 특, #247 + 0xD2F0, // 티, #187 + 0xD305, // 팅, #410 + 0xD30C, // 파, #141 + 0xD310, // 판, #163 + 0xD314, // 팔, #499 + 0xD328, // 패, #307 + 0xD32C, // 팬, #459 + 0xD338, // 팸, #433 + 0xD37C, // 퍼, #344 + 0xD398, // 페, #172 + 0xD3B8, // 편, #251 + 0xD3C9, // 평, #291 + 0xD3EC, // 포, #68 + 0xD3ED, // 폭, #445 + 0xD3F0, // 폰, #318 + 0xD45C, // 표, #232 + 0xD480, // 풀, #497 + 0xD488, // 품, #113 + 0xD48D, // 풍, #425 + 0xD504, // 프, #110 + 0xD508, // 픈, #498 + 0xD50C, // 플, #211 + 0xD53C, // 피, #169 + 0xD544, // 필, #295 + 0xD551, // 핑, #376 + 0xD558, // 하, #7 + 0xD559, // 학, #129 + 0xD55C, // 한, #15 + 0xD560, // 할, #144 + 0xD568, // 함, #152 + 0xD569, // 합, #123 + 0xD56D, // 항, #268 + 0xD574, // 해, #32 + 0xD588, // 했, #180 + 0xD589, // 행, #135 + 0xD5A5, // 향, #345 + 0xD5C8, // 허, #396 + 0xD5D8, // 험, #316 + 0xD5E4, // 헤, #474 + 0xD604, // 현, #185 + 0xD611, // 협, #315 + 0xD615, // 형, #244 + 0xD61C, // 혜, #428 + 0xD638, // 호, #117 + 0xD63C, // 혼, #358 + 0xD648, // 홈, #330 + 0xD64D, // 홍, #363 + 0xD654, // 화, #63 + 0xD655, // 확, #183 + 0xD658, // 환, #224 + 0xD65C, // 활, #277 + 0xD669, // 황, #353 + 0xD68C, // 회, #74 + 0xD68D, // 획, #458 + 0xD69F, // 횟, #409 + 0xD6A8, // 효, #400 + 0xD6C4, // 후, #176 + 0xD6C8, // 훈, #486 + 0xD734, // 휴, #365 + 0xD754, // 흔, #480 + 0xD76C, // 희, #334 + 0xD788, // 히, #228 + 0xD798, // 힘, #502 +}; +// the percentage of the sample covered by the above characters +static const float frequent_ko_coverage=0.948157021464184; + diff --git a/media/libmedia/MediaScannerClient.cpp b/media/libmedia/MediaScannerClient.cpp index 93a4a4c..1661f04 100644 --- a/media/libmedia/MediaScannerClient.cpp +++ b/media/libmedia/MediaScannerClient.cpp @@ -14,217 +14,57 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaScannerClient" +#include + #include +#include "CharacterEncodingDetector.h" #include "StringArray.h" -#include "autodetect.h" -#include "unicode/ucnv.h" -#include "unicode/ustring.h" - namespace android { MediaScannerClient::MediaScannerClient() - : mNames(NULL), - mValues(NULL), - mLocaleEncoding(kEncodingNone) + : mEncodingDetector(NULL) { } MediaScannerClient::~MediaScannerClient() { - delete mNames; - delete mValues; + delete mEncodingDetector; } void MediaScannerClient::setLocale(const char* locale) { - if (!locale) return; - - if (!strncmp(locale, "ja", 2)) - mLocaleEncoding = kEncodingShiftJIS; - else if (!strncmp(locale, "ko", 2)) - mLocaleEncoding = kEncodingEUCKR; - else if (!strncmp(locale, "zh", 2)) { - if (!strcmp(locale, "zh_CN")) { - // simplified chinese for mainland China - mLocaleEncoding = kEncodingGBK; - } else { - // assume traditional for non-mainland Chinese locales (Taiwan, Hong Kong, Singapore) - mLocaleEncoding = kEncodingBig5; - } - } + mLocale = locale; // not currently used } void MediaScannerClient::beginFile() { - mNames = new StringArray; - mValues = new StringArray; + delete mEncodingDetector; + mEncodingDetector = new CharacterEncodingDetector(); } status_t MediaScannerClient::addStringTag(const char* name, const char* value) { - if (mLocaleEncoding != kEncodingNone) { - // don't bother caching strings that are all ASCII. - // call handleStringTag directly instead. - // check to see if value (which should be utf8) has any non-ASCII characters - bool nonAscii = false; - const char* chp = value; - char ch; - while ((ch = *chp++)) { - if (ch & 0x80) { - nonAscii = true; - break; - } - } - - if (nonAscii) { - // save the strings for later so they can be used for native encoding detection - mNames->push_back(name); - mValues->push_back(value); - return OK; - } - // else fall through - } - - // autodetection is not necessary, so no need to cache the values - // pass directly to the client instead - return handleStringTag(name, value); -} - -static uint32_t possibleEncodings(const char* s) -{ - uint32_t result = kEncodingAll; - // if s contains a native encoding, then it was mistakenly encoded in utf8 as if it were latin-1 - // so we need to reverse the latin-1 -> utf8 conversion to get the native chars back - uint8_t ch1, ch2; - uint8_t* chp = (uint8_t *)s; - - while ((ch1 = *chp++)) { - if (ch1 & 0x80) { - ch2 = *chp++; - ch1 = ((ch1 << 6) & 0xC0) | (ch2 & 0x3F); - // ch1 is now the first byte of the potential native char - - ch2 = *chp++; - if (ch2 & 0x80) - ch2 = ((ch2 << 6) & 0xC0) | (*chp++ & 0x3F); - // ch2 is now the second byte of the potential native char - int ch = (int)ch1 << 8 | (int)ch2; - result &= findPossibleEncodings(ch); - } - // else ASCII character, which could be anything - } - - return result; -} - -void MediaScannerClient::convertValues(uint32_t encoding) -{ - const char* enc = NULL; - switch (encoding) { - case kEncodingShiftJIS: - enc = "shift-jis"; - break; - case kEncodingGBK: - enc = "gbk"; - break; - case kEncodingBig5: - enc = "Big5"; - break; - case kEncodingEUCKR: - enc = "EUC-KR"; - break; - } - - if (enc) { - UErrorCode status = U_ZERO_ERROR; - - UConverter *conv = ucnv_open(enc, &status); - if (U_FAILURE(status)) { - ALOGE("could not create UConverter for %s", enc); - return; - } - UConverter *utf8Conv = ucnv_open("UTF-8", &status); - if (U_FAILURE(status)) { - ALOGE("could not create UConverter for UTF-8"); - ucnv_close(conv); - return; - } - - // for each value string, convert from native encoding to UTF-8 - for (int i = 0; i < mNames->size(); i++) { - // first we need to untangle the utf8 and convert it back to the original bytes - // since we are reducing the length of the string, we can do this in place - uint8_t* src = (uint8_t *)mValues->getEntry(i); - int len = strlen((char *)src); - uint8_t* dest = src; - - uint8_t uch; - while ((uch = *src++)) { - if (uch & 0x80) - *dest++ = ((uch << 6) & 0xC0) | (*src++ & 0x3F); - else - *dest++ = uch; - } - *dest = 0; - - // now convert from native encoding to UTF-8 - const char* source = mValues->getEntry(i); - int targetLength = len * 3 + 1; - char* buffer = new char[targetLength]; - // don't normally check for NULL, but in this case targetLength may be large - if (!buffer) - break; - char* target = buffer; - - ucnv_convertEx(utf8Conv, conv, &target, target + targetLength, - &source, (const char *)dest, NULL, NULL, NULL, NULL, TRUE, TRUE, &status); - if (U_FAILURE(status)) { - ALOGE("ucnv_convertEx failed: %d", status); - mValues->setEntry(i, "???"); - } else { - // zero terminate - *target = 0; - mValues->setEntry(i, buffer); - } - - delete[] buffer; - } - - ucnv_close(conv); - ucnv_close(utf8Conv); - } + mEncodingDetector->addTag(name, value); + return OK; } void MediaScannerClient::endFile() { - if (mLocaleEncoding != kEncodingNone) { - int size = mNames->size(); - uint32_t encoding = kEncodingAll; - - // compute a bit mask containing all possible encodings - for (int i = 0; i < mNames->size(); i++) - encoding &= possibleEncodings(mValues->getEntry(i)); - - // if the locale encoding matches, then assume we have a native encoding. - if (encoding & mLocaleEncoding) - convertValues(mLocaleEncoding); - - // finally, push all name/value pairs to the client - for (int i = 0; i < mNames->size(); i++) { - status_t status = handleStringTag(mNames->getEntry(i), mValues->getEntry(i)); - if (status) { - break; - } + mEncodingDetector->detectAndConvert(); + + int size = mEncodingDetector->size(); + if (size) { + for (int i = 0; i < size; i++) { + const char *name; + const char *value; + mEncodingDetector->getTag(i, &name, &value); + handleStringTag(name, value); } } - // else addStringTag() has done all the work so we have nothing to do - - delete mNames; - delete mValues; - mNames = NULL; - mValues = NULL; } } // namespace android diff --git a/media/libmedia/autodetect.cpp b/media/libmedia/autodetect.cpp deleted file mode 100644 index be5c3b2..0000000 --- a/media/libmedia/autodetect.cpp +++ /dev/null @@ -1,885 +0,0 @@ -/* - * Copyright (C) 2008 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 "autodetect.h" - -struct CharRange { - uint16_t first; - uint16_t last; -}; - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) - -// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP932.TXT -static const CharRange kShiftJISRanges[] = { - { 0x8140, 0x817E }, - { 0x8180, 0x81AC }, - { 0x81B8, 0x81BF }, - { 0x81C8, 0x81CE }, - { 0x81DA, 0x81E8 }, - { 0x81F0, 0x81F7 }, - { 0x81FC, 0x81FC }, - { 0x824F, 0x8258 }, - { 0x8260, 0x8279 }, - { 0x8281, 0x829A }, - { 0x829F, 0x82F1 }, - { 0x8340, 0x837E }, - { 0x8380, 0x8396 }, - { 0x839F, 0x83B6 }, - { 0x83BF, 0x83D6 }, - { 0x8440, 0x8460 }, - { 0x8470, 0x847E }, - { 0x8480, 0x8491 }, - { 0x849F, 0x84BE }, - { 0x8740, 0x875D }, - { 0x875F, 0x8775 }, - { 0x877E, 0x877E }, - { 0x8780, 0x879C }, - { 0x889F, 0x88FC }, - { 0x8940, 0x897E }, - { 0x8980, 0x89FC }, - { 0x8A40, 0x8A7E }, - { 0x8A80, 0x8AFC }, - { 0x8B40, 0x8B7E }, - { 0x8B80, 0x8BFC }, - { 0x8C40, 0x8C7E }, - { 0x8C80, 0x8CFC }, - { 0x8D40, 0x8D7E }, - { 0x8D80, 0x8DFC }, - { 0x8E40, 0x8E7E }, - { 0x8E80, 0x8EFC }, - { 0x8F40, 0x8F7E }, - { 0x8F80, 0x8FFC }, - { 0x9040, 0x907E }, - { 0x9080, 0x90FC }, - { 0x9140, 0x917E }, - { 0x9180, 0x91FC }, - { 0x9240, 0x927E }, - { 0x9280, 0x92FC }, - { 0x9340, 0x937E }, - { 0x9380, 0x93FC }, - { 0x9440, 0x947E }, - { 0x9480, 0x94FC }, - { 0x9540, 0x957E }, - { 0x9580, 0x95FC }, - { 0x9640, 0x967E }, - { 0x9680, 0x96FC }, - { 0x9740, 0x977E }, - { 0x9780, 0x97FC }, - { 0x9840, 0x9872 }, - { 0x989F, 0x98FC }, - { 0x9940, 0x997E }, - { 0x9980, 0x99FC }, - { 0x9A40, 0x9A7E }, - { 0x9A80, 0x9AFC }, - { 0x9B40, 0x9B7E }, - { 0x9B80, 0x9BFC }, - { 0x9C40, 0x9C7E }, - { 0x9C80, 0x9CFC }, - { 0x9D40, 0x9D7E }, - { 0x9D80, 0x9DFC }, - { 0x9E40, 0x9E7E }, - { 0x9E80, 0x9EFC }, - { 0x9F40, 0x9F7E }, - { 0x9F80, 0x9FFC }, - { 0xE040, 0xE07E }, - { 0xE080, 0xE0FC }, - { 0xE140, 0xE17E }, - { 0xE180, 0xE1FC }, - { 0xE240, 0xE27E }, - { 0xE280, 0xE2FC }, - { 0xE340, 0xE37E }, - { 0xE380, 0xE3FC }, - { 0xE440, 0xE47E }, - { 0xE480, 0xE4FC }, - { 0xE540, 0xE57E }, - { 0xE580, 0xE5FC }, - { 0xE640, 0xE67E }, - { 0xE680, 0xE6FC }, - { 0xE740, 0xE77E }, - { 0xE780, 0xE7FC }, - { 0xE840, 0xE87E }, - { 0xE880, 0xE8FC }, - { 0xE940, 0xE97E }, - { 0xE980, 0xE9FC }, - { 0xEA40, 0xEA7E }, - { 0xEA80, 0xEAA4 }, - { 0xED40, 0xED7E }, - { 0xED80, 0xEDFC }, - { 0xEE40, 0xEE7E }, - { 0xEE80, 0xEEEC }, - { 0xEEEF, 0xEEFC }, - { 0xFA40, 0xFA7E }, - { 0xFA80, 0xFAFC }, - { 0xFB40, 0xFB7E }, - { 0xFB80, 0xFBFC }, - { 0xFC40, 0xFC4B }, -}; - -// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP936.TXT -static const CharRange kGBKRanges[] = { - { 0x8140, 0x817E }, - { 0x8180, 0x81FE }, - { 0x8240, 0x827E }, - { 0x8280, 0x82FE }, - { 0x8340, 0x837E }, - { 0x8380, 0x83FE }, - { 0x8440, 0x847E }, - { 0x8480, 0x84FE }, - { 0x8540, 0x857E }, - { 0x8580, 0x85FE }, - { 0x8640, 0x867E }, - { 0x8680, 0x86FE }, - { 0x8740, 0x877E }, - { 0x8780, 0x87FE }, - { 0x8840, 0x887E }, - { 0x8880, 0x88FE }, - { 0x8940, 0x897E }, - { 0x8980, 0x89FE }, - { 0x8A40, 0x8A7E }, - { 0x8A80, 0x8AFE }, - { 0x8B40, 0x8B7E }, - { 0x8B80, 0x8BFE }, - { 0x8C40, 0x8C7E }, - { 0x8C80, 0x8CFE }, - { 0x8D40, 0x8D7E }, - { 0x8D80, 0x8DFE }, - { 0x8E40, 0x8E7E }, - { 0x8E80, 0x8EFE }, - { 0x8F40, 0x8F7E }, - { 0x8F80, 0x8FFE }, - { 0x9040, 0x907E }, - { 0x9080, 0x90FE }, - { 0x9140, 0x917E }, - { 0x9180, 0x91FE }, - { 0x9240, 0x927E }, - { 0x9280, 0x92FE }, - { 0x9340, 0x937E }, - { 0x9380, 0x93FE }, - { 0x9440, 0x947E }, - { 0x9480, 0x94FE }, - { 0x9540, 0x957E }, - { 0x9580, 0x95FE }, - { 0x9640, 0x967E }, - { 0x9680, 0x96FE }, - { 0x9740, 0x977E }, - { 0x9780, 0x97FE }, - { 0x9840, 0x987E }, - { 0x9880, 0x98FE }, - { 0x9940, 0x997E }, - { 0x9980, 0x99FE }, - { 0x9A40, 0x9A7E }, - { 0x9A80, 0x9AFE }, - { 0x9B40, 0x9B7E }, - { 0x9B80, 0x9BFE }, - { 0x9C40, 0x9C7E }, - { 0x9C80, 0x9CFE }, - { 0x9D40, 0x9D7E }, - { 0x9D80, 0x9DFE }, - { 0x9E40, 0x9E7E }, - { 0x9E80, 0x9EFE }, - { 0x9F40, 0x9F7E }, - { 0x9F80, 0x9FFE }, - { 0xA040, 0xA07E }, - { 0xA080, 0xA0FE }, - { 0xA1A1, 0xA1FE }, - { 0xA2A1, 0xA2AA }, - { 0xA2B1, 0xA2E2 }, - { 0xA2E5, 0xA2EE }, - { 0xA2F1, 0xA2FC }, - { 0xA3A1, 0xA3FE }, - { 0xA4A1, 0xA4F3 }, - { 0xA5A1, 0xA5F6 }, - { 0xA6A1, 0xA6B8 }, - { 0xA6C1, 0xA6D8 }, - { 0xA6E0, 0xA6EB }, - { 0xA6EE, 0xA6F2 }, - { 0xA6F4, 0xA6F5 }, - { 0xA7A1, 0xA7C1 }, - { 0xA7D1, 0xA7F1 }, - { 0xA840, 0xA87E }, - { 0xA880, 0xA895 }, - { 0xA8A1, 0xA8BB }, - { 0xA8BD, 0xA8BE }, - { 0xA8C0, 0xA8C0 }, - { 0xA8C5, 0xA8E9 }, - { 0xA940, 0xA957 }, - { 0xA959, 0xA95A }, - { 0xA95C, 0xA95C }, - { 0xA960, 0xA97E }, - { 0xA980, 0xA988 }, - { 0xA996, 0xA996 }, - { 0xA9A4, 0xA9EF }, - { 0xAA40, 0xAA7E }, - { 0xAA80, 0xAAA0 }, - { 0xAB40, 0xAB7E }, - { 0xAB80, 0xABA0 }, - { 0xAC40, 0xAC7E }, - { 0xAC80, 0xACA0 }, - { 0xAD40, 0xAD7E }, - { 0xAD80, 0xADA0 }, - { 0xAE40, 0xAE7E }, - { 0xAE80, 0xAEA0 }, - { 0xAF40, 0xAF7E }, - { 0xAF80, 0xAFA0 }, - { 0xB040, 0xB07E }, - { 0xB080, 0xB0FE }, - { 0xB140, 0xB17E }, - { 0xB180, 0xB1FE }, - { 0xB240, 0xB27E }, - { 0xB280, 0xB2FE }, - { 0xB340, 0xB37E }, - { 0xB380, 0xB3FE }, - { 0xB440, 0xB47E }, - { 0xB480, 0xB4FE }, - { 0xB540, 0xB57E }, - { 0xB580, 0xB5FE }, - { 0xB640, 0xB67E }, - { 0xB680, 0xB6FE }, - { 0xB740, 0xB77E }, - { 0xB780, 0xB7FE }, - { 0xB840, 0xB87E }, - { 0xB880, 0xB8FE }, - { 0xB940, 0xB97E }, - { 0xB980, 0xB9FE }, - { 0xBA40, 0xBA7E }, - { 0xBA80, 0xBAFE }, - { 0xBB40, 0xBB7E }, - { 0xBB80, 0xBBFE }, - { 0xBC40, 0xBC7E }, - { 0xBC80, 0xBCFE }, - { 0xBD40, 0xBD7E }, - { 0xBD80, 0xBDFE }, - { 0xBE40, 0xBE7E }, - { 0xBE80, 0xBEFE }, - { 0xBF40, 0xBF7E }, - { 0xBF80, 0xBFFE }, - { 0xC040, 0xC07E }, - { 0xC080, 0xC0FE }, - { 0xC140, 0xC17E }, - { 0xC180, 0xC1FE }, - { 0xC240, 0xC27E }, - { 0xC280, 0xC2FE }, - { 0xC340, 0xC37E }, - { 0xC380, 0xC3FE }, - { 0xC440, 0xC47E }, - { 0xC480, 0xC4FE }, - { 0xC540, 0xC57E }, - { 0xC580, 0xC5FE }, - { 0xC640, 0xC67E }, - { 0xC680, 0xC6FE }, - { 0xC740, 0xC77E }, - { 0xC780, 0xC7FE }, - { 0xC840, 0xC87E }, - { 0xC880, 0xC8FE }, - { 0xC940, 0xC97E }, - { 0xC980, 0xC9FE }, - { 0xCA40, 0xCA7E }, - { 0xCA80, 0xCAFE }, - { 0xCB40, 0xCB7E }, - { 0xCB80, 0xCBFE }, - { 0xCC40, 0xCC7E }, - { 0xCC80, 0xCCFE }, - { 0xCD40, 0xCD7E }, - { 0xCD80, 0xCDFE }, - { 0xCE40, 0xCE7E }, - { 0xCE80, 0xCEFE }, - { 0xCF40, 0xCF7E }, - { 0xCF80, 0xCFFE }, - { 0xD040, 0xD07E }, - { 0xD080, 0xD0FE }, - { 0xD140, 0xD17E }, - { 0xD180, 0xD1FE }, - { 0xD240, 0xD27E }, - { 0xD280, 0xD2FE }, - { 0xD340, 0xD37E }, - { 0xD380, 0xD3FE }, - { 0xD440, 0xD47E }, - { 0xD480, 0xD4FE }, - { 0xD540, 0xD57E }, - { 0xD580, 0xD5FE }, - { 0xD640, 0xD67E }, - { 0xD680, 0xD6FE }, - { 0xD740, 0xD77E }, - { 0xD780, 0xD7F9 }, - { 0xD840, 0xD87E }, - { 0xD880, 0xD8FE }, - { 0xD940, 0xD97E }, - { 0xD980, 0xD9FE }, - { 0xDA40, 0xDA7E }, - { 0xDA80, 0xDAFE }, - { 0xDB40, 0xDB7E }, - { 0xDB80, 0xDBFE }, - { 0xDC40, 0xDC7E }, - { 0xDC80, 0xDCFE }, - { 0xDD40, 0xDD7E }, - { 0xDD80, 0xDDFE }, - { 0xDE40, 0xDE7E }, - { 0xDE80, 0xDEFE }, - { 0xDF40, 0xDF7E }, - { 0xDF80, 0xDFFE }, - { 0xE040, 0xE07E }, - { 0xE080, 0xE0FE }, - { 0xE140, 0xE17E }, - { 0xE180, 0xE1FE }, - { 0xE240, 0xE27E }, - { 0xE280, 0xE2FE }, - { 0xE340, 0xE37E }, - { 0xE380, 0xE3FE }, - { 0xE440, 0xE47E }, - { 0xE480, 0xE4FE }, - { 0xE540, 0xE57E }, - { 0xE580, 0xE5FE }, - { 0xE640, 0xE67E }, - { 0xE680, 0xE6FE }, - { 0xE740, 0xE77E }, - { 0xE780, 0xE7FE }, - { 0xE840, 0xE87E }, - { 0xE880, 0xE8FE }, - { 0xE940, 0xE97E }, - { 0xE980, 0xE9FE }, - { 0xEA40, 0xEA7E }, - { 0xEA80, 0xEAFE }, - { 0xEB40, 0xEB7E }, - { 0xEB80, 0xEBFE }, - { 0xEC40, 0xEC7E }, - { 0xEC80, 0xECFE }, - { 0xED40, 0xED7E }, - { 0xED80, 0xEDFE }, - { 0xEE40, 0xEE7E }, - { 0xEE80, 0xEEFE }, - { 0xEF40, 0xEF7E }, - { 0xEF80, 0xEFFE }, - { 0xF040, 0xF07E }, - { 0xF080, 0xF0FE }, - { 0xF140, 0xF17E }, - { 0xF180, 0xF1FE }, - { 0xF240, 0xF27E }, - { 0xF280, 0xF2FE }, - { 0xF340, 0xF37E }, - { 0xF380, 0xF3FE }, - { 0xF440, 0xF47E }, - { 0xF480, 0xF4FE }, - { 0xF540, 0xF57E }, - { 0xF580, 0xF5FE }, - { 0xF640, 0xF67E }, - { 0xF680, 0xF6FE }, - { 0xF740, 0xF77E }, - { 0xF780, 0xF7FE }, - { 0xF840, 0xF87E }, - { 0xF880, 0xF8A0 }, - { 0xF940, 0xF97E }, - { 0xF980, 0xF9A0 }, - { 0xFA40, 0xFA7E }, - { 0xFA80, 0xFAA0 }, - { 0xFB40, 0xFB7E }, - { 0xFB80, 0xFBA0 }, - { 0xFC40, 0xFC7E }, - { 0xFC80, 0xFCA0 }, - { 0xFD40, 0xFD7E }, - { 0xFD80, 0xFDA0 }, - { 0xFE40, 0xFE4F }, -}; - -// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP949.TXT -static const CharRange kEUCKRRanges[] = { - { 0x8141, 0x815A }, - { 0x8161, 0x817A }, - { 0x8181, 0x81FE }, - { 0x8241, 0x825A }, - { 0x8261, 0x827A }, - { 0x8281, 0x82FE }, - { 0x8341, 0x835A }, - { 0x8361, 0x837A }, - { 0x8381, 0x83FE }, - { 0x8441, 0x845A }, - { 0x8461, 0x847A }, - { 0x8481, 0x84FE }, - { 0x8541, 0x855A }, - { 0x8561, 0x857A }, - { 0x8581, 0x85FE }, - { 0x8641, 0x865A }, - { 0x8661, 0x867A }, - { 0x8681, 0x86FE }, - { 0x8741, 0x875A }, - { 0x8761, 0x877A }, - { 0x8781, 0x87FE }, - { 0x8841, 0x885A }, - { 0x8861, 0x887A }, - { 0x8881, 0x88FE }, - { 0x8941, 0x895A }, - { 0x8961, 0x897A }, - { 0x8981, 0x89FE }, - { 0x8A41, 0x8A5A }, - { 0x8A61, 0x8A7A }, - { 0x8A81, 0x8AFE }, - { 0x8B41, 0x8B5A }, - { 0x8B61, 0x8B7A }, - { 0x8B81, 0x8BFE }, - { 0x8C41, 0x8C5A }, - { 0x8C61, 0x8C7A }, - { 0x8C81, 0x8CFE }, - { 0x8D41, 0x8D5A }, - { 0x8D61, 0x8D7A }, - { 0x8D81, 0x8DFE }, - { 0x8E41, 0x8E5A }, - { 0x8E61, 0x8E7A }, - { 0x8E81, 0x8EFE }, - { 0x8F41, 0x8F5A }, - { 0x8F61, 0x8F7A }, - { 0x8F81, 0x8FFE }, - { 0x9041, 0x905A }, - { 0x9061, 0x907A }, - { 0x9081, 0x90FE }, - { 0x9141, 0x915A }, - { 0x9161, 0x917A }, - { 0x9181, 0x91FE }, - { 0x9241, 0x925A }, - { 0x9261, 0x927A }, - { 0x9281, 0x92FE }, - { 0x9341, 0x935A }, - { 0x9361, 0x937A }, - { 0x9381, 0x93FE }, - { 0x9441, 0x945A }, - { 0x9461, 0x947A }, - { 0x9481, 0x94FE }, - { 0x9541, 0x955A }, - { 0x9561, 0x957A }, - { 0x9581, 0x95FE }, - { 0x9641, 0x965A }, - { 0x9661, 0x967A }, - { 0x9681, 0x96FE }, - { 0x9741, 0x975A }, - { 0x9761, 0x977A }, - { 0x9781, 0x97FE }, - { 0x9841, 0x985A }, - { 0x9861, 0x987A }, - { 0x9881, 0x98FE }, - { 0x9941, 0x995A }, - { 0x9961, 0x997A }, - { 0x9981, 0x99FE }, - { 0x9A41, 0x9A5A }, - { 0x9A61, 0x9A7A }, - { 0x9A81, 0x9AFE }, - { 0x9B41, 0x9B5A }, - { 0x9B61, 0x9B7A }, - { 0x9B81, 0x9BFE }, - { 0x9C41, 0x9C5A }, - { 0x9C61, 0x9C7A }, - { 0x9C81, 0x9CFE }, - { 0x9D41, 0x9D5A }, - { 0x9D61, 0x9D7A }, - { 0x9D81, 0x9DFE }, - { 0x9E41, 0x9E5A }, - { 0x9E61, 0x9E7A }, - { 0x9E81, 0x9EFE }, - { 0x9F41, 0x9F5A }, - { 0x9F61, 0x9F7A }, - { 0x9F81, 0x9FFE }, - { 0xA041, 0xA05A }, - { 0xA061, 0xA07A }, - { 0xA081, 0xA0FE }, - { 0xA141, 0xA15A }, - { 0xA161, 0xA17A }, - { 0xA181, 0xA1FE }, - { 0xA241, 0xA25A }, - { 0xA261, 0xA27A }, - { 0xA281, 0xA2E7 }, - { 0xA341, 0xA35A }, - { 0xA361, 0xA37A }, - { 0xA381, 0xA3FE }, - { 0xA441, 0xA45A }, - { 0xA461, 0xA47A }, - { 0xA481, 0xA4FE }, - { 0xA541, 0xA55A }, - { 0xA561, 0xA57A }, - { 0xA581, 0xA5AA }, - { 0xA5B0, 0xA5B9 }, - { 0xA5C1, 0xA5D8 }, - { 0xA5E1, 0xA5F8 }, - { 0xA641, 0xA65A }, - { 0xA661, 0xA67A }, - { 0xA681, 0xA6E4 }, - { 0xA741, 0xA75A }, - { 0xA761, 0xA77A }, - { 0xA781, 0xA7EF }, - { 0xA841, 0xA85A }, - { 0xA861, 0xA87A }, - { 0xA881, 0xA8A4 }, - { 0xA8A6, 0xA8A6 }, - { 0xA8A8, 0xA8AF }, - { 0xA8B1, 0xA8FE }, - { 0xA941, 0xA95A }, - { 0xA961, 0xA97A }, - { 0xA981, 0xA9FE }, - { 0xAA41, 0xAA5A }, - { 0xAA61, 0xAA7A }, - { 0xAA81, 0xAAF3 }, - { 0xAB41, 0xAB5A }, - { 0xAB61, 0xAB7A }, - { 0xAB81, 0xABF6 }, - { 0xAC41, 0xAC5A }, - { 0xAC61, 0xAC7A }, - { 0xAC81, 0xACC1 }, - { 0xACD1, 0xACF1 }, - { 0xAD41, 0xAD5A }, - { 0xAD61, 0xAD7A }, - { 0xAD81, 0xADA0 }, - { 0xAE41, 0xAE5A }, - { 0xAE61, 0xAE7A }, - { 0xAE81, 0xAEA0 }, - { 0xAF41, 0xAF5A }, - { 0xAF61, 0xAF7A }, - { 0xAF81, 0xAFA0 }, - { 0xB041, 0xB05A }, - { 0xB061, 0xB07A }, - { 0xB081, 0xB0FE }, - { 0xB141, 0xB15A }, - { 0xB161, 0xB17A }, - { 0xB181, 0xB1FE }, - { 0xB241, 0xB25A }, - { 0xB261, 0xB27A }, - { 0xB281, 0xB2FE }, - { 0xB341, 0xB35A }, - { 0xB361, 0xB37A }, - { 0xB381, 0xB3FE }, - { 0xB441, 0xB45A }, - { 0xB461, 0xB47A }, - { 0xB481, 0xB4FE }, - { 0xB541, 0xB55A }, - { 0xB561, 0xB57A }, - { 0xB581, 0xB5FE }, - { 0xB641, 0xB65A }, - { 0xB661, 0xB67A }, - { 0xB681, 0xB6FE }, - { 0xB741, 0xB75A }, - { 0xB761, 0xB77A }, - { 0xB781, 0xB7FE }, - { 0xB841, 0xB85A }, - { 0xB861, 0xB87A }, - { 0xB881, 0xB8FE }, - { 0xB941, 0xB95A }, - { 0xB961, 0xB97A }, - { 0xB981, 0xB9FE }, - { 0xBA41, 0xBA5A }, - { 0xBA61, 0xBA7A }, - { 0xBA81, 0xBAFE }, - { 0xBB41, 0xBB5A }, - { 0xBB61, 0xBB7A }, - { 0xBB81, 0xBBFE }, - { 0xBC41, 0xBC5A }, - { 0xBC61, 0xBC7A }, - { 0xBC81, 0xBCFE }, - { 0xBD41, 0xBD5A }, - { 0xBD61, 0xBD7A }, - { 0xBD81, 0xBDFE }, - { 0xBE41, 0xBE5A }, - { 0xBE61, 0xBE7A }, - { 0xBE81, 0xBEFE }, - { 0xBF41, 0xBF5A }, - { 0xBF61, 0xBF7A }, - { 0xBF81, 0xBFFE }, - { 0xC041, 0xC05A }, - { 0xC061, 0xC07A }, - { 0xC081, 0xC0FE }, - { 0xC141, 0xC15A }, - { 0xC161, 0xC17A }, - { 0xC181, 0xC1FE }, - { 0xC241, 0xC25A }, - { 0xC261, 0xC27A }, - { 0xC281, 0xC2FE }, - { 0xC341, 0xC35A }, - { 0xC361, 0xC37A }, - { 0xC381, 0xC3FE }, - { 0xC441, 0xC45A }, - { 0xC461, 0xC47A }, - { 0xC481, 0xC4FE }, - { 0xC541, 0xC55A }, - { 0xC561, 0xC57A }, - { 0xC581, 0xC5FE }, - { 0xC641, 0xC652 }, - { 0xC6A1, 0xC6FE }, - { 0xC7A1, 0xC7FE }, - { 0xC8A1, 0xC8FE }, - { 0xCAA1, 0xCAFE }, - { 0xCBA1, 0xCBFE }, - { 0xCCA1, 0xCCFE }, - { 0xCDA1, 0xCDFE }, - { 0xCEA1, 0xCEFE }, - { 0xCFA1, 0xCFFE }, - { 0xD0A1, 0xD0FE }, - { 0xD1A1, 0xD1FE }, - { 0xD2A1, 0xD2FE }, - { 0xD3A1, 0xD3FE }, - { 0xD4A1, 0xD4FE }, - { 0xD5A1, 0xD5FE }, - { 0xD6A1, 0xD6FE }, - { 0xD7A1, 0xD7FE }, - { 0xD8A1, 0xD8FE }, - { 0xD9A1, 0xD9FE }, - { 0xDAA1, 0xDAFE }, - { 0xDBA1, 0xDBFE }, - { 0xDCA1, 0xDCFE }, - { 0xDDA1, 0xDDFE }, - { 0xDEA1, 0xDEFE }, - { 0xDFA1, 0xDFFE }, - { 0xE0A1, 0xE0FE }, - { 0xE1A1, 0xE1FE }, - { 0xE2A1, 0xE2FE }, - { 0xE3A1, 0xE3FE }, - { 0xE4A1, 0xE4FE }, - { 0xE5A1, 0xE5FE }, - { 0xE6A1, 0xE6FE }, - { 0xE7A1, 0xE7FE }, - { 0xE8A1, 0xE8FE }, - { 0xE9A1, 0xE9FE }, - { 0xEAA1, 0xEAFE }, - { 0xEBA1, 0xEBFE }, - { 0xECA1, 0xECFE }, - { 0xEDA1, 0xEDFE }, - { 0xEEA1, 0xEEFE }, - { 0xEFA1, 0xEFFE }, - { 0xF0A1, 0xF0FE }, - { 0xF1A1, 0xF1FE }, - { 0xF2A1, 0xF2FE }, - { 0xF3A1, 0xF3FE }, - { 0xF4A1, 0xF4FE }, - { 0xF5A1, 0xF5FE }, - { 0xF6A1, 0xF6FE }, - { 0xF7A1, 0xF7FE }, - { 0xF8A1, 0xF8FE }, - { 0xF9A1, 0xF9FE }, - { 0xFAA1, 0xFAFE }, - { 0xFBA1, 0xFBFE }, - { 0xFCA1, 0xFCFE }, - { 0xFDA1, 0xFDFE }, -}; - -// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP950.TXT -static const CharRange kBig5Ranges[] = { - { 0xA140, 0xA17E }, - { 0xA1A1, 0xA1FE }, - { 0xA240, 0xA27E }, - { 0xA2A1, 0xA2FE }, - { 0xA340, 0xA37E }, - { 0xA3A1, 0xA3BF }, - { 0xA3E1, 0xA3E1 }, - { 0xA440, 0xA47E }, - { 0xA4A1, 0xA4FE }, - { 0xA540, 0xA57E }, - { 0xA5A1, 0xA5FE }, - { 0xA640, 0xA67E }, - { 0xA6A1, 0xA6FE }, - { 0xA740, 0xA77E }, - { 0xA7A1, 0xA7FE }, - { 0xA840, 0xA87E }, - { 0xA8A1, 0xA8FE }, - { 0xA940, 0xA97E }, - { 0xA9A1, 0xA9FE }, - { 0xAA40, 0xAA7E }, - { 0xAAA1, 0xAAFE }, - { 0xAB40, 0xAB7E }, - { 0xABA1, 0xABFE }, - { 0xAC40, 0xAC7E }, - { 0xACA1, 0xACFE }, - { 0xAD40, 0xAD7E }, - { 0xADA1, 0xADFE }, - { 0xAE40, 0xAE7E }, - { 0xAEA1, 0xAEFE }, - { 0xAF40, 0xAF7E }, - { 0xAFA1, 0xAFFE }, - { 0xB040, 0xB07E }, - { 0xB0A1, 0xB0FE }, - { 0xB140, 0xB17E }, - { 0xB1A1, 0xB1FE }, - { 0xB240, 0xB27E }, - { 0xB2A1, 0xB2FE }, - { 0xB340, 0xB37E }, - { 0xB3A1, 0xB3FE }, - { 0xB440, 0xB47E }, - { 0xB4A1, 0xB4FE }, - { 0xB540, 0xB57E }, - { 0xB5A1, 0xB5FE }, - { 0xB640, 0xB67E }, - { 0xB6A1, 0xB6FE }, - { 0xB740, 0xB77E }, - { 0xB7A1, 0xB7FE }, - { 0xB840, 0xB87E }, - { 0xB8A1, 0xB8FE }, - { 0xB940, 0xB97E }, - { 0xB9A1, 0xB9FE }, - { 0xBA40, 0xBA7E }, - { 0xBAA1, 0xBAFE }, - { 0xBB40, 0xBB7E }, - { 0xBBA1, 0xBBFE }, - { 0xBC40, 0xBC7E }, - { 0xBCA1, 0xBCFE }, - { 0xBD40, 0xBD7E }, - { 0xBDA1, 0xBDFE }, - { 0xBE40, 0xBE7E }, - { 0xBEA1, 0xBEFE }, - { 0xBF40, 0xBF7E }, - { 0xBFA1, 0xBFFE }, - { 0xC040, 0xC07E }, - { 0xC0A1, 0xC0FE }, - { 0xC140, 0xC17E }, - { 0xC1A1, 0xC1FE }, - { 0xC240, 0xC27E }, - { 0xC2A1, 0xC2FE }, - { 0xC340, 0xC37E }, - { 0xC3A1, 0xC3FE }, - { 0xC440, 0xC47E }, - { 0xC4A1, 0xC4FE }, - { 0xC540, 0xC57E }, - { 0xC5A1, 0xC5FE }, - { 0xC640, 0xC67E }, - { 0xC940, 0xC97E }, - { 0xC9A1, 0xC9FE }, - { 0xCA40, 0xCA7E }, - { 0xCAA1, 0xCAFE }, - { 0xCB40, 0xCB7E }, - { 0xCBA1, 0xCBFE }, - { 0xCC40, 0xCC7E }, - { 0xCCA1, 0xCCFE }, - { 0xCD40, 0xCD7E }, - { 0xCDA1, 0xCDFE }, - { 0xCE40, 0xCE7E }, - { 0xCEA1, 0xCEFE }, - { 0xCF40, 0xCF7E }, - { 0xCFA1, 0xCFFE }, - { 0xD040, 0xD07E }, - { 0xD0A1, 0xD0FE }, - { 0xD140, 0xD17E }, - { 0xD1A1, 0xD1FE }, - { 0xD240, 0xD27E }, - { 0xD2A1, 0xD2FE }, - { 0xD340, 0xD37E }, - { 0xD3A1, 0xD3FE }, - { 0xD440, 0xD47E }, - { 0xD4A1, 0xD4FE }, - { 0xD540, 0xD57E }, - { 0xD5A1, 0xD5FE }, - { 0xD640, 0xD67E }, - { 0xD6A1, 0xD6FE }, - { 0xD740, 0xD77E }, - { 0xD7A1, 0xD7FE }, - { 0xD840, 0xD87E }, - { 0xD8A1, 0xD8FE }, - { 0xD940, 0xD97E }, - { 0xD9A1, 0xD9FE }, - { 0xDA40, 0xDA7E }, - { 0xDAA1, 0xDAFE }, - { 0xDB40, 0xDB7E }, - { 0xDBA1, 0xDBFE }, - { 0xDC40, 0xDC7E }, - { 0xDCA1, 0xDCFE }, - { 0xDD40, 0xDD7E }, - { 0xDDA1, 0xDDFE }, - { 0xDE40, 0xDE7E }, - { 0xDEA1, 0xDEFE }, - { 0xDF40, 0xDF7E }, - { 0xDFA1, 0xDFFE }, - { 0xE040, 0xE07E }, - { 0xE0A1, 0xE0FE }, - { 0xE140, 0xE17E }, - { 0xE1A1, 0xE1FE }, - { 0xE240, 0xE27E }, - { 0xE2A1, 0xE2FE }, - { 0xE340, 0xE37E }, - { 0xE3A1, 0xE3FE }, - { 0xE440, 0xE47E }, - { 0xE4A1, 0xE4FE }, - { 0xE540, 0xE57E }, - { 0xE5A1, 0xE5FE }, - { 0xE640, 0xE67E }, - { 0xE6A1, 0xE6FE }, - { 0xE740, 0xE77E }, - { 0xE7A1, 0xE7FE }, - { 0xE840, 0xE87E }, - { 0xE8A1, 0xE8FE }, - { 0xE940, 0xE97E }, - { 0xE9A1, 0xE9FE }, - { 0xEA40, 0xEA7E }, - { 0xEAA1, 0xEAFE }, - { 0xEB40, 0xEB7E }, - { 0xEBA1, 0xEBFE }, - { 0xEC40, 0xEC7E }, - { 0xECA1, 0xECFE }, - { 0xED40, 0xED7E }, - { 0xEDA1, 0xEDFE }, - { 0xEE40, 0xEE7E }, - { 0xEEA1, 0xEEFE }, - { 0xEF40, 0xEF7E }, - { 0xEFA1, 0xEFFE }, - { 0xF040, 0xF07E }, - { 0xF0A1, 0xF0FE }, - { 0xF140, 0xF17E }, - { 0xF1A1, 0xF1FE }, - { 0xF240, 0xF27E }, - { 0xF2A1, 0xF2FE }, - { 0xF340, 0xF37E }, - { 0xF3A1, 0xF3FE }, - { 0xF440, 0xF47E }, - { 0xF4A1, 0xF4FE }, - { 0xF540, 0xF57E }, - { 0xF5A1, 0xF5FE }, - { 0xF640, 0xF67E }, - { 0xF6A1, 0xF6FE }, - { 0xF740, 0xF77E }, - { 0xF7A1, 0xF7FE }, - { 0xF840, 0xF87E }, - { 0xF8A1, 0xF8FE }, - { 0xF940, 0xF97E }, - { 0xF9A1, 0xF9FE }, -}; - -static bool charMatchesEncoding(int ch, const CharRange* encodingRanges, int rangeCount) { - // Use binary search to see if the character is contained in the encoding - int low = 0; - int high = rangeCount; - - while (low < high) { - int i = (low + high) / 2; - const CharRange* range = &encodingRanges[i]; - if (ch >= range->first && ch <= range->last) - return true; - if (ch > range->last) - low = i + 1; - else - high = i; - } - - return false; -} - -extern uint32_t findPossibleEncodings(int ch) -{ - // ASCII matches everything - if (ch < 256) return kEncodingAll; - - int result = kEncodingNone; - - if (charMatchesEncoding(ch, kShiftJISRanges, ARRAY_SIZE(kShiftJISRanges))) - result |= kEncodingShiftJIS; - if (charMatchesEncoding(ch, kGBKRanges, ARRAY_SIZE(kGBKRanges))) - result |= kEncodingGBK; - if (charMatchesEncoding(ch, kBig5Ranges, ARRAY_SIZE(kBig5Ranges))) - result |= kEncodingBig5; - if (charMatchesEncoding(ch, kEUCKRRanges, ARRAY_SIZE(kEUCKRRanges))) - result |= kEncodingEUCKR; - - return result; -} diff --git a/media/libmedia/autodetect.h b/media/libmedia/autodetect.h deleted file mode 100644 index 9675db3..0000000 --- a/media/libmedia/autodetect.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2008 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 AUTODETECT_H -#define AUTODETECT_H - -#include - -// flags used for native encoding detection -enum { - kEncodingNone = 0, - kEncodingShiftJIS = (1 << 0), - kEncodingGBK = (1 << 1), - kEncodingBig5 = (1 << 2), - kEncodingEUCKR = (1 << 3), - - kEncodingAll = (kEncodingShiftJIS | kEncodingGBK | kEncodingBig5 | kEncodingEUCKR), -}; - - -// returns a bitfield containing the possible native encodings for the given character -extern uint32_t findPossibleEncodings(int ch); - -#endif // AUTODETECT_H diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp index 34d671a..a486522 100644 --- a/media/libstagefright/id3/ID3.cpp +++ b/media/libstagefright/id3/ID3.cpp @@ -468,49 +468,6 @@ void ID3::Iterator::getID(String8 *id) const { } } -static void convertISO8859ToString8( - const uint8_t *data, size_t size, - String8 *s) { - size_t utf8len = 0; - for (size_t i = 0; i < size; ++i) { - if (data[i] == '\0') { - size = i; - break; - } else if (data[i] < 0x80) { - ++utf8len; - } else { - utf8len += 2; - } - } - - if (utf8len == size) { - // Only ASCII characters present. - - s->setTo((const char *)data, size); - return; - } - - char *tmp = new char[utf8len]; - char *ptr = tmp; - for (size_t i = 0; i < size; ++i) { - if (data[i] == '\0') { - break; - } else if (data[i] < 0x80) { - *ptr++ = data[i]; - } else if (data[i] < 0xc0) { - *ptr++ = 0xc2; - *ptr++ = data[i]; - } else { - *ptr++ = 0xc3; - *ptr++ = data[i] - 64; - } - } - - s->setTo(tmp, utf8len); - - delete[] tmp; - tmp = NULL; -} // the 2nd argument is used to get the data following the \0 in a comment field void ID3::Iterator::getString(String8 *id, String8 *comment) const { @@ -543,7 +500,9 @@ void ID3::Iterator::getstring(String8 *id, bool otherdata) const { return; } - convertISO8859ToString8(frameData, mFrameSize, id); + // this is supposed to be ISO-8859-1, but pass it up as-is to the caller, who will figure + // out the real encoding + id->setTo((const char*)frameData, mFrameSize); return; } @@ -561,13 +520,13 @@ void ID3::Iterator::getstring(String8 *id, bool otherdata) const { } if (encoding == 0x00) { - // ISO 8859-1 - convertISO8859ToString8(frameData + 1, n, id); + // supposedly ISO 8859-1 + id->setTo((const char*)frameData + 1, n); } else if (encoding == 0x03) { - // UTF-8 + // supposedly UTF-8 id->setTo((const char *)(frameData + 1), n); } else if (encoding == 0x02) { - // UTF-16 BE, no byte order mark. + // supposedly UTF-16 BE, no byte order mark. // API wants number of characters, not number of bytes... int len = n / 2; const char16_t *framedata = (const char16_t *) (frameData + 1); @@ -583,7 +542,7 @@ void ID3::Iterator::getstring(String8 *id, bool otherdata) const { if (framedatacopy != NULL) { delete[] framedatacopy; } - } else { + } else if (encoding == 0x01) { // UCS-2 // API wants number of characters, not number of bytes... int len = n / 2; @@ -602,7 +561,27 @@ void ID3::Iterator::getstring(String8 *id, bool otherdata) const { framedata++; len--; } - id->setTo(framedata, len); + + // check if the resulting data consists entirely of 8-bit values + bool eightBit = true; + for (int i = 0; i < len; i++) { + if (framedata[i] > 0xff) { + eightBit = false; + break; + } + } + if (eightBit) { + // collapse to 8 bit, then let the media scanner client figure out the real encoding + char *frame8 = new char[len]; + for (int i = 0; i < len; i++) { + frame8[i] = framedata[i]; + } + id->setTo(frame8, len); + delete [] frame8; + } else { + id->setTo(framedata, len); + } + if (framedatacopy != NULL) { delete[] framedatacopy; } -- cgit v1.1 From e175e5ec1636fc638465187f3d5c6166d92388ed Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 16 Dec 2013 10:16:32 -0800 Subject: stagefright: Fix bugs in playlist fetcher logic 1. Improve start time: start playback as soon as the target duration or 10s was buffered. 2. Select playlist monitor time based on target duration to avoid continuously missing the boat. 3. If "we miss the boat" we still must request a safe sequence number (last - 3) Change-Id: Ie99c360ac67b152ad9af19e9c6e520016f67e4e3 Signed-off-by: Lajos Molnar Bug: 12060952 --- media/libstagefright/httplive/PlaylistFetcher.cpp | 127 +++++++++++++++++----- media/libstagefright/httplive/PlaylistFetcher.h | 7 +- 2 files changed, 105 insertions(+), 29 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 973b779..1754bf2 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -47,6 +47,7 @@ namespace android { // static const int64_t PlaylistFetcher::kMinBufferedDurationUs = 10000000ll; +const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll; PlaylistFetcher::PlaylistFetcher( const sp ¬ify, @@ -61,6 +62,7 @@ PlaylistFetcher::PlaylistFetcher( mSeqNumber(-1), mNumRetries(0), mStartup(true), + mPrepared(false), mNextPTSTimeUs(-1ll), mMonitorQueueGeneration(0), mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY), @@ -103,10 +105,16 @@ int64_t PlaylistFetcher::getSegmentStartTimeUs(int32_t seqNumber) const { return segmentStartUs; } -bool PlaylistFetcher::timeToRefreshPlaylist(int64_t nowUs) const { - if (mPlaylist == NULL) { +int64_t PlaylistFetcher::delayUsToRefreshPlaylist() const { + int64_t nowUs = ALooper::GetNowUs(); + + if (mPlaylist == NULL || mLastPlaylistFetchTimeUs < 0ll) { CHECK_EQ((int)mRefreshState, (int)INITIAL_MINIMUM_RELOAD_DELAY); - return true; + return 0ll; + } + + if (mPlaylist->isComplete()) { + return (~0llu >> 1); } int32_t targetDurationSecs; @@ -157,7 +165,8 @@ bool PlaylistFetcher::timeToRefreshPlaylist(int64_t nowUs) const { break; } - return mLastPlaylistFetchTimeUs + minPlaylistAgeUs <= nowUs; + int64_t delayUs = mLastPlaylistFetchTimeUs + minPlaylistAgeUs - nowUs; + return delayUs > 0ll ? delayUs : 0ll; } status_t PlaylistFetcher::decryptBuffer( @@ -274,7 +283,15 @@ status_t PlaylistFetcher::decryptBuffer( return OK; } -void PlaylistFetcher::postMonitorQueue(int64_t delayUs) { +void PlaylistFetcher::postMonitorQueue(int64_t delayUs, int64_t minDelayUs) { + int64_t maxDelayUs = delayUsToRefreshPlaylist(); + if (maxDelayUs < minDelayUs) { + maxDelayUs = minDelayUs; + } + if (delayUs > maxDelayUs) { + ALOGV("Need to refresh playlist in %lld", maxDelayUs); + delayUs = maxDelayUs; + } sp msg = new AMessage(kWhatMonitorQueue, id()); msg->setInt32("generation", mMonitorQueueGeneration); msg->post(delayUs); @@ -415,6 +432,7 @@ status_t PlaylistFetcher::onStart(const sp &msg) { if (mStartTimeUs >= 0ll) { mSeqNumber = -1; mStartup = true; + mPrepared = false; } postMonitorQueue(); @@ -456,40 +474,62 @@ void PlaylistFetcher::queueDiscontinuity( void PlaylistFetcher::onMonitorQueue() { bool downloadMore = false; + refreshPlaylist(); + + int32_t targetDurationSecs; + int64_t targetDurationUs = kMinBufferedDurationUs; + if (mPlaylist != NULL) { + CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs)); + targetDurationUs = targetDurationSecs * 1000000ll; + } - status_t finalResult; + // buffer at least 3 times the target duration, or up to 10 seconds + int64_t durationToBufferUs = targetDurationUs * 3; + if (durationToBufferUs > kMinBufferedDurationUs) { + durationToBufferUs = kMinBufferedDurationUs; + } + + int64_t bufferedDurationUs = 0ll; + status_t finalResult = NOT_ENOUGH_DATA; if (mStreamTypeMask == LiveSession::STREAMTYPE_SUBTITLES) { sp packetSource = mPacketSources.valueFor(LiveSession::STREAMTYPE_SUBTITLES); - int64_t bufferedDurationUs = + bufferedDurationUs = packetSource->getBufferedDurationUs(&finalResult); - - downloadMore = (bufferedDurationUs < kMinBufferedDurationUs); finalResult = OK; } else { bool first = true; - int64_t minBufferedDurationUs = 0ll; for (size_t i = 0; i < mPacketSources.size(); ++i) { if ((mStreamTypeMask & mPacketSources.keyAt(i)) == 0) { continue; } - int64_t bufferedDurationUs = + int64_t bufferedStreamDurationUs = mPacketSources.valueAt(i)->getBufferedDurationUs(&finalResult); - - if (first || bufferedDurationUs < minBufferedDurationUs) { - minBufferedDurationUs = bufferedDurationUs; + if (first || bufferedStreamDurationUs < bufferedDurationUs) { + bufferedDurationUs = bufferedStreamDurationUs; first = false; } } + } + downloadMore = (bufferedDurationUs < durationToBufferUs); + + // signal start if buffered up at least the target size + if (!mPrepared && bufferedDurationUs > targetDurationUs && downloadMore) { + mPrepared = true; - downloadMore = - !first && (minBufferedDurationUs < kMinBufferedDurationUs); + ALOGV("prepared, buffered=%lld > %lld", + bufferedDurationUs, targetDurationUs); + sp msg = mNotify->dup(); + msg->setInt32("what", kWhatTemporarilyDoneFetching); + msg->post(); } if (finalResult == OK && downloadMore) { + ALOGV("monitoring, buffered=%lld < %lld", + bufferedDurationUs, durationToBufferUs); onDownloadNext(); } else { // Nothing to do yet, try again in a second. @@ -498,15 +538,17 @@ void PlaylistFetcher::onMonitorQueue() { msg->setInt32("what", kWhatTemporarilyDoneFetching); msg->post(); - postMonitorQueue(1000000ll); + int64_t delayUs = mPrepared ? kMaxMonitorDelayUs : targetDurationUs / 2; + ALOGV("pausing for %lld, buffered=%lld > %lld", + delayUs, bufferedDurationUs, durationToBufferUs); + // :TRICKY: need to enforce minimum delay because the delay to + // refresh the playlist will become 0 + postMonitorQueue(delayUs, mPrepared ? targetDurationUs * 2 : 0); } } -void PlaylistFetcher::onDownloadNext() { - int64_t nowUs = ALooper::GetNowUs(); - - if (mLastPlaylistFetchTimeUs < 0ll - || (!mPlaylist->isComplete() && timeToRefreshPlaylist(nowUs))) { +status_t PlaylistFetcher::refreshPlaylist() { + if (delayUsToRefreshPlaylist() <= 0) { bool unchanged; sp playlist = mSession->fetchPlaylist( mURI.c_str(), mPlaylistHash, &unchanged); @@ -522,7 +564,7 @@ void PlaylistFetcher::onDownloadNext() { } else { ALOGE("failed to load playlist at url '%s'", mURI.c_str()); notifyError(ERROR_IO); - return; + return ERROR_IO; } } else { mRefreshState = INITIAL_MINIMUM_RELOAD_DELAY; @@ -535,6 +577,13 @@ void PlaylistFetcher::onDownloadNext() { mLastPlaylistFetchTimeUs = ALooper::GetNowUs(); } + return OK; +} + +void PlaylistFetcher::onDownloadNext() { + if (refreshPlaylist() != OK) { + return; + } int32_t firstSeqNumberInPlaylist; if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32( @@ -553,12 +602,18 @@ void PlaylistFetcher::onDownloadNext() { if (mPlaylist->isComplete() || mPlaylist->isEvent()) { mSeqNumber = getSeqNumberForTime(mStartTimeUs); + ALOGV("Initial sequence number for time %lld is %ld from (%ld .. %ld)", + mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist, + lastSeqNumberInPlaylist); } else { // If this is a live session, start 3 segments from the end. mSeqNumber = lastSeqNumberInPlaylist - 3; if (mSeqNumber < firstSeqNumberInPlaylist) { mSeqNumber = firstSeqNumberInPlaylist; } + ALOGV("Initial sequence number for live event %ld from (%ld .. %ld)", + mSeqNumber, firstSeqNumberInPlaylist, + lastSeqNumberInPlaylist); } mStartTimeUs = -1ll; @@ -570,16 +625,34 @@ void PlaylistFetcher::onDownloadNext() { ++mNumRetries; if (mSeqNumber > lastSeqNumberInPlaylist) { - mLastPlaylistFetchTimeUs = -1; - postMonitorQueue(3000000ll); + // refresh in increasing fraction (1/2, 1/3, ...) of the + // playlist's target duration or 3 seconds, whichever is less + int32_t targetDurationSecs; + CHECK(mPlaylist->meta()->findInt32( + "target-duration", &targetDurationSecs)); + int64_t delayUs = mPlaylist->size() * targetDurationSecs * + 1000000ll / (1 + mNumRetries); + if (delayUs > kMaxMonitorDelayUs) { + delayUs = kMaxMonitorDelayUs; + } + ALOGV("sequence number high: %ld from (%ld .. %ld), monitor in %lld (retry=%d)", + mSeqNumber, firstSeqNumberInPlaylist, + lastSeqNumberInPlaylist, delayUs, mNumRetries); + postMonitorQueue(delayUs); return; } // we've missed the boat, let's start from the lowest sequence // number available and signal a discontinuity. - ALOGI("We've missed the boat, restarting playback."); - mSeqNumber = lastSeqNumberInPlaylist; + ALOGI("We've missed the boat, restarting playback." + " mStartup=%d, was looking for %d in %d-%d", + mStartup, mSeqNumber, firstSeqNumberInPlaylist, + lastSeqNumberInPlaylist); + mSeqNumber = lastSeqNumberInPlaylist - 3; + if (mSeqNumber < firstSeqNumberInPlaylist) { + mSeqNumber = firstSeqNumberInPlaylist; + } explicitDiscontinuity = true; // fall through diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index 1648e02..78dea20 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -79,6 +79,7 @@ private: }; static const int64_t kMinBufferedDurationUs; + static const int64_t kMaxMonitorDelayUs; sp mNotify; sp mSession; @@ -97,6 +98,7 @@ private: int32_t mSeqNumber; int32_t mNumRetries; bool mStartup; + bool mPrepared; int64_t mNextPTSTimeUs; int32_t mMonitorQueueGeneration; @@ -120,10 +122,11 @@ private: status_t decryptBuffer( size_t playlistIndex, const sp &buffer); - void postMonitorQueue(int64_t delayUs = 0); + void postMonitorQueue(int64_t delayUs = 0, int64_t minDelayUs = 0); void cancelMonitorQueue(); - bool timeToRefreshPlaylist(int64_t nowUs) const; + int64_t delayUsToRefreshPlaylist() const; + status_t refreshPlaylist(); // Returns the media time in us of the segment specified by seqNumber. // This is computed by summing the durations of all segments before it. -- cgit v1.1 From fd9b01b92a95f94d2d3a8b0ee5973756784fe05f Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Tue, 17 Dec 2013 14:10:46 -0800 Subject: stagefright: Fix issue with tracking media format in packet source Media format in AnotherPacketSource is now tracked across discontinuities. This fixes a bug where format was set on queueAccessUnit and cleared on dequeueAccessUnit, thereby allowing it to remain cleared. Change-Id: I20975a630443f4a223a2b4344e8244f34b9560b9 Signed-off-by: Lajos Molnar Bug: 12060952 --- media/libstagefright/httplive/PlaylistFetcher.cpp | 9 ++-- .../libstagefright/mpeg2ts/AnotherPacketSource.cpp | 48 ++++++++++++++++++---- 2 files changed, 44 insertions(+), 13 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 1754bf2..f095987 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -861,12 +861,13 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( && source->dequeueAccessUnit(&accessUnit) == OK) { // Note that we do NOT dequeue any discontinuities. + // for simplicity, store a reference to the format in each unit + sp format = source->getFormat(); + if (format != NULL) { + accessUnit->meta()->setObject("format", format); + } packetSource->queueAccessUnit(accessUnit); } - - if (packetSource->getFormat() == NULL) { - packetSource->setFormat(source->getFormat()); - } } return OK; diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index 3153c8b..52fb2a5 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -70,7 +70,27 @@ status_t AnotherPacketSource::stop() { } sp AnotherPacketSource::getFormat() { - return mFormat; + Mutex::Autolock autoLock(mLock); + if (mFormat != NULL) { + return mFormat; + } + + List >::iterator it = mBuffers.begin(); + while (it != mBuffers.end()) { + sp buffer = *it; + int32_t discontinuity; + if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { + break; + } + + sp object; + if (buffer->meta()->findObject("format", &object)) { + return static_cast(object.get()); + } + + ++it; + } + return NULL; } status_t AnotherPacketSource::dequeueAccessUnit(sp *buffer) { @@ -94,6 +114,11 @@ status_t AnotherPacketSource::dequeueAccessUnit(sp *buffer) { return INFO_DISCONTINUITY; } + sp object; + if ((*buffer)->meta()->findObject("format", &object)) { + mFormat = static_cast(object.get()); + } + return OK; } @@ -120,17 +145,22 @@ status_t AnotherPacketSource::read( } return INFO_DISCONTINUITY; - } else { - int64_t timeUs; - CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); + } - MediaBuffer *mediaBuffer = new MediaBuffer(buffer); + sp object; + if (buffer->meta()->findObject("format", &object)) { + mFormat = static_cast(object.get()); + } - mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs); + int64_t timeUs; + CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); - *out = mediaBuffer; - return OK; - } + MediaBuffer *mediaBuffer = new MediaBuffer(buffer); + + mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs); + + *out = mediaBuffer; + return OK; } return mEOSResult; -- cgit v1.1 From be08f6a6688f3b1ae6914fbe800953c9bfb13c45 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 19 Dec 2013 09:09:33 -0800 Subject: Fix compile warning / incomplete initialization Change-Id: Ib4accf99be800988e081f96222e1ee73538221ec --- media/libmedia/mediaplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 0f6d897..7a6f31d 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -654,7 +654,7 @@ status_t MediaPlayer::setRetransmitEndpoint(const char* addrString, return BAD_VALUE; } - memset(&mRetransmitEndpoint, 0, sizeof(&mRetransmitEndpoint)); + memset(&mRetransmitEndpoint, 0, sizeof(mRetransmitEndpoint)); mRetransmitEndpoint.sin_family = AF_INET; mRetransmitEndpoint.sin_addr = saddr; mRetransmitEndpoint.sin_port = htons(port); -- cgit v1.1 From c23885ebb142b9da31543789ecc3f7cf7111bc67 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 19 Dec 2013 16:35:18 -0800 Subject: Add versions of get/SetParameters without I/O handle This is a step towards hiding I/O handles from application level, as much as possible. Change-Id: I30f4171d5dcf77f8e8eb332ce2e9245b30f5f2e1 --- media/libmedia/AudioSystem.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 8033c2c..18f0f46 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -190,6 +190,16 @@ String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& ke return result; } +status_t AudioSystem::setParameters(const String8& keyValuePairs) +{ + return setParameters((audio_io_handle_t) 0, keyValuePairs); +} + +String8 AudioSystem::getParameters(const String8& keys) +{ + return getParameters((audio_io_handle_t) 0, keys); +} + // convert volume steps to natural log scale // change this value to change volume scaling -- cgit v1.1 From 7c7be1e05634d96d08210efb4bdeb012ffba440d Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 19 Dec 2013 16:34:04 -0800 Subject: Fix some (but not all) unused parameter warnings Change-Id: Ia99e23a0b46db3f3e6aa46f9018e63c14f4af369 --- media/libmedia/AudioRecord.cpp | 6 +++--- media/libmedia/AudioSystem.cpp | 4 ++-- media/libmedia/AudioTrack.cpp | 8 ++++---- media/libmedia/AudioTrackShared.cpp | 4 ++-- media/libmedia/IMediaDeathNotifier.cpp | 2 +- media/libmedia/SoundPool.cpp | 4 ++-- media/libmedia/mediametadataretriever.cpp | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 666fafa..6ec8ed2 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -692,7 +692,7 @@ ssize_t AudioRecord::read(void* buffer, size_t userSize) // ------------------------------------------------------------------------- -nsecs_t AudioRecord::processAudioBuffer(const sp& thread) +nsecs_t AudioRecord::processAudioBuffer() { mLock.lock(); if (mAwaitBoost) { @@ -954,7 +954,7 @@ status_t AudioRecord::restoreRecord_l(const char *from) // ========================================================================= -void AudioRecord::DeathNotifier::binderDied(const wp& who) +void AudioRecord::DeathNotifier::binderDied(const wp& who __unused) { sp audioRecord = mAudioRecord.promote(); if (audioRecord != 0) { @@ -993,7 +993,7 @@ bool AudioRecord::AudioRecordThread::threadLoop() return true; } } - nsecs_t ns = mReceiver.processAudioBuffer(this); + nsecs_t ns = mReceiver.processAudioBuffer(); switch (ns) { case 0: return true; diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 8033c2c..9b0ad22 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -419,7 +419,7 @@ void AudioSystem::releaseAudioSessionId(int audioSession) { // --------------------------------------------------------------------------- -void AudioSystem::AudioFlingerClient::binderDied(const wp& who) { +void AudioSystem::AudioFlingerClient::binderDied(const wp& who __unused) { Mutex::Autolock _l(AudioSystem::gLock); AudioSystem::gAudioFlinger.clear(); @@ -804,7 +804,7 @@ bool AudioSystem::isOffloadSupported(const audio_offload_info_t& info) // --------------------------------------------------------------------------- -void AudioSystem::AudioPolicyServiceClient::binderDied(const wp& who) { +void AudioSystem::AudioPolicyServiceClient::binderDied(const wp& who __unused) { Mutex::Autolock _l(AudioSystem::gLock); AudioSystem::gAudioPolicyService.clear(); diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index b48cb1f..ddd4612 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1341,7 +1341,7 @@ status_t TimedAudioTrack::setMediaTimeTransform(const LinearTransform& xform, // ------------------------------------------------------------------------- -nsecs_t AudioTrack::processAudioBuffer(const sp& thread) +nsecs_t AudioTrack::processAudioBuffer() { // Currently the AudioTrack thread is not created if there are no callbacks. // Would it ever make sense to run the thread, even without callbacks? @@ -1767,7 +1767,7 @@ String8 AudioTrack::getParameters(const String8& keys) } } -status_t AudioTrack::dump(int fd, const Vector& args) const +status_t AudioTrack::dump(int fd, const Vector& args __unused) const { const size_t SIZE = 256; @@ -1797,7 +1797,7 @@ uint32_t AudioTrack::getUnderrunFrames() const // ========================================================================= -void AudioTrack::DeathNotifier::binderDied(const wp& who) +void AudioTrack::DeathNotifier::binderDied(const wp& who __unused) { sp audioTrack = mAudioTrack.promote(); if (audioTrack != 0) { @@ -1841,7 +1841,7 @@ bool AudioTrack::AudioTrackThread::threadLoop() return true; } } - nsecs_t ns = mReceiver.processAudioBuffer(this); + nsecs_t ns = mReceiver.processAudioBuffer(); switch (ns) { case 0: return true; diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index caa7900..7a1e207 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -765,7 +765,7 @@ ssize_t StaticAudioTrackServerProxy::pollPosition() return (ssize_t) position; } -status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush) +status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush __unused) { if (mIsShutdown) { buffer->mFrameCount = 0; @@ -847,7 +847,7 @@ void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer) buffer->mNonContig = 0; } -void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount) +void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount __unused) { // Unlike AudioTrackServerProxy::tallyUnderrunFrames() used for streaming tracks, // we don't have a location to count underrun frames. The underrun frame counter diff --git a/media/libmedia/IMediaDeathNotifier.cpp b/media/libmedia/IMediaDeathNotifier.cpp index 9db5b1b..10b4934 100644 --- a/media/libmedia/IMediaDeathNotifier.cpp +++ b/media/libmedia/IMediaDeathNotifier.cpp @@ -75,7 +75,7 @@ IMediaDeathNotifier::removeObitRecipient(const wp& recipien } void -IMediaDeathNotifier::DeathNotifier::binderDied(const wp& who) { +IMediaDeathNotifier::DeathNotifier::binderDied(const wp& who __unused) { ALOGW("media server died"); // Need to do this with the lock held diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp index b420c95..98acd1f 100644 --- a/media/libmedia/SoundPool.cpp +++ b/media/libmedia/SoundPool.cpp @@ -199,7 +199,7 @@ SoundChannel* SoundPool::findNextChannel(int channelID) return NULL; } -int SoundPool::load(const char* path, int priority) +int SoundPool::load(const char* path, int priority __unused) { ALOGV("load: path=%s, priority=%d", path, priority); Mutex::Autolock lock(&mLock); @@ -209,7 +209,7 @@ int SoundPool::load(const char* path, int priority) return sample->sampleID(); } -int SoundPool::load(int fd, int64_t offset, int64_t length, int priority) +int SoundPool::load(int fd, int64_t offset, int64_t length, int priority __unused) { ALOGV("load: fd=%d, offset=%lld, length=%lld, priority=%d", fd, offset, length, priority); diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp index 110b94c..bad2494 100644 --- a/media/libmedia/mediametadataretriever.cpp +++ b/media/libmedia/mediametadataretriever.cpp @@ -157,7 +157,7 @@ sp MediaMetadataRetriever::extractAlbumArt() return mRetriever->extractAlbumArt(); } -void MediaMetadataRetriever::DeathNotifier::binderDied(const wp& who) { +void MediaMetadataRetriever::DeathNotifier::binderDied(const wp& who __unused) { Mutex::Autolock lock(MediaMetadataRetriever::sServiceLock); MediaMetadataRetriever::sService.clear(); ALOGW("MediaMetadataRetriever server died!"); -- cgit v1.1 From 74935e44734c1ec235c2b6677db3e0dbefa5ddb8 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 19 Dec 2013 08:56:45 -0800 Subject: Replace control block frameCount_ by explicit in/out parameter in IAudioFlinger::createTrack and IAudioFlinger::openRecord Change-Id: I09c644c80e92c8e744b1b99055988a2588b2a83d --- media/libmedia/AudioRecord.cpp | 13 +++++++++---- media/libmedia/AudioTrack.cpp | 6 ++++-- media/libmedia/AudioTrackShared.cpp | 2 +- media/libmedia/IAudioFlinger.cpp | 20 ++++++++++++++++---- 4 files changed, 30 insertions(+), 11 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 666fafa..13c9f60 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -255,9 +255,6 @@ status_t AudioRecord::set( mStatus = NO_ERROR; - // Update buffer size in case it has been limited by AudioFlinger during track creation - mFrameCount = mCblk->frameCount_; - mActive = false; mCbf = cbf; mRefreshRemaining = true; @@ -462,11 +459,13 @@ status_t AudioRecord::openRecord_l(size_t epoch) return BAD_VALUE; } + size_t temp = mFrameCount; // temp may be replaced by a revised value of frameCount, + // but we will still need the original value also int originalSessionId = mSessionId; sp record = audioFlinger->openRecord(input, mSampleRate, mFormat, mChannelMask, - mFrameCount, + &temp, &trackFlags, tid, &mSessionId, @@ -498,6 +497,12 @@ status_t AudioRecord::openRecord_l(size_t epoch) mCblkMemory = iMem; audio_track_cblk_t* cblk = static_cast(iMemPointer); mCblk = cblk; + // note that temp is the (possibly revised) value of mFrameCount + if (temp < mFrameCount || (mFrameCount == 0 && temp == 0)) { + ALOGW("Requested frameCount %u but received frameCount %u", mFrameCount, temp); + } + mFrameCount = temp; + // FIXME missing fast track frameCount logic mAwaitBoost = false; if (mFlags & AUDIO_INPUT_FLAG_FAST) { diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index b48cb1f..74bb7a6 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -969,13 +969,15 @@ status_t AudioTrack::createTrack_l( trackFlags |= IAudioFlinger::TRACK_OFFLOAD; } + size_t temp = frameCount; // temp may be replaced by a revised value of frameCount, + // but we will still need the original value also sp track = audioFlinger->createTrack(streamType, sampleRate, // AudioFlinger only sees 16-bit PCM format == AUDIO_FORMAT_PCM_8_BIT ? AUDIO_FORMAT_PCM_16_BIT : format, mChannelMask, - frameCount, + &temp, &trackFlags, sharedBuffer, output, @@ -1003,7 +1005,7 @@ status_t AudioTrack::createTrack_l( mCblkMemory = iMem; audio_track_cblk_t* cblk = static_cast(iMem->pointer()); mCblk = cblk; - size_t temp = cblk->frameCount_; + // note that temp is the (possibly revised) value of frameCount if (temp < frameCount || (frameCount == 0 && temp == 0)) { // In current design, AudioTrack client checks and ensures frame count validity before // passing it to AudioFlinger so AudioFlinger should not return a different value except diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index caa7900..11f5d58 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -26,7 +26,7 @@ extern "C" { namespace android { audio_track_cblk_t::audio_track_cblk_t() - : mServer(0), frameCount_(0), mFutex(0), mMinimum(0), + : mServer(0), mFutex(0), mMinimum(0), mVolumeLR(0x10001000), mSampleRate(0), mSendLevel(0), mFlags(0) { memset(&u, 0, sizeof(u)); diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 9df10f0..c33cb13 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -89,7 +89,7 @@ public: uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, - size_t frameCount, + size_t *pFrameCount, track_flags_t *flags, const sp& sharedBuffer, audio_io_handle_t output, @@ -106,6 +106,7 @@ public: data.writeInt32(sampleRate); data.writeInt32(format); data.writeInt32(channelMask); + size_t frameCount = pFrameCount != NULL ? *pFrameCount : 0; data.writeInt32(frameCount); track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT; data.writeInt32(lFlags); @@ -127,6 +128,10 @@ public: if (lStatus != NO_ERROR) { ALOGE("createTrack error: %s", strerror(-lStatus)); } else { + frameCount = reply.readInt32(); + if (pFrameCount != NULL) { + *pFrameCount = frameCount; + } lFlags = reply.readInt32(); if (flags != NULL) { *flags = lFlags; @@ -150,7 +155,7 @@ public: uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, - size_t frameCount, + size_t *pFrameCount, track_flags_t *flags, pid_t tid, int *sessionId, @@ -163,6 +168,7 @@ public: data.writeInt32(sampleRate); data.writeInt32(format); data.writeInt32(channelMask); + size_t frameCount = pFrameCount != NULL ? *pFrameCount : 0; data.writeInt32(frameCount); track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT; data.writeInt32(lFlags); @@ -176,6 +182,10 @@ public: if (lStatus != NO_ERROR) { ALOGE("openRecord error: %s", strerror(-lStatus)); } else { + frameCount = reply.readInt32(); + if (pFrameCount != NULL) { + *pFrameCount = frameCount; + } lFlags = reply.readInt32(); if (flags != NULL) { *flags = lFlags; @@ -793,9 +803,10 @@ status_t BnAudioFlinger::onTransact( } else { track = createTrack( (audio_stream_type_t) streamType, sampleRate, format, - channelMask, frameCount, &flags, buffer, output, tid, + channelMask, &frameCount, &flags, buffer, output, tid, &sessionId, name, clientUid, &status); } + reply->writeInt32(frameCount); reply->writeInt32(flags); reply->writeInt32(sessionId); reply->writeString8(name); @@ -815,8 +826,9 @@ status_t BnAudioFlinger::onTransact( int sessionId = data.readInt32(); status_t status; sp record = openRecord(input, - sampleRate, format, channelMask, frameCount, &flags, tid, &sessionId, &status); + sampleRate, format, channelMask, &frameCount, &flags, tid, &sessionId, &status); LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR)); + reply->writeInt32(frameCount); reply->writeInt32(flags); reply->writeInt32(sessionId); reply->writeInt32(status); -- cgit v1.1 From aea7ea06394bcb155972d82055d4ea59962e4051 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 26 Jun 2013 09:25:47 -0700 Subject: Use AUDIO_SESSION_ALLOCATE instead of 0 Also fix a couple of places where we were using AUDIO_SESSION_OUTPUT_MIX, which happens to also be equal to 0, but has a different meaning. Change-Id: I90e39be3b89f5021a96d9e3b8d10929013ca977f --- media/libmedia/AudioRecord.cpp | 8 ++++---- media/libmedia/IAudioFlinger.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 666fafa..df99147 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -71,7 +71,7 @@ status_t AudioRecord::getMinFrameCount( // --------------------------------------------------------------------------- AudioRecord::AudioRecord() - : mStatus(NO_INIT), mSessionId(0), + : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT) { } @@ -88,7 +88,7 @@ AudioRecord::AudioRecord( int sessionId, transfer_type transferType, audio_input_flags_t flags) - : mStatus(NO_INIT), mSessionId(0), + : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mProxy(NULL) @@ -233,7 +233,7 @@ status_t AudioRecord::set( mNotificationFramesReq = notificationFrames; mNotificationFramesAct = 0; - if (sessionId == 0 ) { + if (sessionId == AUDIO_SESSION_ALLOCATE) { mSessionId = AudioSystem::newAudioSessionId(); } else { mSessionId = sessionId; @@ -471,7 +471,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) tid, &mSessionId, &status); - ALOGE_IF(originalSessionId != 0 && mSessionId != originalSessionId, + ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId, "session ID changed from %d to %d", originalSessionId, mSessionId); if (record == 0 || status != NO_ERROR) { diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 9df10f0..c9c8d58 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -117,7 +117,7 @@ public: } data.writeInt32((int32_t) output); data.writeInt32((int32_t) tid); - int lSessionId = 0; + int lSessionId = AUDIO_SESSION_ALLOCATE; if (sessionId != NULL) { lSessionId = *sessionId; } @@ -167,7 +167,7 @@ public: track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT; data.writeInt32(lFlags); data.writeInt32((int32_t) tid); - int lSessionId = 0; + int lSessionId = AUDIO_SESSION_ALLOCATE; if (sessionId != NULL) { lSessionId = *sessionId; } -- cgit v1.1 From c21623371d947b2c0bf9c4029bcc8d33c590a8ef Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Wed, 18 Dec 2013 09:43:21 -0800 Subject: Update AAC decoder wrapper to latest FDK API for output channel count Rename decoder parameter for the maximum number of PCM output channels, according to FDK AAC decoder interface, as defined in aacdecoder_lib.h Bug 9428126 Change-Id: I2f0f6ca848bdbc8657d8dea589b03238245c0eaf --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index f842e27..2f5eff4 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -30,7 +30,7 @@ #define DRC_DEFAULT_MOBILE_REF_LEVEL 64 /* 64*-0.25dB = -16 dB below full scale for mobile conf */ #define DRC_DEFAULT_MOBILE_DRC_CUT 127 /* maximum compression of dynamic range for mobile conf */ #define DRC_DEFAULT_MOBILE_DRC_BOOST 127 /* maximum compression of dynamic range for mobile conf */ -#define MAX_CHANNEL_COUNT 6 /* maximum number of audio channels that can be decoded */ +#define MAX_CHANNEL_COUNT 8 /* maximum number of audio channels that can be decoded */ // names of properties that can be used to override the default DRC settings #define PROP_DRC_OVERRIDE_REF_LEVEL "aac_drc_reference_level" #define PROP_DRC_OVERRIDE_CUT "aac_drc_cut" @@ -296,8 +296,11 @@ void SoftAAC2::maybeConfigureDownmix() const { if (!(property_get("media.aac_51_output_enabled", value, NULL) && (!strcmp(value, "1") || !strcasecmp(value, "true")))) { ALOGI("Downmixing multichannel AAC to stereo"); - aacDecoder_SetParam(mAACDecoder, AAC_PCM_OUTPUT_CHANNELS, 2); + aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, 2); mStreamInfo->numChannels = 2; + // By default, the decoder creates a 5.1 channel downmix signal + // for seven and eight channel input streams. To enable 6.1 and 7.1 channel output + // use aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1) } } } -- cgit v1.1 From f4512c9672110c11b7bdeea0073a54bfae9c8f87 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Wed, 18 Dec 2013 15:47:49 -0800 Subject: Support more channel configurations in MPEG4Extractor Add support for streams having an audio specific configuration with the channel_configuration equal to zero. Add support for 6.1 and 7.1 channel configurations. Bug 9428126 Change-Id: Iaac2516139093579c52095d4f74ae4428f8e368a --- media/libstagefright/MPEG4Extractor.cpp | 159 +++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index dc73980..9c89e82 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -2372,6 +2372,58 @@ status_t MPEG4Extractor::verifyTrack(Track *track) { return OK; } +typedef enum { + //AOT_NONE = -1, + //AOT_NULL_OBJECT = 0, + //AOT_AAC_MAIN = 1, /**< Main profile */ + AOT_AAC_LC = 2, /**< Low Complexity object */ + //AOT_AAC_SSR = 3, + //AOT_AAC_LTP = 4, + AOT_SBR = 5, + //AOT_AAC_SCAL = 6, + //AOT_TWIN_VQ = 7, + //AOT_CELP = 8, + //AOT_HVXC = 9, + //AOT_RSVD_10 = 10, /**< (reserved) */ + //AOT_RSVD_11 = 11, /**< (reserved) */ + //AOT_TTSI = 12, /**< TTSI Object */ + //AOT_MAIN_SYNTH = 13, /**< Main Synthetic object */ + //AOT_WAV_TAB_SYNTH = 14, /**< Wavetable Synthesis object */ + //AOT_GEN_MIDI = 15, /**< General MIDI object */ + //AOT_ALG_SYNTH_AUD_FX = 16, /**< Algorithmic Synthesis and Audio FX object */ + AOT_ER_AAC_LC = 17, /**< Error Resilient(ER) AAC Low Complexity */ + //AOT_RSVD_18 = 18, /**< (reserved) */ + //AOT_ER_AAC_LTP = 19, /**< Error Resilient(ER) AAC LTP object */ + AOT_ER_AAC_SCAL = 20, /**< Error Resilient(ER) AAC Scalable object */ + //AOT_ER_TWIN_VQ = 21, /**< Error Resilient(ER) TwinVQ object */ + AOT_ER_BSAC = 22, /**< Error Resilient(ER) BSAC object */ + AOT_ER_AAC_LD = 23, /**< Error Resilient(ER) AAC LowDelay object */ + //AOT_ER_CELP = 24, /**< Error Resilient(ER) CELP object */ + //AOT_ER_HVXC = 25, /**< Error Resilient(ER) HVXC object */ + //AOT_ER_HILN = 26, /**< Error Resilient(ER) HILN object */ + //AOT_ER_PARA = 27, /**< Error Resilient(ER) Parametric object */ + //AOT_RSVD_28 = 28, /**< might become SSC */ + AOT_PS = 29, /**< PS, Parametric Stereo (includes SBR) */ + //AOT_MPEGS = 30, /**< MPEG Surround */ + + AOT_ESCAPE = 31, /**< Signal AOT uses more than 5 bits */ + + //AOT_MP3ONMP4_L1 = 32, /**< MPEG-Layer1 in mp4 */ + //AOT_MP3ONMP4_L2 = 33, /**< MPEG-Layer2 in mp4 */ + //AOT_MP3ONMP4_L3 = 34, /**< MPEG-Layer3 in mp4 */ + //AOT_RSVD_35 = 35, /**< might become DST */ + //AOT_RSVD_36 = 36, /**< might become ALS */ + //AOT_AAC_SLS = 37, /**< AAC + SLS */ + //AOT_SLS = 38, /**< SLS */ + //AOT_ER_AAC_ELD = 39, /**< AAC Enhanced Low Delay */ + + //AOT_USAC = 42, /**< USAC */ + //AOT_SAOC = 43, /**< SAOC */ + //AOT_LD_MPEGS = 44, /**< Low Delay MPEG Surround */ + + //AOT_RSVD50 = 50, /**< Interim AOT for Rsvd50 */ +} AUDIO_OBJECT_TYPE; + status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio( const void *esds_data, size_t esds_size) { ESDS esds(esds_data, esds_size); @@ -2454,7 +2506,7 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio( sampleRate = kSamplingRate[freqIndex]; } - if (objectType == 5 || objectType == 29) { // SBR specific config per 14496-3 table 1.13 + if (objectType == AOT_SBR || objectType == AOT_PS) {//SBR specific config per 14496-3 table 1.13 uint32_t extFreqIndex = br.getBits(4); int32_t extSampleRate; if (extFreqIndex == 15) { @@ -2472,6 +2524,111 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio( // mLastTrack->meta->setInt32(kKeyExtSampleRate, extSampleRate); } + switch (numChannels) { + // values defined in 14496-3_2009 amendment-4 Table 1.19 - Channel Configuration + case 0: + case 1:// FC + case 2:// FL FR + case 3:// FC, FL FR + case 4:// FC, FL FR, RC + case 5:// FC, FL FR, SL SR + case 6:// FC, FL FR, SL SR, LFE + //numChannels already contains the right value + break; + case 11:// FC, FL FR, SL SR, RC, LFE + numChannels = 7; + break; + case 7: // FC, FCL FCR, FL FR, SL SR, LFE + case 12:// FC, FL FR, SL SR, RL RR, LFE + case 14:// FC, FL FR, SL SR, LFE, FHL FHR + numChannels = 8; + break; + default: + return ERROR_UNSUPPORTED; + } + + { + if (objectType == AOT_SBR || objectType == AOT_PS) { + const int32_t extensionSamplingFrequency = br.getBits(4); + objectType = br.getBits(5); + + if (objectType == AOT_ESCAPE) { + objectType = 32 + br.getBits(6); + } + } + if (objectType == AOT_AAC_LC || objectType == AOT_ER_AAC_LC || + objectType == AOT_ER_AAC_LD || objectType == AOT_ER_AAC_SCAL || + objectType == AOT_ER_BSAC) { + const int32_t frameLengthFlag = br.getBits(1); + + const int32_t dependsOnCoreCoder = br.getBits(1); + + if (dependsOnCoreCoder ) { + const int32_t coreCoderDelay = br.getBits(14); + } + + const int32_t extensionFlag = br.getBits(1); + + if (numChannels == 0 ) { + int32_t channelsEffectiveNum = 0; + int32_t channelsNum = 0; + const int32_t ElementInstanceTag = br.getBits(4); + const int32_t Profile = br.getBits(2); + const int32_t SamplingFrequencyIndex = br.getBits(4); + const int32_t NumFrontChannelElements = br.getBits(4); + const int32_t NumSideChannelElements = br.getBits(4); + const int32_t NumBackChannelElements = br.getBits(4); + const int32_t NumLfeChannelElements = br.getBits(2); + const int32_t NumAssocDataElements = br.getBits(3); + const int32_t NumValidCcElements = br.getBits(4); + + const int32_t MonoMixdownPresent = br.getBits(1); + if (MonoMixdownPresent != 0) { + const int32_t MonoMixdownElementNumber = br.getBits(4); + } + + const int32_t StereoMixdownPresent = br.getBits(1); + if (StereoMixdownPresent != 0) { + const int32_t StereoMixdownElementNumber = br.getBits(4); + } + + const int32_t MatrixMixdownIndexPresent = br.getBits(1); + if (MatrixMixdownIndexPresent != 0) { + const int32_t MatrixMixdownIndex = br.getBits(2); + const int32_t PseudoSurroundEnable = br.getBits(1); + } + + int i; + for (i=0; i < NumFrontChannelElements; i++) { + const int32_t FrontElementIsCpe = br.getBits(1); + const int32_t FrontElementTagSelect = br.getBits(4); + channelsNum += FrontElementIsCpe ? 2 : 1; + } + + for (i=0; i < NumSideChannelElements; i++) { + const int32_t SideElementIsCpe = br.getBits(1); + const int32_t SideElementTagSelect = br.getBits(4); + channelsNum += SideElementIsCpe ? 2 : 1; + } + + for (i=0; i < NumBackChannelElements; i++) { + const int32_t BackElementIsCpe = br.getBits(1); + const int32_t BackElementTagSelect = br.getBits(4); + channelsNum += BackElementIsCpe ? 2 : 1; + } + channelsEffectiveNum = channelsNum; + + for (i=0; i < NumLfeChannelElements; i++) { + const int32_t LfeElementTagSelect = br.getBits(4); + channelsNum += 1; + } + ALOGV("mpeg4 audio channelsNum = %d", channelsNum); + ALOGV("mpeg4 audio channelsEffectiveNum = %d", channelsEffectiveNum); + numChannels = channelsNum; + } + } + } + if (numChannels == 0) { return ERROR_UNSUPPORTED; } -- cgit v1.1 From 5446e541367061b53f45f3fd4600f9060680bca3 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 8 Jan 2014 08:58:53 -0800 Subject: Cleanup AudioSystem::getInputBufferSize error handling and caching Previously, if the IAudioFlinger::getInputBufferSize failed, it would return NO_ERROR but a zero buffer size value, which could confuse the caller. Now it returns BAD_VALUE in this case. Also it would still cache the zero buffer size. Now it does not cache on failure. Removed over-initialization of the cache globals. Change-Id: I6835fcb56fe52535e018fc8c0c242115221b5d85 --- media/libmedia/AudioSystem.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 9a76111..de3beb5 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -40,10 +40,10 @@ audio_error_callback AudioSystem::gAudioErrorCallback = NULL; DefaultKeyedVector AudioSystem::gOutputs(0); // Cached values for recording queries, all protected by gLock -uint32_t AudioSystem::gPrevInSamplingRate = 16000; -audio_format_t AudioSystem::gPrevInFormat = AUDIO_FORMAT_PCM_16_BIT; -audio_channel_mask_t AudioSystem::gPrevInChannelMask = AUDIO_CHANNEL_IN_MONO; -size_t AudioSystem::gInBuffSize = 0; +uint32_t AudioSystem::gPrevInSamplingRate; +audio_format_t AudioSystem::gPrevInFormat; +audio_channel_mask_t AudioSystem::gPrevInChannelMask; +size_t AudioSystem::gInBuffSize = 0; // zero indicates cache is invalid // establish binder interface to AudioFlinger service @@ -359,6 +359,12 @@ status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t for return PERMISSION_DENIED; } inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask); + if (inBuffSize == 0) { + ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %x channelMask %x", + sampleRate, format, channelMask); + return BAD_VALUE; + } + // A benign race is possible here: we could overwrite a fresher cache entry gLock.lock(); // save the request params gPrevInSamplingRate = sampleRate; -- cgit v1.1 From f94006ca0f30c27868c284e553f57bf467ae92bc Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 8 Jan 2014 08:56:06 -0800 Subject: Cleanup error handling in AudioSystem get methods Don't return zero sample rate or frame count without an error. Change-Id: I052d841080ed33e4f081ae9825a2f33dff444fb9 --- media/libmedia/AudioSystem.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 9a76111..e37888b 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -259,6 +259,11 @@ status_t AudioSystem::getSamplingRate(audio_io_handle_t output, *samplingRate = outputDesc->samplingRate; gLock.unlock(); } + if (*samplingRate == 0) { + ALOGE("AudioSystem::getSamplingRate failed for output %d stream type %d", + output, streamType); + return BAD_VALUE; + } ALOGV("getSamplingRate() streamType %d, output %d, sampling rate %u", streamType, output, *samplingRate); @@ -299,6 +304,11 @@ status_t AudioSystem::getFrameCount(audio_io_handle_t output, *frameCount = outputDesc->frameCount; gLock.unlock(); } + if (*frameCount == 0) { + ALOGE("AudioSystem::getFrameCount failed for output %d stream type %d", + output, streamType); + return BAD_VALUE; + } ALOGV("getFrameCount() streamType %d, output %d, frameCount %d", streamType, output, *frameCount); -- cgit v1.1 From 66a0467fdddada4caabd0f0a999fbb367fea7bee Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 8 Jan 2014 08:53:44 -0800 Subject: Cleanup AudioTrack::getMinFrameCount error handling Guarantee to return a non-zero frameCount for return status NO_ERROR; Return the correct specific status_t if any of the AudioSystem APIs fail, instead of the generic NO_INIT. API change: getMinFramCount no longer defaults to zero on error, so callers _must_ check the return status. This change makes getMinFrameCount more like other APIs. All known callers were reviewed, and they do check the return status. Change-Id: I4a8342a75ee89a068c23c84b8380ed9d1b968507 --- media/libmedia/AudioTrack.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index ddd4612..a6ffc62 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -44,9 +44,6 @@ status_t AudioTrack::getMinFrameCount( return BAD_VALUE; } - // default to 0 in case of error - *frameCount = 0; - // FIXME merge with similar code in createTrack_l(), except we're missing // some information here that is available in createTrack_l(): // audio_io_handle_t output @@ -54,16 +51,20 @@ status_t AudioTrack::getMinFrameCount( // audio_channel_mask_t channelMask // audio_output_flags_t flags uint32_t afSampleRate; - if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { - return NO_INIT; + status_t status; + status = AudioSystem::getOutputSamplingRate(&afSampleRate, streamType); + if (status != NO_ERROR) { + return status; } size_t afFrameCount; - if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { - return NO_INIT; + status = AudioSystem::getOutputFrameCount(&afFrameCount, streamType); + if (status != NO_ERROR) { + return status; } uint32_t afLatency; - if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) { - return NO_INIT; + status = AudioSystem::getOutputLatency(&afLatency, streamType); + if (status != NO_ERROR) { + return status; } // Ensure that buffer depth covers at least audio hardware latency @@ -74,6 +75,13 @@ status_t AudioTrack::getMinFrameCount( *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount : afFrameCount * minBufCount * sampleRate / afSampleRate; + // The formula above should always produce a non-zero value, but return an error + // in the unlikely event that it does not, as that's part of the API contract. + if (*frameCount == 0) { + ALOGE("AudioTrack::getMinFrameCount failed for streamType %d, sampleRate %d", + streamType, sampleRate); + return BAD_VALUE; + } ALOGV("getMinFrameCount=%d: afFrameCount=%d, minBufCount=%d, afSampleRate=%d, afLatency=%d", *frameCount, afFrameCount, minBufCount, afSampleRate, afLatency); return NO_ERROR; -- cgit v1.1 From efa6ea97022780b68e595e5326e30dbe2a799202 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 8 Jan 2014 09:10:43 -0800 Subject: Fix error handling in AudioSystem::getOutputForEffect and AudioPolicyService::getOutputForEffect. The conventional error value for audio_io_handle_t is 0, not a status_t cast to audio_io_handle_t. Change-Id: I34b3fd1a50f3fa1cbf39f32eea1911112a4e094a --- media/libmedia/AudioSystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 9a76111..cf7dfef 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -719,7 +719,8 @@ audio_devices_t AudioSystem::getDevicesForStream(audio_stream_type_t stream) audio_io_handle_t AudioSystem::getOutputForEffect(const effect_descriptor_t *desc) { const sp& aps = AudioSystem::get_audio_policy_service(); - if (aps == 0) return PERMISSION_DENIED; + // FIXME change return type to status_t, and return PERMISSION_DENIED here + if (aps == 0) return 0; return aps->getOutputForEffect(desc); } -- cgit v1.1 From 396fabdb6efcdac5aea3d9f559d1beedf6a4cedc Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 8 Jan 2014 08:54:23 -0800 Subject: Document AudioTrack mFrameCount and mReqFrameCount better and remove unnecessary initialization of mFrameCount in set(). Change-Id: I9effeb0a6dd035ca02fe77f6992c55d9515b4df6 --- media/libmedia/AudioTrack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index a6ffc62..7f6fd7a 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -318,7 +318,7 @@ status_t AudioTrack::set( mVolume[LEFT] = 1.0f; mVolume[RIGHT] = 1.0f; mSendLevel = 0.0f; - mFrameCount = frameCount; + // mFrameCount is initialized in createTrack_l mReqFrameCount = frameCount; mNotificationFramesReq = notificationFrames; mNotificationFramesAct = 0; -- cgit v1.1 From 2c6c5294388e251ebc1e00d6c8785190561c27fc Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 13 Jan 2014 10:29:08 -0800 Subject: Fix race in AudioTrack::getParameters() mOutput is protected by mLock. Change-Id: Id02e627062855ca60f28bd8961b1d5f44939c727 --- media/libmedia/AudioTrack.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index a6ffc62..1d56788 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1768,8 +1768,9 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) String8 AudioTrack::getParameters(const String8& keys) { - if (mOutput) { - return AudioSystem::getParameters(mOutput, keys); + audio_io_handle_t output = getOutput(); + if (output != 0) { + return AudioSystem::getParameters(output, keys); } else { return String8::empty(); } -- cgit v1.1 From b1bef51fec06e8bceec914d1b48b411d3ff2adff Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 13 Jan 2014 10:25:53 -0800 Subject: Improve error logging for getOutputSamplingRate Change-Id: I3b52402a663b27efe1d7c6a4f684521f33f3ff8f --- media/libmedia/AudioTrack.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index a6ffc62..f9d335f 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -245,12 +245,14 @@ status_t AudioTrack::set( streamType = AUDIO_STREAM_MUSIC; } + status_t status; if (sampleRate == 0) { - uint32_t afSampleRate; - if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { - return NO_INIT; + status = AudioSystem::getOutputSamplingRate(&sampleRate, streamType); + if (status != NO_ERROR) { + ALOGE("Could not get output sample rate for stream type %d; status %d", + streamType, status); + return status; } - sampleRate = afSampleRate; } mSampleRate = sampleRate; @@ -338,7 +340,7 @@ status_t AudioTrack::set( } // create the IAudioTrack - status_t status = createTrack_l(streamType, + status = createTrack_l(streamType, sampleRate, format, frameCount, -- cgit v1.1 From 41721bb796da589f8a669d1db7687a0da8f88761 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 13 Jan 2014 09:59:51 -0800 Subject: Fix race condition in AudioRecord::pause followed by start Bug: 11148722 Change-Id: Ia1e14133d73ac301fe06a047e70a573911822630 --- media/libmedia/AudioRecord.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 6ec8ed2..4328593 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -966,7 +966,8 @@ void AudioRecord::DeathNotifier::binderDied(const wp& who __unused) // ========================================================================= AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver, bool bCanCallJava) - : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL) + : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL), + mIgnoreNextPausedInt(false) { } @@ -983,6 +984,10 @@ bool AudioRecord::AudioRecordThread::threadLoop() // caller will check for exitPending() return true; } + if (mIgnoreNextPausedInt) { + mIgnoreNextPausedInt = false; + mPausedInt = false; + } if (mPausedInt) { if (mPausedNs > 0) { (void) mMyCond.waitRelative(mMyLock, mPausedNs); @@ -1017,12 +1022,7 @@ void AudioRecord::AudioRecordThread::requestExit() { // must be in this order to avoid a race condition Thread::requestExit(); - AutoMutex _l(mMyLock); - if (mPaused || mPausedInt) { - mPaused = false; - mPausedInt = false; - mMyCond.signal(); - } + resume(); } void AudioRecord::AudioRecordThread::pause() @@ -1034,6 +1034,7 @@ void AudioRecord::AudioRecordThread::pause() void AudioRecord::AudioRecordThread::resume() { AutoMutex _l(mMyLock); + mIgnoreNextPausedInt = true; if (mPaused || mPausedInt) { mPaused = false; mPausedInt = false; -- cgit v1.1 From 23a7545c4de71e989c2d8ebf1d5b9dcf463c36a9 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 13 Jan 2014 10:37:17 -0800 Subject: Document locking rules for mFlags, and fix discrepancies Change-Id: Id45ba544cc84133ed5e578fb4fd8a11b62211dc1 --- media/libmedia/AudioTrack.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 50e394b..8954d9f 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -457,7 +457,7 @@ void AudioTrack::stop() return; } - if (isOffloaded()) { + if (isOffloaded_l()) { mState = STATE_STOPPING; } else { mState = STATE_STOPPED; @@ -479,7 +479,7 @@ void AudioTrack::stop() sp t = mAudioTrackThread; if (t != 0) { - if (!isOffloaded()) { + if (!isOffloaded_l()) { t->pause(); } } else { @@ -517,7 +517,7 @@ void AudioTrack::flush_l() mRefreshRemaining = true; mState = STATE_FLUSHED; - if (isOffloaded()) { + if (isOffloaded_l()) { mProxy->interrupt(); } mProxy->flush(); @@ -550,7 +550,7 @@ status_t AudioTrack::setVolume(float left, float right) mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000)); - if (isOffloaded()) { + if (isOffloaded_l()) { mAudioTrack->signal(); } return NO_ERROR; @@ -614,7 +614,7 @@ uint32_t AudioTrack::getSampleRate() const // sample rate can be updated during playback by the offloaded decoder so we need to // query the HAL and update if needed. // FIXME use Proxy return channel to update the rate from server and avoid polling here - if (isOffloaded()) { + if (isOffloaded_l()) { if (mOutput != 0) { uint32_t sampleRate = 0; status_t status = AudioSystem::getSamplingRate(mOutput, mStreamType, &sampleRate); @@ -751,7 +751,7 @@ status_t AudioTrack::getPosition(uint32_t *position) const } AutoMutex lock(mLock); - if (isOffloaded()) { + if (isOffloaded_l()) { uint32_t dspFrames = 0; if (mOutput != 0) { @@ -1389,7 +1389,7 @@ nsecs_t AudioTrack::processAudioBuffer() // for offloaded tracks restoreTrack_l() will just update the sequence and clear // AudioSystem cache. We should not exit here but after calling the callback so // that the upper layers can recreate the track - if (!isOffloaded() || (mSequence == mObservedSequence)) { + if (!isOffloaded_l() || (mSequence == mObservedSequence)) { status_t status = restoreTrack_l("processAudioBuffer"); mLock.unlock(); // Run again immediately, but with a new IAudioTrack @@ -1676,7 +1676,7 @@ nsecs_t AudioTrack::processAudioBuffer() status_t AudioTrack::restoreTrack_l(const char *from) { ALOGW("dead IAudioTrack, %s, creating a new one from %s()", - isOffloaded() ? "Offloaded" : "PCM", from); + isOffloaded_l() ? "Offloaded" : "PCM", from); ++mSequence; status_t result; @@ -1684,7 +1684,8 @@ status_t AudioTrack::restoreTrack_l(const char *from) // output parameters in getOutput_l() and createTrack_l() AudioSystem::clearAudioConfigCache(); - if (isOffloaded()) { + if (isOffloaded_l()) { + // FIXME re-creation of offloaded tracks is not yet implemented return DEAD_OBJECT; } @@ -1778,6 +1779,12 @@ String8 AudioTrack::getParameters(const String8& keys) } } +bool AudioTrack::isOffloaded() const +{ + AutoMutex lock(mLock); + return isOffloaded_l(); +} + status_t AudioTrack::dump(int fd, const Vector& args __unused) const { -- cgit v1.1 From 2b2165c75790050810460c8de3f414876bce4c0e Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 13 Jan 2014 08:53:36 -0800 Subject: Unify comments between AudioTrack and AudioRecord Change-Id: I00a1025e2891a1c96218b3c2187eaddda6614ebc --- media/libmedia/AudioRecord.cpp | 8 +++++--- media/libmedia/AudioTrack.cpp | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 4328593..d2a81e1 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -352,6 +352,7 @@ bool AudioRecord::stopped() const status_t AudioRecord::setMarkerPosition(uint32_t marker) { + // The only purpose of setting marker position is to get a callback if (mCbf == NULL) { return INVALID_OPERATION; } @@ -377,6 +378,7 @@ status_t AudioRecord::getMarkerPosition(uint32_t *marker) const status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod) { + // The only purpose of setting position update period is to get a callback if (mCbf == NULL) { return INVALID_OPERATION; } @@ -770,7 +772,7 @@ nsecs_t AudioRecord::processAudioBuffer() int32_t sequence = mSequence; // These fields don't need to be cached, because they are assigned only by set(): - // mTransfer, mCbf, mUserData, mSampleRate + // mTransfer, mCbf, mUserData, mSampleRate, mFrameSize mLock.unlock(); @@ -844,8 +846,8 @@ nsecs_t AudioRecord::processAudioBuffer() "obtainBuffer() err=%d frameCount=%u", err, audioBuffer.frameCount); requested = &ClientProxy::kNonBlocking; size_t avail = audioBuffer.frameCount + nonContig; - ALOGV("obtainBuffer(%u) returned %u = %u + %u", - mRemainingFrames, avail, audioBuffer.frameCount, nonContig); + ALOGV("obtainBuffer(%u) returned %u = %u + %u err %d", + mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err); if (err != NO_ERROR) { if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR) { break; diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 8954d9f..8aa0126 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -355,7 +355,7 @@ status_t AudioTrack::set( mAudioTrackThread->requestExitAndWait(); mAudioTrackThread.clear(); } - //Use of direct and offloaded output streams is ref counted by audio policy manager. + // Use of direct and offloaded output streams is ref counted by audio policy manager. // As getOutput was called above and resulted in an output stream to be opened, // we need to release it. AudioSystem::releaseOutput(output); @@ -698,6 +698,7 @@ status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod) AutoMutex lock(mLock); mNewPosition = mProxy->getPosition() + updatePeriod; mUpdatePeriod = updatePeriod; + return NO_ERROR; } @@ -1735,7 +1736,7 @@ status_t AudioTrack::restoreTrack_l(const char *from) } } if (result != NO_ERROR) { - //Use of direct and offloaded output streams is ref counted by audio policy manager. + // Use of direct and offloaded output streams is ref counted by audio policy manager. // As getOutput was called above and resulted in an output stream to be opened, // we need to release it. AudioSystem::releaseOutput(output); -- cgit v1.1 From 5f972c031d4061f4f037c9fda1ea4bd9b6a756cd Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 13 Jan 2014 09:59:31 -0800 Subject: AudioRecord::getInputFramesLost() cleanup Fixed bug that if the binder call failed (for example if the IAudioFlinger binder is dead), then getInputFramesLost was returning garbage. Now it correctly returns zero, which is the error value for this method. The type declarations for getInputFramesLost were inconsistent: a mixture of unsigned int, size_t, and uint32_t. Now it returns uint32_t everywhere, which is what the underlying HAL API returns. Added a FIXME about the side effect behavior. This will need review for multi-client. Change-Id: Ifa2e117a87dbd0c1f2c892a31d1c3dd919bf1a0a --- media/libmedia/AudioRecord.cpp | 2 +- media/libmedia/AudioSystem.cpp | 4 ++-- media/libmedia/IAudioFlinger.cpp | 11 +++++++---- media/libstagefright/AudioSource.cpp | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index e39a475..0a728a8 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -412,7 +412,7 @@ status_t AudioRecord::getPosition(uint32_t *position) const return NO_ERROR; } -unsigned int AudioRecord::getInputFramesLost() const +uint32_t AudioRecord::getInputFramesLost() const { // no need to check mActive, because if inactive this will return 0, which is what we want return AudioSystem::getInputFramesLost(getInput()); diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 4580030..2188cac 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -413,9 +413,9 @@ status_t AudioSystem::getRenderPosition(audio_io_handle_t output, size_t *halFra return af->getRenderPosition(halFrames, dspFrames, output); } -size_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) { +uint32_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) { const sp& af = AudioSystem::get_audio_flinger(); - unsigned int result = 0; + uint32_t result = 0; if (af == 0) return result; if (ioHandle == 0) return result; diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index c9c8d58..3aaff88 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -564,13 +564,16 @@ public: return status; } - virtual size_t getInputFramesLost(audio_io_handle_t ioHandle) const + virtual uint32_t getInputFramesLost(audio_io_handle_t ioHandle) const { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInt32((int32_t) ioHandle); - remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply); - return reply.readInt32(); + status_t status = remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply); + if (status != NO_ERROR) { + return 0; + } + return (uint32_t) reply.readInt32(); } virtual int newAudioSessionId() @@ -1044,7 +1047,7 @@ status_t BnAudioFlinger::onTransact( case GET_INPUT_FRAMES_LOST: { CHECK_INTERFACE(IAudioFlinger, data, reply); audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32(); - reply->writeInt32(getInputFramesLost(ioHandle)); + reply->writeInt32((int32_t) getInputFramesLost(ioHandle)); return NO_ERROR; } break; case NEW_AUDIO_SESSION_ID: { diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index d7223d9..cadadc8 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -278,7 +278,7 @@ status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) { // Drop retrieved and previously lost audio data. if (mNumFramesReceived == 0 && timeUs < mStartTimeUs) { - mRecord->getInputFramesLost(); + (void) mRecord->getInputFramesLost(); ALOGV("Drop audio data at %lld/%lld us", timeUs, mStartTimeUs); return OK; } -- cgit v1.1 From 8ff50e7526d24aca11713006933b8dcb64ef6be9 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 14 Jan 2014 15:44:30 -0800 Subject: Use uint32_t sequence numbers for IAudioRecord This makes it the same as for IAudioTrack. Previously we had a mix of int, int32_t and uint32_t, which could cause comparisons to fail. Change-Id: Ic72ef650ee81f65db11e42ed16d818fdf3e310f4 --- media/libmedia/AudioRecord.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index e39a475..076404b 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -767,7 +767,7 @@ nsecs_t AudioRecord::processAudioBuffer() mRetryOnPartialBuffer = false; } size_t misalignment = mProxy->getMisalignment(); - int32_t sequence = mSequence; + uint32_t sequence = mSequence; // These fields don't need to be cached, because they are assigned only by set(): // mTransfer, mCbf, mUserData, mSampleRate -- cgit v1.1 From 7103d9671ded507fd3f6938297019a32f71ea5a0 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 14 Jan 2014 15:47:52 -0800 Subject: Remove dead code in AudioTrack::processAudioBuffer Change-Id: I0baefe9dc08bb5ec45d34698fc764caa160789d2 --- media/libmedia/AudioTrack.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index d5e3e67..3794c84 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1610,7 +1610,6 @@ nsecs_t AudioTrack::processAudioBuffer() size_t reqSize = audioBuffer.size; mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer); size_t writtenSize = audioBuffer.size; - size_t writtenFrames = writtenSize / mFrameSize; // Sanity check on returned size if (ssize_t(writtenSize) < 0 || writtenSize > reqSize) { -- cgit v1.1 From 70c0bfbe5ec88dcc3efa2bd8df26f36cff1cf03a Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 14 Jan 2014 15:47:01 -0800 Subject: Improve logs in AudioTrack::getMinFrameCount Change-Id: I8b478e6abdded26a43f32c131931939e9ae36fd7 --- media/libmedia/AudioTrack.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index d5e3e67..a8f91ab 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -54,16 +54,22 @@ status_t AudioTrack::getMinFrameCount( status_t status; status = AudioSystem::getOutputSamplingRate(&afSampleRate, streamType); if (status != NO_ERROR) { + ALOGE("Unable to query output sample rate for stream type %d; status %d", + streamType, status); return status; } size_t afFrameCount; status = AudioSystem::getOutputFrameCount(&afFrameCount, streamType); if (status != NO_ERROR) { + ALOGE("Unable to query output frame count for stream type %d; status %d", + streamType, status); return status; } uint32_t afLatency; status = AudioSystem::getOutputLatency(&afLatency, streamType); if (status != NO_ERROR) { + ALOGE("Unable to query output latency for stream type %d; status %d", + streamType, status); return status; } -- cgit v1.1 From d8a9d0220e84ae0b5049385aa9b1a0d8ea02b5bb Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 14 Jan 2014 15:46:38 -0800 Subject: Cleanup loop termination logic in AudioRecord::obtainBuffer() Apply the same change to AudioRecord, that was already done for AudioTrack in this CL: > Change-Id: I0fc48117946364cb255afd653195498891f622bd If the proxy->obtainBuffer at the end of the "do" loop fails with status DEAD_OBJECT, and the restoreRecord_l during the next trip of the "do" loop also fails, then the value of the buffer fields will be based on the previous proxy->obtainBuffer that returned DEAD_OBJECT. This will have cleared the buffer, but it's tricky. So instead explicitly clear the buffer after restoreRecord_l, before breaking out of the loop. Change-Id: Ifc97f2ab7b8195d6b149502bb5d765d2983b07be --- media/libmedia/AudioRecord.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index e39a475..f332313 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -591,6 +591,9 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, const struct timespec *r if (newSequence == oldSequence) { status = restoreRecord_l("obtainBuffer"); if (status != NO_ERROR) { + buffer.mFrameCount = 0; + buffer.mRaw = NULL; + buffer.mNonContig = 0; break; } } -- cgit v1.1 From 5e1f79baa5c7355effbd2c9183787d6604487908 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 14 Jan 2014 15:45:21 -0800 Subject: AudioRecord: fix unwanted overrun when restarting Apply the same fix to AudioRecord as this CL did for AudioTrack: > Change-Id: Id703f8dc092a6f07c905eee194054b4a978f979d Details: When restarting an AudioRecord from stopped state, it is necessary to force refresh of mRemainingFrames by processAudioBuffer() as the last read before stop() could be partial. No doing so will lead into unnecessary sleep before filling the non contiguous part of the buffer returned by obtainBuffer() when processAudioBuffer() is executed for the first time after start(). Change-Id: I0ff04648e990e97bad5ea3db5be0c4151250d5e1 --- media/libmedia/AudioRecord.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index e39a475..3a0f222 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -289,6 +289,9 @@ status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession) // reset current position as seen by client to 0 mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition()); + // force refresh of remaining frames by processAudioBuffer() as last + // read before stop could be partial. + mRefreshRemaining = true; mNewPosition = mProxy->getPosition() + mUpdatePeriod; int32_t flags = android_atomic_acquire_load(&mCblk->mFlags); -- cgit v1.1 From 0cde076ddb283c84c3801a2df4cc3df99bd1577f Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 16 Jan 2014 15:06:36 -0800 Subject: Cleanup createTrack error handling Similar to cleanup done earlier for openRecord in this CL: > Change-Id: I84897dd7d30b370640b54e928f230604b873cb68 Bug: 10888816 Change-Id: I804a47f898e0319a60a9bd58906bbb037e45cc25 --- media/libmedia/AudioTrack.cpp | 7 ++++++- media/libmedia/IAudioFlinger.cpp | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index d5e3e67..a113f77 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1004,6 +1004,11 @@ status_t AudioTrack::createTrack_l( ALOGE("Could not get control block"); return NO_INIT; } + void *iMemPointer = iMem->pointer(); + if (iMemPointer == NULL) { + ALOGE("Could not get control block pointer"); + return NO_INIT; + } // invariant that mAudioTrack != 0 is true only after set() returns successfully if (mAudioTrack != 0) { mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this); @@ -1011,7 +1016,7 @@ status_t AudioTrack::createTrack_l( } mAudioTrack = track; mCblkMemory = iMem; - audio_track_cblk_t* cblk = static_cast(iMem->pointer()); + audio_track_cblk_t* cblk = static_cast(iMemPointer); mCblk = cblk; size_t temp = cblk->frameCount_; if (temp < frameCount || (frameCount == 0 && temp == 0)) { diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index c9c8d58..ecbb5bf 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -138,6 +138,17 @@ public: name = reply.readString8(); lStatus = reply.readInt32(); track = interface_cast(reply.readStrongBinder()); + if (lStatus == NO_ERROR) { + if (track == 0) { + ALOGE("createTrack should have returned an IAudioTrack"); + lStatus = UNKNOWN_ERROR; + } + } else { + if (track != 0) { + ALOGE("createTrack returned an IAudioTrack but with status %d", lStatus); + track.clear(); + } + } } if (status != NULL) { *status = lStatus; @@ -795,6 +806,7 @@ status_t BnAudioFlinger::onTransact( (audio_stream_type_t) streamType, sampleRate, format, channelMask, frameCount, &flags, buffer, output, tid, &sessionId, name, clientUid, &status); + LOG_ALWAYS_FATAL_IF((track != 0) != (status == NO_ERROR)); } reply->writeInt32(flags); reply->writeInt32(sessionId); -- cgit v1.1 From dd5f4c8c4059f890e81b28b026a688febb4e1dd9 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 13 Jan 2014 10:26:32 -0800 Subject: Move up initialization of mFormat, mStreamType, and mSharedBuffer earlier This will allow removal of most of the parameter list to createTrack_l. Also check for valid stream type at client so we can log a better error message. Change-Id: Ia7176896d47fbb49106119fca26d9de8e7efe859 --- media/libmedia/AudioTrack.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index a113f77..eeaab44 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -216,6 +216,7 @@ status_t AudioTrack::set( ALOGE("Invalid transfer type %d", transferType); return BAD_VALUE; } + mSharedBuffer = sharedBuffer; mTransfer = transferType; // FIXME "int" here is legacy and will be replaced by size_t later @@ -244,6 +245,11 @@ status_t AudioTrack::set( if (streamType == AUDIO_STREAM_DEFAULT) { streamType = AUDIO_STREAM_MUSIC; } + if (uint32_t(streamType) >= AUDIO_STREAM_CNT) { + ALOGE("Invalid stream type %d", streamType); + return BAD_VALUE; + } + mStreamType = streamType; status_t status; if (sampleRate == 0) { @@ -266,6 +272,7 @@ status_t AudioTrack::set( ALOGE("Invalid format %d", format); return BAD_VALUE; } + mFormat = format; if (!audio_is_output_channel(channelMask)) { ALOGE("Invalid channel mask %#x", channelMask); @@ -363,9 +370,6 @@ status_t AudioTrack::set( } mStatus = NO_ERROR; - mStreamType = streamType; - mFormat = format; - mSharedBuffer = sharedBuffer; mState = STATE_STOPPED; mUserData = user; mLoopPeriod = 0; -- cgit v1.1 From b5ccb2d99b2af400c70777a6452f090ac14f5a96 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 13 Jan 2014 14:42:43 -0800 Subject: Make copy of audio_offload_info_t for future use Change-Id: I515970aa0660418d5d1640fb1bf477e112c89bdd --- media/libmedia/AudioTrack.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index eeaab44..2cb3459 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -324,6 +324,16 @@ status_t AudioTrack::set( return BAD_VALUE; } + // Make copy of input parameter offloadInfo so that in the future: + // (a) createTrack_l doesn't need it as an input parameter + // (b) we can support re-creation of offloaded tracks + if (offloadInfo != NULL) { + mOffloadInfoCopy = *offloadInfo; + mOffloadInfo = &mOffloadInfoCopy; + } else { + mOffloadInfo = NULL; + } + mVolume[LEFT] = 1.0f; mVolume[RIGHT] = 1.0f; mSendLevel = 0.0f; -- cgit v1.1 From 7226c059cda892ffa384b455ecfc49989e9bf6f0 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Fri, 17 Jan 2014 14:46:21 -0800 Subject: Fix build. Missing vendor_tag header. --- media/mediaserver/Android.mk | 1 + 1 file changed, 1 insertion(+) (limited to 'media') diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk index 1ac647a..f848054 100644 --- a/media/mediaserver/Android.mk +++ b/media/mediaserver/Android.mk @@ -15,6 +15,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libaudioflinger \ + libcamera_metadata\ libcameraservice \ libmedialogservice \ libcutils \ -- cgit v1.1 From 4d69457c1d7f3e528455fa971c1719099d3699fc Mon Sep 17 00:00:00 2001 From: Changwan Ryu Date: Tue, 29 Oct 2013 14:31:00 +0900 Subject: Support for MPEG2 video Change-Id: If1f4e20939c96c87c65c84d56e529501facb8597 (cherry picked from commit 774eb18c40c3a7da0bc1636a9779f02315ddbad8) --- media/libstagefright/ACodec.cpp | 2 ++ media/libstagefright/OMXCodec.cpp | 2 ++ 2 files changed, 4 insertions(+) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 5d5220f..5259b7d 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -977,6 +977,8 @@ status_t ACodec::setComponentRole( "audio_decoder.flac", "audio_encoder.flac" }, { MEDIA_MIMETYPE_AUDIO_MSGSM, "audio_decoder.gsm", "audio_encoder.gsm" }, + { MEDIA_MIMETYPE_VIDEO_MPEG2, + "video_decoder.mpeg2", "video_encoder.mpeg2" }, }; static const size_t kNumMimeToRole = diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 43736ad..dec82ad 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1394,6 +1394,8 @@ void OMXCodec::setComponentRole( "audio_decoder.flac", "audio_encoder.flac" }, { MEDIA_MIMETYPE_AUDIO_MSGSM, "audio_decoder.gsm", "audio_encoder.gsm" }, + { MEDIA_MIMETYPE_VIDEO_MPEG2, + "video_decoder.mpeg2", "video_encoder.mpeg2" }, }; static const size_t kNumMimeToRole = -- cgit v1.1 From 38e905b3cbba4da443d799b16999989781afc6d8 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 13 Jan 2014 10:21:48 -0800 Subject: Refactor code related to I/O handles to reduce chance for leaks The AudioRecord input handle code was refactored earlier to fix a potential handle leak, and to simplify the code: > Change-Id: I124dce344b1d11c2dd66ca5e2c9aec0c52c230e2 This changelist refactors AudioTrack similarly, and adds further cleanup of both AudioTrack and AudioRecord. We attempt to implement the rules for referencing counting I/O handles, but there is still the possibility of a handle leak if the client process dies after allocating the handle reference but before releasing it. That issue is being tracked separately. Details: - AudioSystem::getOutput() is now called within createTrack_l - restoreTrack_l was missing offload info now it has the info available, but is not yet being called for offloaded tracks - AudioTrack::getOutput() is now const - Remove getOutput_l() Change-Id: I44a0a623d24fc5847bcac0939c276400568adbca --- media/libmedia/AudioRecord.cpp | 21 ++++++++-- media/libmedia/AudioTrack.cpp | 91 +++++++++++++++++++++++------------------- 2 files changed, 67 insertions(+), 45 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 0673079..a999e7e 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -244,7 +244,7 @@ status_t AudioRecord::set( // create the IAudioRecord status = openRecord_l(0 /*epoch*/); - if (status) { + if (status != NO_ERROR) { return status; } @@ -463,6 +463,9 @@ status_t AudioRecord::openRecord_l(size_t epoch) ALOGE("Could not get audio input for record source %d", mInputSource); return BAD_VALUE; } + { + // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger, + // we must release it ourselves if anything goes wrong. size_t temp = mFrameCount; // temp may be replaced by a revised value of frameCount, // but we will still need the original value also @@ -480,9 +483,11 @@ status_t AudioRecord::openRecord_l(size_t epoch) if (record == 0 || status != NO_ERROR) { ALOGE("AudioFlinger could not create record track, status: %d", status); - AudioSystem::releaseInput(input); - return status; + goto release; } + // AudioFlinger now owns the reference to the I/O handle, + // so we are no longer responsible for releasing it. + sp iMem = record->getCblk(); if (iMem == 0) { ALOGE("Could not get control block"); @@ -497,6 +502,8 @@ status_t AudioRecord::openRecord_l(size_t epoch) mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this); mDeathNotifier.clear(); } + + // We retain a copy of the I/O handle, but don't own the reference mInput = input; mAudioRecord = record; mCblkMemory = iMem; @@ -540,6 +547,14 @@ status_t AudioRecord::openRecord_l(size_t epoch) mAudioRecord->asBinder()->linkToDeath(mDeathNotifier, this); return NO_ERROR; + } + +release: + AudioSystem::releaseInput(input); + if (status == NO_ERROR) { + status = NO_INIT; + } + return status; } status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index c8dc38b..8e91f12 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -245,8 +245,6 @@ status_t AudioTrack::set( return INVALID_OPERATION; } - mOutput = 0; - // handle default values first. if (streamType == AUDIO_STREAM_DEFAULT) { streamType = AUDIO_STREAM_MUSIC; @@ -319,17 +317,6 @@ status_t AudioTrack::set( mFrameSizeAF = sizeof(uint8_t); } - audio_io_handle_t output = AudioSystem::getOutput( - streamType, - sampleRate, format, channelMask, - flags, - offloadInfo); - - if (output == 0) { - ALOGE("Could not get audio output for stream type %d", streamType); - return BAD_VALUE; - } - // Make copy of input parameter offloadInfo so that in the future: // (a) createTrack_l doesn't need it as an input parameter // (b) we can support re-creation of offloaded tracks @@ -369,7 +356,6 @@ status_t AudioTrack::set( frameCount, flags, sharedBuffer, - output, 0 /*epoch*/); if (status != NO_ERROR) { @@ -379,9 +365,15 @@ status_t AudioTrack::set( mAudioTrackThread.clear(); } // Use of direct and offloaded output streams is ref counted by audio policy manager. +#if 0 // FIXME This should no longer be needed + //Use of direct and offloaded output streams is ref counted by audio policy manager. // As getOutput was called above and resulted in an output stream to be opened, // we need to release it. - AudioSystem::releaseOutput(output); + if (mOutput != 0) { + AudioSystem::releaseOutput(mOutput); + mOutput = 0; + } +#endif return status; } @@ -397,7 +389,6 @@ status_t AudioTrack::set( mSequence = 1; mObservedSequence = mSequence; mInUnderrun = false; - mOutput = output; return NO_ERROR; } @@ -821,23 +812,12 @@ status_t AudioTrack::reload() return NO_ERROR; } -audio_io_handle_t AudioTrack::getOutput() +audio_io_handle_t AudioTrack::getOutput() const { AutoMutex lock(mLock); return mOutput; } -// must be called with mLock held -audio_io_handle_t AudioTrack::getOutput_l() -{ - if (mOutput) { - return mOutput; - } else { - return AudioSystem::getOutput(mStreamType, - mSampleRate, mFormat, mChannelMask, mFlags); - } -} - status_t AudioTrack::attachAuxEffect(int effectId) { AutoMutex lock(mLock); @@ -858,7 +838,6 @@ status_t AudioTrack::createTrack_l( size_t frameCount, audio_output_flags_t flags, const sp& sharedBuffer, - audio_io_handle_t output, size_t epoch) { status_t status; @@ -868,27 +847,39 @@ status_t AudioTrack::createTrack_l( return NO_INIT; } + audio_io_handle_t output = AudioSystem::getOutput(mStreamType, mSampleRate, mFormat, + mChannelMask, mFlags, mOffloadInfo); + if (output == 0) { + ALOGE("Could not get audio output for stream type %d, sample rate %u, format %#x, " + "channel mask %#x, flags %#x", + mStreamType, mSampleRate, mFormat, mChannelMask, mFlags); + return BAD_VALUE; + } + { + // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger, + // we must release it ourselves if anything goes wrong. + // Not all of these values are needed under all conditions, but it is easier to get them all uint32_t afLatency; status = AudioSystem::getLatency(output, streamType, &afLatency); if (status != NO_ERROR) { ALOGE("getLatency(%d) failed status %d", output, status); - return NO_INIT; + goto release; } size_t afFrameCount; status = AudioSystem::getFrameCount(output, streamType, &afFrameCount); if (status != NO_ERROR) { ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, streamType, status); - return NO_INIT; + goto release; } uint32_t afSampleRate; status = AudioSystem::getSamplingRate(output, streamType, &afSampleRate); if (status != NO_ERROR) { ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, streamType, status); - return NO_INIT; + goto release; } // Client decides whether the track is TIMED (see below), but can only express a preference @@ -940,7 +931,8 @@ status_t AudioTrack::createTrack_l( if (((size_t)sharedBuffer->pointer() & (alignment - 1)) != 0) { ALOGE("Invalid buffer alignment: address %p, channel count %u", sharedBuffer->pointer(), mChannelCount); - return BAD_VALUE; + status = BAD_VALUE; + goto release; } // When initializing a shared buffer AudioTrack via constructors, @@ -1020,8 +1012,11 @@ status_t AudioTrack::createTrack_l( if (track == 0) { ALOGE("AudioFlinger could not create track, status: %d", status); - return status; + goto release; } + // AudioFlinger now owns the reference to the I/O handle, + // so we are no longer responsible for releasing it. + sp iMem = track->getCblk(); if (iMem == 0) { ALOGE("Could not get control block"); @@ -1081,10 +1076,13 @@ status_t AudioTrack::createTrack_l( ALOGW("AUDIO_OUTPUT_FLAG_OFFLOAD denied by server"); flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD); mFlags = flags; - return NO_INIT; + // FIXME This is a warning, not an error, so don't return error status + //return NO_INIT; } } + // We retain a copy of the I/O handle, but don't own the reference + mOutput = output; mRefreshRemaining = true; // Starting address of buffers in shared memory. If there is a shared buffer, buffers @@ -1127,6 +1125,14 @@ status_t AudioTrack::createTrack_l( mAudioTrack->asBinder()->linkToDeath(mDeathNotifier, this); return NO_ERROR; + } + +release: + AudioSystem::releaseOutput(output); + if (status == NO_ERROR) { + status = NO_INIT; + } + return status; } status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) @@ -1708,7 +1714,7 @@ status_t AudioTrack::restoreTrack_l(const char *from) status_t result; // refresh the audio configuration cache in this process to make sure we get new - // output parameters in getOutput_l() and createTrack_l() + // output parameters in createTrack_l() AudioSystem::clearAudioConfigCache(); if (isOffloaded_l()) { @@ -1716,10 +1722,6 @@ status_t AudioTrack::restoreTrack_l(const char *from) return DEAD_OBJECT; } - // force new output query from audio policy manager; - mOutput = 0; - audio_io_handle_t output = getOutput_l(); - // if the new IAudioTrack is created, createTrack_l() will modify the // following member variables: mAudioTrack, mCblkMemory and mCblk. // It will also delete the strong references on previous IAudioTrack and IMemory @@ -1733,7 +1735,6 @@ status_t AudioTrack::restoreTrack_l(const char *from) mReqFrameCount, // so that frame count never goes down mFlags, mSharedBuffer, - output, position /*epoch*/); if (result == NO_ERROR) { @@ -1763,9 +1764,15 @@ status_t AudioTrack::restoreTrack_l(const char *from) } if (result != NO_ERROR) { // Use of direct and offloaded output streams is ref counted by audio policy manager. +#if 0 // FIXME This should no longer be needed + //Use of direct and offloaded output streams is ref counted by audio policy manager. // As getOutput was called above and resulted in an output stream to be opened, // we need to release it. - AudioSystem::releaseOutput(output); + if (mOutput != 0) { + AudioSystem::releaseOutput(mOutput); + mOutput = 0; + } +#endif ALOGW("restoreTrack_l() failed status %d", result); mState = STATE_STOPPED; } -- cgit v1.1 From 363fb75db26698cbb50065506e0c80b61d1fbf92 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 15 Jan 2014 12:27:31 -0800 Subject: Remove the redundant parameters from createTrack_l() AudioRecord::openRecord_l() code was refactored earlier to remove the redundant parameters: > Change-Id: I124dce344b1d11c2dd66ca5e2c9aec0c52c230e2 This changelist refactors AudioTrack similarly. Change-Id: Iefd2bd662870ea81d04eff7b7c26f9c8b0dadd26 --- media/libmedia/AudioTrack.cpp | 103 +++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 62 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 8e91f12..f61a265 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -350,13 +350,7 @@ status_t AudioTrack::set( } // create the IAudioTrack - status = createTrack_l(streamType, - sampleRate, - format, - frameCount, - flags, - sharedBuffer, - 0 /*epoch*/); + status = createTrack_l(0 /*epoch*/); if (status != NO_ERROR) { if (mAudioTrackThread != 0) { @@ -831,14 +825,7 @@ status_t AudioTrack::attachAuxEffect(int effectId) // ------------------------------------------------------------------------- // must be called with mLock held -status_t AudioTrack::createTrack_l( - audio_stream_type_t streamType, - uint32_t sampleRate, - audio_format_t format, - size_t frameCount, - audio_output_flags_t flags, - const sp& sharedBuffer, - size_t epoch) +status_t AudioTrack::createTrack_l(size_t epoch) { status_t status; const sp& audioFlinger = AudioSystem::get_audio_flinger(); @@ -862,38 +849,37 @@ status_t AudioTrack::createTrack_l( // Not all of these values are needed under all conditions, but it is easier to get them all uint32_t afLatency; - status = AudioSystem::getLatency(output, streamType, &afLatency); + status = AudioSystem::getLatency(output, mStreamType, &afLatency); if (status != NO_ERROR) { ALOGE("getLatency(%d) failed status %d", output, status); goto release; } size_t afFrameCount; - status = AudioSystem::getFrameCount(output, streamType, &afFrameCount); + status = AudioSystem::getFrameCount(output, mStreamType, &afFrameCount); if (status != NO_ERROR) { - ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, streamType, status); + ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, mStreamType, status); goto release; } uint32_t afSampleRate; - status = AudioSystem::getSamplingRate(output, streamType, &afSampleRate); + status = AudioSystem::getSamplingRate(output, mStreamType, &afSampleRate); if (status != NO_ERROR) { - ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, streamType, status); + ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, mStreamType, status); goto release; } // Client decides whether the track is TIMED (see below), but can only express a preference // for FAST. Server will perform additional tests. - if ((flags & AUDIO_OUTPUT_FLAG_FAST) && !( + if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) && !( // either of these use cases: // use case 1: shared buffer - (sharedBuffer != 0) || + (mSharedBuffer != 0) || // use case 2: callback handler (mCbf != NULL))) { ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client"); // once denied, do not request again if IAudioTrack is re-created - flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST); - mFlags = flags; + mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST); } ALOGV("createTrack_l() output %d afLatency %d", output, afLatency); @@ -904,33 +890,34 @@ status_t AudioTrack::createTrack_l( // n = 3 normal track, with sample rate conversion // (pessimistic; some non-1:1 conversion ratios don't actually need triple-buffering) // n > 3 very high latency or very small notification interval; nBuffering is ignored - const uint32_t nBuffering = (sampleRate == afSampleRate) ? 2 : 3; + const uint32_t nBuffering = (mSampleRate == afSampleRate) ? 2 : 3; mNotificationFramesAct = mNotificationFramesReq; - if (!audio_is_linear_pcm(format)) { + size_t frameCount = mReqFrameCount; + if (!audio_is_linear_pcm(mFormat)) { - if (sharedBuffer != 0) { + if (mSharedBuffer != 0) { // Same comment as below about ignoring frameCount parameter for set() - frameCount = sharedBuffer->size(); + frameCount = mSharedBuffer->size(); } else if (frameCount == 0) { frameCount = afFrameCount; } if (mNotificationFramesAct != frameCount) { mNotificationFramesAct = frameCount; } - } else if (sharedBuffer != 0) { + } else if (mSharedBuffer != 0) { // Ensure that buffer alignment matches channel count // 8-bit data in shared memory is not currently supported by AudioFlinger - size_t alignment = /* format == AUDIO_FORMAT_PCM_8_BIT ? 1 : */ 2; + size_t alignment = /* mFormat == AUDIO_FORMAT_PCM_8_BIT ? 1 : */ 2; if (mChannelCount > 1) { // More than 2 channels does not require stronger alignment than stereo alignment <<= 1; } - if (((size_t)sharedBuffer->pointer() & (alignment - 1)) != 0) { + if (((size_t)mSharedBuffer->pointer() & (alignment - 1)) != 0) { ALOGE("Invalid buffer alignment: address %p, channel count %u", - sharedBuffer->pointer(), mChannelCount); + mSharedBuffer->pointer(), mChannelCount); status = BAD_VALUE; goto release; } @@ -939,9 +926,9 @@ status_t AudioTrack::createTrack_l( // there's no frameCount parameter. // But when initializing a shared buffer AudioTrack via set(), // there _is_ a frameCount parameter. We silently ignore it. - frameCount = sharedBuffer->size()/mChannelCount/sizeof(int16_t); + frameCount = mSharedBuffer->size()/mChannelCount/sizeof(int16_t); - } else if (!(flags & AUDIO_OUTPUT_FLAG_FAST)) { + } else if (!(mFlags & AUDIO_OUTPUT_FLAG_FAST)) { // FIXME move these calculations and associated checks to server @@ -953,10 +940,10 @@ status_t AudioTrack::createTrack_l( minBufCount = nBuffering; } - size_t minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate; + size_t minFrameCount = (afFrameCount*mSampleRate*minBufCount)/afSampleRate; ALOGV("minFrameCount: %u, afFrameCount=%d, minBufCount=%d, sampleRate=%u, afSampleRate=%u" ", afLatency=%d", - minFrameCount, afFrameCount, minBufCount, sampleRate, afSampleRate, afLatency); + minFrameCount, afFrameCount, minBufCount, mSampleRate, afSampleRate, afLatency); if (frameCount == 0) { frameCount = minFrameCount; @@ -981,28 +968,28 @@ status_t AudioTrack::createTrack_l( } pid_t tid = -1; - if (flags & AUDIO_OUTPUT_FLAG_FAST) { + if (mFlags & AUDIO_OUTPUT_FLAG_FAST) { trackFlags |= IAudioFlinger::TRACK_FAST; if (mAudioTrackThread != 0) { tid = mAudioTrackThread->getTid(); } } - if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { + if (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { trackFlags |= IAudioFlinger::TRACK_OFFLOAD; } size_t temp = frameCount; // temp may be replaced by a revised value of frameCount, // but we will still need the original value also - sp track = audioFlinger->createTrack(streamType, - sampleRate, + sp track = audioFlinger->createTrack(mStreamType, + mSampleRate, // AudioFlinger only sees 16-bit PCM - format == AUDIO_FORMAT_PCM_8_BIT ? - AUDIO_FORMAT_PCM_16_BIT : format, + mFormat == AUDIO_FORMAT_PCM_8_BIT ? + AUDIO_FORMAT_PCM_16_BIT : mFormat, mChannelMask, &temp, &trackFlags, - sharedBuffer, + mSharedBuffer, output, tid, &mSessionId, @@ -1045,11 +1032,11 @@ status_t AudioTrack::createTrack_l( } frameCount = temp; mAwaitBoost = false; - if (flags & AUDIO_OUTPUT_FLAG_FAST) { + if (mFlags & AUDIO_OUTPUT_FLAG_FAST) { if (trackFlags & IAudioFlinger::TRACK_FAST) { ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %u", frameCount); mAwaitBoost = true; - if (sharedBuffer == 0) { + if (mSharedBuffer == 0) { // Theoretically double-buffering is not required for fast tracks, // due to tighter scheduling. But in practice, to accommodate kernels with // scheduling jitter, and apps with computation jitter, we use double-buffering. @@ -1060,22 +1047,20 @@ status_t AudioTrack::createTrack_l( } else { ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %u", frameCount); // once denied, do not request again if IAudioTrack is re-created - flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST); - mFlags = flags; - if (sharedBuffer == 0) { + mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST); + if (mSharedBuffer == 0) { if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/nBuffering) { mNotificationFramesAct = frameCount/nBuffering; } } } } - if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { + if (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { if (trackFlags & IAudioFlinger::TRACK_OFFLOAD) { ALOGV("AUDIO_OUTPUT_FLAG_OFFLOAD successful"); } else { ALOGW("AUDIO_OUTPUT_FLAG_OFFLOAD denied by server"); - flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD); - mFlags = flags; + mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD); // FIXME This is a warning, not an error, so don't return error status //return NO_INIT; } @@ -1090,15 +1075,15 @@ status_t AudioTrack::createTrack_l( // immediately after the control block. This address is for the mapping within client // address space. AudioFlinger::TrackBase::mBuffer is for the server address space. void* buffers; - if (sharedBuffer == 0) { + if (mSharedBuffer == 0) { buffers = (char*)cblk + sizeof(audio_track_cblk_t); } else { - buffers = sharedBuffer->pointer(); + buffers = mSharedBuffer->pointer(); } mAudioTrack->attachAuxEffect(mAuxEffectId); // FIXME don't believe this lie - mLatency = afLatency + (1000*frameCount) / sampleRate; + mLatency = afLatency + (1000*frameCount) / mSampleRate; mFrameCount = frameCount; // If IAudioTrack is re-created, don't let the requested frameCount // decrease. This can confuse clients that cache frameCount(). @@ -1107,7 +1092,7 @@ status_t AudioTrack::createTrack_l( } // update proxy - if (sharedBuffer == 0) { + if (mSharedBuffer == 0) { mStaticProxy.clear(); mProxy = new AudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF); } else { @@ -1729,13 +1714,7 @@ status_t AudioTrack::restoreTrack_l(const char *from) // take the frames that will be lost by track recreation into account in saved position size_t position = mProxy->getPosition() + mProxy->getFramesFilled(); size_t bufferPosition = mStaticProxy != NULL ? mStaticProxy->getBufferPosition() : 0; - result = createTrack_l(mStreamType, - mSampleRate, - mFormat, - mReqFrameCount, // so that frame count never goes down - mFlags, - mSharedBuffer, - position /*epoch*/); + result = createTrack_l(position /*epoch*/); if (result == NO_ERROR) { // continue playback from last known position, but -- cgit v1.1 From 625b93f1971039a547b239f87a2dc8a8d5716589 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 23 Jan 2014 14:16:32 -0800 Subject: Fixed misplaced bracket for switch-case block. Change-Id: I66b410e1e19601ad65d8357bda4c0c58e2dc15dc --- media/libstagefright/ACodec.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index eb274a8..173d77f 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -3318,11 +3318,11 @@ void ACodec::BaseState::onInputBufferFilled(const sp &msg) { mCodec->mInputEOSResult = err; } break; - - default: - CHECK_EQ((int)mode, (int)FREE_BUFFERS); - break; } + + default: + CHECK_EQ((int)mode, (int)FREE_BUFFERS); + break; } } -- cgit v1.1 From df576995a5aad3428aeeef765387d650945c161d Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Mon, 27 Jan 2014 18:13:39 -0800 Subject: AudioTrack: fix obtainBuffer timeout calculation AudioTrack::obtainBuffer() passes a pointer to a timeout variable that has gone out of scope when calling ClientProxy::obtainBuffer(). Same fix for AudioRecord. Bug: 11968591. Change-Id: I22af8f94fa2f8cc54ab5c25c89167c805e754317 --- media/libmedia/AudioRecord.cpp | 2 +- media/libmedia/AudioTrack.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index a999e7e..b69e3ae 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -570,13 +570,13 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) } const struct timespec *requested; + struct timespec timeout; if (waitCount == -1) { requested = &ClientProxy::kForever; } else if (waitCount == 0) { requested = &ClientProxy::kNonBlocking; } else if (waitCount > 0) { long long ms = WAIT_PERIOD_MS * (long long) waitCount; - struct timespec timeout; timeout.tv_sec = ms / 1000; timeout.tv_nsec = (int) (ms % 1000) * 1000000; requested = &timeout; diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index f61a265..cfd79bc 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1133,13 +1133,13 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) } const struct timespec *requested; + struct timespec timeout; if (waitCount == -1) { requested = &ClientProxy::kForever; } else if (waitCount == 0) { requested = &ClientProxy::kNonBlocking; } else if (waitCount > 0) { long long ms = WAIT_PERIOD_MS * (long long) waitCount; - struct timespec timeout; timeout.tv_sec = ms / 1000; timeout.tv_nsec = (int) (ms % 1000) * 1000000; requested = &timeout; -- cgit v1.1 From 49270665e7a20cd120724fc388da8b166ff0b4f1 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Fri, 17 Jan 2014 16:29:59 -0800 Subject: save mGraphicBuffer pointer even when we're suspended Bug: 12609966 Change-Id: Ifd41fd973876da69039113fcaeacdccf39472b37 --- media/libstagefright/omx/GraphicBufferSource.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'media') diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index b8970ad..7492577 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -609,6 +609,12 @@ void GraphicBufferSource::onFrameAvailable() { BufferQueue::BufferItem item; status_t err = mBufferQueue->acquireBuffer(&item, 0); if (err == OK) { + // If this is the first time we're seeing this buffer, add it to our + // slot table. + if (item.mGraphicBuffer != NULL) { + ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf); + mBufferSlot[item.mBuf] = item.mGraphicBuffer; + } mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); } -- cgit v1.1 From fdac7c00f9201bb3a9862069145f01d37e39755b Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 28 Jan 2014 11:03:28 -0800 Subject: Replace size_t in shared memory by uint32_t Eventually we may want to use uint64_t, but will need to confirm atomicity. Bug: 12381724 Change-Id: Ia2c591d262d22b47b6f7dab4b9d9faa14b86d865 --- media/libmedia/AudioTrackShared.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index 21018a0..fdd1a12 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -475,9 +475,14 @@ void StaticAudioTrackClientProxy::flush() void StaticAudioTrackClientProxy::setLoop(size_t loopStart, size_t loopEnd, int loopCount) { + // This can only happen on a 64-bit client + if (loopStart > UINT32_MAX || loopEnd > UINT32_MAX) { + // FIXME Should return an error status + return; + } StaticAudioTrackState newState; - newState.mLoopStart = loopStart; - newState.mLoopEnd = loopEnd; + newState.mLoopStart = (uint32_t) loopStart; + newState.mLoopEnd = (uint32_t) loopEnd; newState.mLoopCount = loopCount; mBufferPosition = loopStart; (void) mMutator.push(newState); @@ -487,7 +492,7 @@ size_t StaticAudioTrackClientProxy::getBufferPosition() { size_t bufferPosition; if (mMutator.ack()) { - bufferPosition = mCblk->u.mStatic.mBufferPosition; + bufferPosition = (size_t) mCblk->u.mStatic.mBufferPosition; if (bufferPosition > mFrameCount) { bufferPosition = mFrameCount; } @@ -622,7 +627,7 @@ void ServerProxy::releaseBuffer(Buffer* buffer) if (half == 0) { half = 1; } - size_t minimum = cblk->mMinimum; + size_t minimum = (size_t) cblk->mMinimum; if (minimum == 0) { minimum = mIsOut ? half : 1; } else if (minimum > half) { @@ -760,7 +765,8 @@ ssize_t StaticAudioTrackServerProxy::pollPosition() mIsShutdown = true; return (ssize_t) NO_INIT; } - mCblk->u.mStatic.mBufferPosition = position; + // This may overflow, but client is not supposed to rely on it + mCblk->u.mStatic.mBufferPosition = (uint32_t) position; } return (ssize_t) position; } @@ -836,7 +842,8 @@ void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer) mPosition = newPosition; cblk->mServer += stepCount; - cblk->u.mStatic.mBufferPosition = newPosition; + // This may overflow, but client is not supposed to rely on it + cblk->u.mStatic.mBufferPosition = (uint32_t) newPosition; if (setFlags != 0) { (void) android_atomic_or(setFlags, &cblk->mFlags); // this would be a good place to wake a futex -- cgit v1.1 From ef8adf8ce4ece039a839f42a22b436d8ae077f37 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 23 Jan 2014 15:00:53 -0800 Subject: stagefright: use CODECS field in EXT-X_STREAM-INF as fallback Use the CODECS field in EXT-X-STREAM-INF as a viable fallback for identifying available streams in a variant playlist. Change-Id: I5011809dc7c56220b023eb1a16f2d6a392ddd6f1 --- media/libstagefright/httplive/M3UParser.cpp | 160 ++++++++++++++++++++++++++-- media/libstagefright/httplive/M3UParser.h | 4 + 2 files changed, 157 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 243888c..ae19ffa 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include namespace android { @@ -352,9 +353,27 @@ bool M3UParser::getTypeURI(size_t index, const char *key, AString *uri) const { if (!meta->findString(key, &groupID)) { *uri = mItems.itemAt(index).mURI; - // Assume media without any more specific attribute contains - // audio and video, but no subtitles. - return !strcmp("audio", key) || !strcmp("video", key); + AString codecs; + if (!meta->findString("codecs", &codecs)) { + // Assume media without any more specific attribute contains + // audio and video, but no subtitles. + return !strcmp("audio", key) || !strcmp("video", key); + } else { + // Split the comma separated list of codecs. + size_t offset = 0; + ssize_t commaPos = -1; + codecs.append(','); + while ((commaPos = codecs.find(",", offset)) >= 0) { + AString codec(codecs, offset, commaPos - offset); + // return true only if a codec of type `key` ("audio"/"video") + // is found. + if (codecIsType(codec, key)) { + return true; + } + offset = commaPos + 1; + } + return false; + } } sp group = mMediaGroups.valueFor(groupID); @@ -684,12 +703,22 @@ status_t M3UParser::parseStreamInf( *meta = new AMessage; } (*meta)->setInt32("bandwidth", x); + } else if (!strcasecmp("codecs", key.c_str())) { + if (!isQuotedString(val)) { + ALOGE("Expected quoted string for %s attribute, " + "got '%s' instead.", + key.c_str(), val.c_str());; + + return ERROR_MALFORMED; + } + + key.tolower(); + const AString &codecs = unquoteString(val); + (*meta)->setString(key.c_str(), codecs.c_str()); } else if (!strcasecmp("audio", key.c_str()) || !strcasecmp("video", key.c_str()) || !strcasecmp("subtitles", key.c_str())) { - if (val.size() < 2 - || val.c_str()[0] != '"' - || val.c_str()[val.size() - 1] != '"') { + if (!isQuotedString(val)) { ALOGE("Expected quoted string for %s attribute, " "got '%s' instead.", key.c_str(), val.c_str()); @@ -697,7 +726,7 @@ status_t M3UParser::parseStreamInf( return ERROR_MALFORMED; } - AString groupID(val, 1, val.size() - 2); + const AString &groupID = unquoteString(val); ssize_t groupIndex = mMediaGroups.indexOfKey(groupID); if (groupIndex < 0) { @@ -1086,4 +1115,121 @@ status_t M3UParser::ParseDouble(const char *s, double *x) { return OK; } +// static +bool M3UParser::isQuotedString(const AString &str) { + if (str.size() < 2 + || str.c_str()[0] != '"' + || str.c_str()[str.size() - 1] != '"') { + return false; + } + return true; +} + +// static +AString M3UParser::unquoteString(const AString &str) { + if (!isQuotedString(str)) { + return str; + } + return AString(str, 1, str.size() - 2); +} + +// static +bool M3UParser::codecIsType(const AString &codec, const char *type) { + if (codec.size() < 4) { + return false; + } + const char *c = codec.c_str(); + switch (FOURCC(c[0], c[1], c[2], c[3])) { + // List extracted from http://www.mp4ra.org/codecs.html + case 'ac-3': + case 'alac': + case 'dra1': + case 'dtsc': + case 'dtse': + case 'dtsh': + case 'dtsl': + case 'ec-3': + case 'enca': + case 'g719': + case 'g726': + case 'm4ae': + case 'mlpa': + case 'mp4a': + case 'raw ': + case 'samr': + case 'sawb': + case 'sawp': + case 'sevc': + case 'sqcp': + case 'ssmv': + case 'twos': + case 'agsm': + case 'alaw': + case 'dvi ': + case 'fl32': + case 'fl64': + case 'ima4': + case 'in24': + case 'in32': + case 'lpcm': + case 'Qclp': + case 'QDM2': + case 'QDMC': + case 'ulaw': + case 'vdva': + return !strcmp("audio", type); + + case 'avc1': + case 'avc2': + case 'avcp': + case 'drac': + case 'encv': + case 'mjp2': + case 'mp4v': + case 'mvc1': + case 'mvc2': + case 'resv': + case 's263': + case 'svc1': + case 'vc-1': + case 'CFHD': + case 'civd': + case 'DV10': + case 'dvh5': + case 'dvh6': + case 'dvhp': + case 'DVOO': + case 'DVOR': + case 'DVTV': + case 'DVVT': + case 'flic': + case 'gif ': + case 'h261': + case 'h263': + case 'HD10': + case 'jpeg': + case 'M105': + case 'mjpa': + case 'mjpb': + case 'png ': + case 'PNTG': + case 'rle ': + case 'rpza': + case 'Shr0': + case 'Shr1': + case 'Shr2': + case 'Shr3': + case 'Shr4': + case 'SVQ1': + case 'SVQ3': + case 'tga ': + case 'tiff': + case 'WRLE': + return !strcmp("video", type); + + default: + return false; + } +} + } // namespace android diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h index 5248004..b93b0e5 100644 --- a/media/libstagefright/httplive/M3UParser.h +++ b/media/libstagefright/httplive/M3UParser.h @@ -100,6 +100,10 @@ private: static status_t ParseInt32(const char *s, int32_t *x); static status_t ParseDouble(const char *s, double *x); + static bool isQuotedString(const AString &str); + static AString unquoteString(const AString &str); + static bool codecIsType(const AString &codec, const char *type); + DISALLOW_EVIL_CONSTRUCTORS(M3UParser); }; -- cgit v1.1 From 75832930a28fd70f6fc683ed966477ceea810668 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 23 Jan 2014 15:26:43 -0800 Subject: Added support to query ACodec whether adaptive playback is enabled. Change-Id: I6b0308aa8550c643706959277e46dad586c37297 --- media/libstagefright/ACodec.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 173d77f..a990273 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -365,6 +365,7 @@ ACodec::ACodec() mIsEncoder(false), mUseMetadataOnEncoderOutput(false), mShutdownInProgress(false), + mIsConfiguredForAdaptivePlayback(false), mEncoderDelay(0), mEncoderPadding(0), mChannelMaskPresent(false), @@ -1121,6 +1122,7 @@ status_t ACodec::configureCodec( int32_t haveNativeWindow = msg->findObject("native-window", &obj) && obj != NULL; mStoreMetaDataInOutputBuffers = false; + mIsConfiguredForAdaptivePlayback = false; if (!encoder && video && haveNativeWindow) { err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_TRUE); if (err != OK) { @@ -1165,12 +1167,14 @@ status_t ACodec::configureCodec( ALOGW_IF(err != OK, "[%s] prepareForAdaptivePlayback failed w/ err %d", mComponentName.c_str(), err); + mIsConfiguredForAdaptivePlayback = (err == OK); } // allow failure err = OK; } else { ALOGV("[%s] storeMetaDataInBuffers succeeded", mComponentName.c_str()); mStoreMetaDataInOutputBuffers = true; + mIsConfiguredForAdaptivePlayback = true; } int32_t push; @@ -3773,6 +3777,7 @@ void ACodec::LoadedState::stateEntered() { mCodec->mDequeueCounter = 0; mCodec->mMetaDataBuffersToSubmit = 0; mCodec->mRepeatFrameDelayUs = -1ll; + mCodec->mIsConfiguredForAdaptivePlayback = false; if (mCodec->mShutdownInProgress) { bool keepComponentAllocated = mCodec->mKeepComponentAllocated; -- cgit v1.1 From 8284de3be2ac07d8774b15e6565df5aba084db04 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 29 Jan 2014 17:02:02 -0800 Subject: MPEG4Writer: use "mp42" as major/minor brand in ftyp box. Bug: 12783430 Change-Id: I7c8029de1db21fcac0ce3e4505661189535c45f1 --- media/libstagefright/MPEG4Writer.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index a0f17b5..b7a4b75 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -972,13 +972,16 @@ void MPEG4Writer::writeFtypBox(MetaData *param) { if (param && param->findInt32(kKeyFileType, &fileType) && fileType != OUTPUT_FORMAT_MPEG_4) { writeFourcc("3gp4"); + writeInt32(0); + writeFourcc("isom"); + writeFourcc("3gp4"); } else { + writeFourcc("mp42"); + writeInt32(0); writeFourcc("isom"); + writeFourcc("mp42"); } - writeInt32(0); - writeFourcc("isom"); - writeFourcc("3gp4"); endBox(); } -- cgit v1.1 From 94ee4b708acfa941581160b267afb79192b1d816 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Fri, 10 Jan 2014 17:36:57 -0800 Subject: Cap pts gap between adjacent frames to specified value - In the scenario of cast mirroring, encoding could be suspended for prolonged periods. Limiting the pts gap to workaround the problem where encoder's rate control logic produces huge frames after a long period of suspension. - Repeat last frame a couple more times to get better quality on static scenes. - Fix the timestamp on repeat frames (it was not set) Bug: 11971963 Change-Id: I1d68ab3d269874bf3921aa429a985c5f63e428c7 --- media/libstagefright/ACodec.cpp | 22 ++++- media/libstagefright/omx/GraphicBufferSource.cpp | 100 ++++++++++++++++++++++- media/libstagefright/omx/GraphicBufferSource.h | 25 +++++- media/libstagefright/omx/OMXNodeInstance.cpp | 26 +++++- 4 files changed, 167 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index eb274a8..cdb89cd 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -372,7 +372,8 @@ ACodec::ACodec() mDequeueCounter(0), mStoreMetaDataInOutputBuffers(false), mMetaDataBuffersToSubmit(0), - mRepeatFrameDelayUs(-1ll) { + mRepeatFrameDelayUs(-1ll), + mMaxPtsGapUs(-1l) { mUninitializedState = new UninitializedState(this); mLoadedState = new LoadedState(this); mLoadedToIdleState = new LoadedToIdleState(this); @@ -1114,6 +1115,10 @@ status_t ACodec::configureCodec( &mRepeatFrameDelayUs)) { mRepeatFrameDelayUs = -1ll; } + + if (!msg->findInt64("max-pts-gap-to-encoder", &mMaxPtsGapUs)) { + mMaxPtsGapUs = -1l; + } } // Always try to enable dynamic output buffers on native surface @@ -3921,6 +3926,21 @@ void ACodec::LoadedState::onCreateInputSurface( } } + if (err == OK && mCodec->mMaxPtsGapUs > 0l) { + err = mCodec->mOMX->setInternalOption( + mCodec->mNode, + kPortIndexInput, + IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP, + &mCodec->mMaxPtsGapUs, + sizeof(mCodec->mMaxPtsGapUs)); + + if (err != OK) { + ALOGE("[%s] Unable to configure max timestamp gap (err %d)", + mCodec->mComponentName.c_str(), + err); + } + } + if (err == OK) { notify->setObject("input-surface", new BufferProducerWrapper(bufferProducer)); diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 7492577..20fa7ce 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -42,7 +42,11 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, mEndOfStream(false), mEndOfStreamSent(false), mRepeatAfterUs(-1ll), + mMaxTimestampGapUs(-1ll), + mPrevOriginalTimeUs(-1ll), + mPrevModifiedTimeUs(-1ll), mRepeatLastFrameGeneration(0), + mRepeatLastFrameTimestamp(-1ll), mLatestSubmittedBufferId(-1), mLatestSubmittedBufferFrameNum(0), mLatestSubmittedBufferUseCount(0), @@ -299,6 +303,32 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { return; } +void GraphicBufferSource::codecBufferFilled(OMX_BUFFERHEADERTYPE* header) { + Mutex::Autolock autoLock(mMutex); + + if (mMaxTimestampGapUs > 0ll + && !(header->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) { + ssize_t index = mOriginalTimeUs.indexOfKey(header->nTimeStamp); + if (index >= 0) { + ALOGV("OUT timestamp: %lld -> %lld", + header->nTimeStamp, mOriginalTimeUs[index]); + header->nTimeStamp = mOriginalTimeUs[index]; + mOriginalTimeUs.removeItemsAt(index); + } else { + // giving up the effort as encoder doesn't appear to preserve pts + ALOGW("giving up limiting timestamp gap (pts = %lld)", + header->nTimeStamp); + mMaxTimestampGapUs = -1ll; + } + if (mOriginalTimeUs.size() > BufferQueue::NUM_BUFFER_SLOTS) { + // something terribly wrong must have happened, giving up... + ALOGE("mOriginalTimeUs has too many entries (%d)", + mOriginalTimeUs.size()); + mMaxTimestampGapUs = -1ll; + } + } +} + void GraphicBufferSource::suspend(bool suspend) { Mutex::Autolock autoLock(mMutex); @@ -431,6 +461,7 @@ bool GraphicBufferSource::repeatLatestSubmittedBuffer_l() { BufferQueue::BufferItem item; item.mBuf = mLatestSubmittedBufferId; item.mFrameNumber = mLatestSubmittedBufferFrameNum; + item.mTimestamp = mRepeatLastFrameTimestamp; status_t err = submitBuffer_l(item, cbi); @@ -440,6 +471,20 @@ bool GraphicBufferSource::repeatLatestSubmittedBuffer_l() { ++mLatestSubmittedBufferUseCount; + /* repeat last frame up to kRepeatLastFrameCount times. + * in case of static scene, a single repeat might not get rid of encoder + * ghosting completely, refresh a couple more times to get better quality + */ + if (--mRepeatLastFrameCount > 0) { + mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000; + + if (mReflector != NULL) { + sp msg = new AMessage(kWhatRepeatLastFrame, mReflector->id()); + msg->setInt32("generation", ++mRepeatLastFrameGeneration); + msg->post(mRepeatAfterUs); + } + } + return true; } @@ -460,8 +505,11 @@ void GraphicBufferSource::setLatestSubmittedBuffer_l( mLatestSubmittedBufferId = item.mBuf; mLatestSubmittedBufferFrameNum = item.mFrameNumber; + mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000; + mLatestSubmittedBufferUseCount = 1; mRepeatBufferDeferred = false; + mRepeatLastFrameCount = kRepeatLastFrameCount; if (mReflector != NULL) { sp msg = new AMessage(kWhatRepeatLastFrame, mReflector->id()); @@ -497,6 +545,39 @@ status_t GraphicBufferSource::signalEndOfInputStream() { return OK; } +int64_t GraphicBufferSource::getTimestamp(const BufferQueue::BufferItem &item) { + int64_t timeUs = item.mTimestamp / 1000; + + if (mMaxTimestampGapUs > 0ll) { + /* Cap timestamp gap between adjacent frames to specified max + * + * In the scenario of cast mirroring, encoding could be suspended for + * prolonged periods. Limiting the pts gap to workaround the problem + * where encoder's rate control logic produces huge frames after a + * long period of suspension. + */ + + int64_t originalTimeUs = timeUs; + if (mPrevOriginalTimeUs >= 0ll) { + if (originalTimeUs < mPrevOriginalTimeUs) { + // Drop the frame if it's going backward in time. Bad timestamp + // could disrupt encoder's rate control completely. + ALOGV("Dropping frame that's going backward in time"); + return -1; + } + int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs; + timeUs = (timestampGapUs < mMaxTimestampGapUs ? + timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs; + } + mPrevOriginalTimeUs = originalTimeUs; + mPrevModifiedTimeUs = timeUs; + mOriginalTimeUs.add(timeUs, originalTimeUs); + ALOGV("IN timestamp: %lld -> %lld", originalTimeUs, timeUs); + } + + return timeUs; +} + status_t GraphicBufferSource::submitBuffer_l( const BufferQueue::BufferItem &item, int cbi) { ALOGV("submitBuffer_l cbi=%d", cbi); @@ -513,9 +594,15 @@ status_t GraphicBufferSource::submitBuffer_l( memcpy(data, &type, 4); memcpy(data + 4, &handle, sizeof(buffer_handle_t)); + int64_t timeUs = getTimestamp(item); + if (timeUs < 0ll) { + ALOGE("Dropping frame with bad timestamp"); + return UNKNOWN_ERROR; + } + status_t err = mNodeInstance->emptyDirectBuffer(header, 0, 4 + sizeof(buffer_handle_t), OMX_BUFFERFLAG_ENDOFFRAME, - item.mTimestamp / 1000); + timeUs); if (err != OK) { ALOGW("WARNING: emptyDirectBuffer failed: 0x%x", err); codecBuffer.mGraphicBuffer = NULL; @@ -664,6 +751,17 @@ status_t GraphicBufferSource::setRepeatPreviousFrameDelayUs( return OK; } +status_t GraphicBufferSource::setMaxTimestampGapUs(int64_t maxGapUs) { + Mutex::Autolock autoLock(mMutex); + + if (mExecuting || maxGapUs <= 0ll) { + return INVALID_OPERATION; + } + + mMaxTimestampGapUs = maxGapUs; + + return OK; +} void GraphicBufferSource::onMessageReceived(const sp &msg) { switch (msg->what()) { case kWhatRepeatLastFrame: diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index 9e5eee6..3b0e454 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -87,6 +87,10 @@ public: // fill it with a new frame of data; otherwise, just mark it as available. void codecBufferEmptied(OMX_BUFFERHEADERTYPE* header); + // Called when omx_message::FILL_BUFFER_DONE is received. (Currently the + // buffer source will fix timestamp in the header if needed.) + void codecBufferFilled(OMX_BUFFERHEADERTYPE* header); + // This is called after the last input frame has been submitted. We // need to submit an empty buffer with the EOS flag set. If we don't // have a codec buffer ready, we just set the mEndOfStream flag. @@ -105,6 +109,15 @@ public: // state and once this behaviour is specified it cannot be reset. status_t setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs); + // When set, the timestamp fed to the encoder will be modified such that + // the gap between two adjacent frames is capped at maxGapUs. Timestamp + // will be restored to the original when the encoded frame is returned to + // the client. + // This is to solve a problem in certain real-time streaming case, where + // encoder's rate control logic produces huge frames after a long period + // of suspension on input. + status_t setMaxTimestampGapUs(int64_t maxGapUs); + protected: // BufferQueue::ConsumerListener interface, called when a new frame of // data is available. If we're executing and a codec buffer is @@ -165,6 +178,7 @@ private: void setLatestSubmittedBuffer_l(const BufferQueue::BufferItem &item); bool repeatLatestSubmittedBuffer_l(); + int64_t getTimestamp(const BufferQueue::BufferItem &item); // Lock, covers all member variables. mutable Mutex mMutex; @@ -206,13 +220,22 @@ private: enum { kWhatRepeatLastFrame, }; - + enum { + kRepeatLastFrameCount = 10, + }; int64_t mRepeatAfterUs; + int64_t mMaxTimestampGapUs; + + KeyedVector mOriginalTimeUs; + int64_t mPrevOriginalTimeUs; + int64_t mPrevModifiedTimeUs; sp mLooper; sp > mReflector; int32_t mRepeatLastFrameGeneration; + int64_t mRepeatLastFrameTimestamp; + int32_t mRepeatLastFrameCount; int mLatestSubmittedBufferId; uint64_t mLatestSubmittedBufferFrameNum; diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index 5f104fc..6c5c857 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -849,6 +849,7 @@ status_t OMXNodeInstance::setInternalOption( switch (type) { case IOMX::INTERNAL_OPTION_SUSPEND: case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY: + case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: { const sp &bufferSource = getGraphicBufferSource(); @@ -864,7 +865,8 @@ status_t OMXNodeInstance::setInternalOption( bool suspend = *(bool *)data; bufferSource->suspend(suspend); - } else { + } else if (type == + IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY){ if (size != sizeof(int64_t)) { return INVALID_OPERATION; } @@ -872,6 +874,14 @@ status_t OMXNodeInstance::setInternalOption( int64_t delayUs = *(int64_t *)data; return bufferSource->setRepeatPreviousFrameDelayUs(delayUs); + } else { + if (size != sizeof(int64_t)) { + return INVALID_OPERATION; + } + + int64_t maxGapUs = *(int64_t *)data; + + return bufferSource->setMaxTimestampGapUs(maxGapUs); } return OK; @@ -883,6 +893,8 @@ status_t OMXNodeInstance::setInternalOption( } void OMXNodeInstance::onMessage(const omx_message &msg) { + const sp& bufferSource(getGraphicBufferSource()); + if (msg.type == omx_message::FILL_BUFFER_DONE) { OMX_BUFFERHEADERTYPE *buffer = static_cast( @@ -892,10 +904,18 @@ void OMXNodeInstance::onMessage(const omx_message &msg) { static_cast(buffer->pAppPrivate); buffer_meta->CopyFromOMX(buffer); - } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) { - const sp& bufferSource(getGraphicBufferSource()); if (bufferSource != NULL) { + // fix up the buffer info (especially timestamp) if needed + bufferSource->codecBufferFilled(buffer); + + omx_message newMsg = msg; + newMsg.u.extended_buffer_data.timestamp = buffer->nTimeStamp; + mObserver->onMessage(newMsg); + return; + } + } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) { + if (bufferSource != NULL) { // This is one of the buffers used exclusively by // GraphicBufferSource. // Don't dispatch a message back to ACodec, since it doesn't -- cgit v1.1 From 72e54af9fcdc4754914fe2bf8de699523538b315 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 31 Jan 2014 09:37:35 -0800 Subject: Use const NBAIO_Format& in parameter lists This is in preparation for changing the typedef to a struct. Change-Id: I8d73a6b29580c65105afd78f24db7e2f4a1eb872 --- media/libnbaio/AudioBufferProviderSource.cpp | 2 +- media/libnbaio/MonoPipe.cpp | 2 +- media/libnbaio/NBAIO.cpp | 8 ++++---- media/libnbaio/Pipe.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libnbaio/AudioBufferProviderSource.cpp b/media/libnbaio/AudioBufferProviderSource.cpp index 74a6fdb..e952a00 100644 --- a/media/libnbaio/AudioBufferProviderSource.cpp +++ b/media/libnbaio/AudioBufferProviderSource.cpp @@ -24,7 +24,7 @@ namespace android { AudioBufferProviderSource::AudioBufferProviderSource(AudioBufferProvider *provider, - NBAIO_Format format) : + const NBAIO_Format& format) : NBAIO_Source(format), mProvider(provider), mConsumed(0) { ALOG_ASSERT(provider != NULL); diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp index 3c61b60..b23967b 100644 --- a/media/libnbaio/MonoPipe.cpp +++ b/media/libnbaio/MonoPipe.cpp @@ -30,7 +30,7 @@ namespace android { -MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) : +MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) : NBAIO_Sink(format), mUpdateSeq(0), mReqFrames(reqFrames), diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index e0d2c21..290604e 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -22,12 +22,12 @@ namespace android { -size_t Format_frameSize(NBAIO_Format format) +size_t Format_frameSize(const NBAIO_Format& format) { return Format_channelCount(format) * sizeof(short); } -size_t Format_frameBitShift(NBAIO_Format format) +size_t Format_frameBitShift(const NBAIO_Format& format) { // sizeof(short) == 2, so frame size == 1 << channels return Format_channelCount(format); @@ -51,7 +51,7 @@ enum { Format_C_Mask = 0x18 }; -unsigned Format_sampleRate(NBAIO_Format format) +unsigned Format_sampleRate(const NBAIO_Format& format) { if (format == Format_Invalid) { return 0; @@ -78,7 +78,7 @@ unsigned Format_sampleRate(NBAIO_Format format) } } -unsigned Format_channelCount(NBAIO_Format format) +unsigned Format_channelCount(const NBAIO_Format& format) { if (format == Format_Invalid) { return 0; diff --git a/media/libnbaio/Pipe.cpp b/media/libnbaio/Pipe.cpp index 1c21f9c..115f311 100644 --- a/media/libnbaio/Pipe.cpp +++ b/media/libnbaio/Pipe.cpp @@ -25,7 +25,7 @@ namespace android { -Pipe::Pipe(size_t maxFrames, NBAIO_Format format) : +Pipe::Pipe(size_t maxFrames, const NBAIO_Format& format) : NBAIO_Sink(format), mMaxFrames(roundup(maxFrames)), mBuffer(malloc(mMaxFrames * Format_frameSize(format))), -- cgit v1.1 From 9090338367bd9f3fc5678032332a44d457a4a2fe Mon Sep 17 00:00:00 2001 From: Changwan Ryu Date: Mon, 28 Oct 2013 10:53:48 +0900 Subject: [DO NOT MERGE] Support AC3 in stagefright Change-Id: I12016b424bd069413bd6e380ff11484e175e05f3 --- media/libstagefright/ACodec.cpp | 71 +++++++++++++++++++++++++++++++++++++- media/libstagefright/MediaDefs.cpp | 1 + 2 files changed, 71 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 5259b7d..37cad63 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -35,7 +35,9 @@ #include +#include #include +#include #include "include/avc_utils.h" @@ -979,6 +981,8 @@ status_t ACodec::setComponentRole( "audio_decoder.gsm", "audio_encoder.gsm" }, { MEDIA_MIMETYPE_VIDEO_MPEG2, "video_decoder.mpeg2", "video_encoder.mpeg2" }, + { MEDIA_MIMETYPE_AUDIO_AC3, + "audio_decoder.ac3", "audio_encoder.ac3" }, }; static const size_t kNumMimeToRole = @@ -1270,6 +1274,15 @@ status_t ACodec::configureCodec( } else { err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels); } + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)) { + int32_t numChannels; + int32_t sampleRate; + if (!msg->findInt32("channel-count", &numChannels) + || !msg->findInt32("sample-rate", &sampleRate)) { + err = INVALID_OPERATION; + } else { + err = setupAC3Codec(encoder, numChannels, sampleRate); + } } if (err != OK) { @@ -1466,6 +1479,44 @@ status_t ACodec::setupAACCodec( mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); } +status_t ACodec::setupAC3Codec( + bool encoder, int32_t numChannels, int32_t sampleRate) { + status_t err = setupRawAudioFormat( + encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels); + + if (err != OK) { + return err; + } + + if (encoder) { + ALOGW("AC3 encoding is not supported."); + return INVALID_OPERATION; + } + + OMX_AUDIO_PARAM_ANDROID_AC3TYPE def; + InitOMXParams(&def); + def.nPortIndex = kPortIndexInput; + + err = mOMX->getParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, + &def, + sizeof(def)); + + if (err != OK) { + return err; + } + + def.nChannels = numChannels; + def.nSampleRate = sampleRate; + + return mOMX->setParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, + &def, + sizeof(def)); +} + static OMX_AUDIO_AMRBANDMODETYPE pickModeFromBitRate( bool isAMRWB, int32_t bps) { if (isAMRWB) { @@ -2560,7 +2611,7 @@ void ACodec::sendFormatChange(const sp &reply) { { OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio; - switch (audioDef->eEncoding) { + switch ((int)audioDef->eEncoding) { case OMX_AUDIO_CodingPCM: { OMX_AUDIO_PARAM_PCMMODETYPE params; @@ -2666,6 +2717,24 @@ void ACodec::sendFormatChange(const sp &reply) { break; } + case OMX_AUDIO_CodingAndroidAC3: + { + OMX_AUDIO_PARAM_ANDROID_AC3TYPE params; + InitOMXParams(¶ms); + params.nPortIndex = kPortIndexOutput; + + CHECK_EQ((status_t)OK, mOMX->getParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, + ¶ms, + sizeof(params))); + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_AC3); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSampleRate); + break; + } + default: TRESPASS(); } diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp index b5d4e44..340cba7 100644 --- a/media/libstagefright/MediaDefs.cpp +++ b/media/libstagefright/MediaDefs.cpp @@ -42,6 +42,7 @@ const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw"; const char *MEDIA_MIMETYPE_AUDIO_FLAC = "audio/flac"; const char *MEDIA_MIMETYPE_AUDIO_AAC_ADTS = "audio/aac-adts"; const char *MEDIA_MIMETYPE_AUDIO_MSGSM = "audio/gsm"; +const char *MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3"; const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4"; const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/x-wav"; -- cgit v1.1 From dd432ce03eccf280d83672f95076b6fbd561047f Mon Sep 17 00:00:00 2001 From: Changwan Ryu Date: Mon, 28 Oct 2013 11:08:44 +0900 Subject: [DO NOT MERGE] Support TS + AC3 for ATSC standard Change-Id: I141667f3f54b242bafdf0ab9db86852c56f49ffa --- media/libstagefright/OMXCodec.cpp | 51 ++++++++ media/libstagefright/mpeg2ts/ATSParser.cpp | 6 + media/libstagefright/mpeg2ts/ATSParser.h | 4 + media/libstagefright/mpeg2ts/ESQueue.cpp | 190 +++++++++++++++++++++++++++++ media/libstagefright/mpeg2ts/ESQueue.h | 2 + 5 files changed, 253 insertions(+) (limited to 'media') diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index dec82ad..625922f 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -40,7 +40,9 @@ #include #include +#include #include +#include #include "include/avc_utils.h" @@ -528,6 +530,17 @@ status_t OMXCodec::configureCodec(const sp &meta) { sampleRate, numChannels); } + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mMIME)) { + int32_t numChannels; + int32_t sampleRate; + CHECK(meta->findInt32(kKeyChannelCount, &numChannels)); + CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); + + status_t err = setAC3Format(numChannels, sampleRate); + if (err != OK) { + CODEC_LOGE("setAC3Format() failed (err = %d)", err); + return err; + } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_ALAW, mMIME) || !strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_MLAW, mMIME)) { // These are PCM-like formats with a fixed sample rate but @@ -1396,6 +1409,8 @@ void OMXCodec::setComponentRole( "audio_decoder.gsm", "audio_encoder.gsm" }, { MEDIA_MIMETYPE_VIDEO_MPEG2, "video_decoder.mpeg2", "video_encoder.mpeg2" }, + { MEDIA_MIMETYPE_AUDIO_AC3, + "audio_decoder.ac3", "audio_encoder.ac3" }, }; static const size_t kNumMimeToRole = @@ -3491,6 +3506,31 @@ status_t OMXCodec::setAACFormat( return OK; } +status_t OMXCodec::setAC3Format(int32_t numChannels, int32_t sampleRate) { + OMX_AUDIO_PARAM_ANDROID_AC3TYPE def; + InitOMXParams(&def); + def.nPortIndex = kPortIndexInput; + + status_t err = mOMX->getParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, + &def, + sizeof(def)); + + if (err != OK) { + return err; + } + + def.nChannels = numChannels; + def.nSampleRate = sampleRate; + + return mOMX->setParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, + &def, + sizeof(def)); +} + void OMXCodec::setG711Format(int32_t numChannels) { CHECK(!mIsEncoder); setRawAudioFormat(kPortIndexInput, 8000, numChannels); @@ -4424,6 +4464,17 @@ void OMXCodec::initOutputFormat(const sp &inputFormat) { mOutputFormat->setInt32(kKeyChannelCount, numChannels); mOutputFormat->setInt32(kKeySampleRate, sampleRate); mOutputFormat->setInt32(kKeyBitRate, bitRate); + } else if (audio_def->eEncoding == + (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidAC3) { + mOutputFormat->setCString( + kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3); + int32_t numChannels, sampleRate, bitRate; + inputFormat->findInt32(kKeyChannelCount, &numChannels); + inputFormat->findInt32(kKeySampleRate, &sampleRate); + inputFormat->findInt32(kKeyBitRate, &bitRate); + mOutputFormat->setInt32(kKeyChannelCount, numChannels); + mOutputFormat->setInt32(kKeySampleRate, sampleRate); + mOutputFormat->setInt32(kKeyBitRate, bitRate); } else { CHECK(!"Should not be here. Unknown audio encoding."); } diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index 175a263..cb57a2f 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -506,6 +506,11 @@ ATSParser::Stream::Stream( ElementaryStreamQueue::PCM_AUDIO); break; + case STREAMTYPE_AC3: + mQueue = new ElementaryStreamQueue( + ElementaryStreamQueue::AC3); + break; + default: break; } @@ -614,6 +619,7 @@ bool ATSParser::Stream::isAudio() const { case STREAMTYPE_MPEG2_AUDIO: case STREAMTYPE_MPEG2_AUDIO_ADTS: case STREAMTYPE_PCM_AUDIO: + case STREAMTYPE_AC3: return true; default: diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h index a10edc9..d4e30b4 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.h +++ b/media/libstagefright/mpeg2ts/ATSParser.h @@ -88,6 +88,10 @@ struct ATSParser : public RefBase { STREAMTYPE_MPEG2_AUDIO_ADTS = 0x0f, STREAMTYPE_MPEG4_VIDEO = 0x10, STREAMTYPE_H264 = 0x1b, + + // From ATSC A/53 Part 3:2009, 6.7.1 + STREAMTYPE_AC3 = 0x81, + STREAMTYPE_PCM_AUDIO = 0x83, }; diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp index 8f9c9c8..ea79885 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.cpp +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp @@ -56,6 +56,122 @@ void ElementaryStreamQueue::clear(bool clearFormat) { } } +// Parse AC3 header assuming the current ptr is start position of syncframe, +// update metadata only applicable, and return the payload size +static unsigned parseAC3SyncFrame( + const uint8_t *ptr, size_t size, sp *metaData) { + static const unsigned channelCountTable[] = {2, 1, 2, 3, 4, 4, 5, 6}; + static const unsigned samplingRateTable[] = {48000, 44100, 32000}; + static const unsigned rates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, + 320, 384, 448, 512, 576, 640}; + + static const unsigned frameSizeTable[19][3] = { + { 64, 69, 96 }, + { 80, 87, 120 }, + { 96, 104, 144 }, + { 112, 121, 168 }, + { 128, 139, 192 }, + { 160, 174, 240 }, + { 192, 208, 288 }, + { 224, 243, 336 }, + { 256, 278, 384 }, + { 320, 348, 480 }, + { 384, 417, 576 }, + { 448, 487, 672 }, + { 512, 557, 768 }, + { 640, 696, 960 }, + { 768, 835, 1152 }, + { 896, 975, 1344 }, + { 1024, 1114, 1536 }, + { 1152, 1253, 1728 }, + { 1280, 1393, 1920 }, + }; + + ABitReader bits(ptr, size); + unsigned syncStartPos = 0; // in bytes + if (bits.numBitsLeft() < 16) { + return 0; + } + if (bits.getBits(16) != 0x0B77) { + return 0; + } + + if (bits.numBitsLeft() < 16 + 2 + 6 + 5 + 3 + 3) { + ALOGV("Not enough bits left for further parsing"); + return 0; + } + bits.skipBits(16); // crc1 + + unsigned fscod = bits.getBits(2); + if (fscod == 3) { + ALOGW("Incorrect fscod in AC3 header"); + return 0; + } + + unsigned frmsizecod = bits.getBits(6); + if (frmsizecod > 37) { + ALOGW("Incorrect frmsizecod in AC3 header"); + return 0; + } + + unsigned bsid = bits.getBits(5); + if (bsid > 8) { + ALOGW("Incorrect bsid in AC3 header. Possibly E-AC-3?"); + return 0; + } + + unsigned bsmod = bits.getBits(3); + unsigned acmod = bits.getBits(3); + unsigned cmixlev = 0; + unsigned surmixlev = 0; + unsigned dsurmod = 0; + + if ((acmod & 1) > 0 && acmod != 1) { + if (bits.numBitsLeft() < 2) { + return 0; + } + cmixlev = bits.getBits(2); + } + if ((acmod & 4) > 0) { + if (bits.numBitsLeft() < 2) { + return 0; + } + surmixlev = bits.getBits(2); + } + if (acmod == 2) { + if (bits.numBitsLeft() < 2) { + return 0; + } + dsurmod = bits.getBits(2); + } + + if (bits.numBitsLeft() < 1) { + return 0; + } + unsigned lfeon = bits.getBits(1); + + unsigned samplingRate = samplingRateTable[fscod]; + unsigned payloadSize = frameSizeTable[frmsizecod >> 1][fscod]; + if (fscod == 1) { + payloadSize += frmsizecod & 1; + } + payloadSize <<= 1; // convert from 16-bit words to bytes + + unsigned channelCount = channelCountTable[acmod] + lfeon; + + if (metaData != NULL) { + (*metaData)->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3); + (*metaData)->setInt32(kKeyChannelCount, channelCount); + (*metaData)->setInt32(kKeySampleRate, samplingRate); + } + + return payloadSize; +} + +static bool IsSeeminglyValidAC3Header(const uint8_t *ptr, size_t size) { + return parseAC3SyncFrame(ptr, size, NULL) > 0; +} + static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) { if (size < 3) { // Not enough data to verify header. @@ -224,6 +340,33 @@ status_t ElementaryStreamQueue::appendData( break; } + case AC3: + { + uint8_t *ptr = (uint8_t *)data; + + ssize_t startOffset = -1; + for (size_t i = 0; i < size; ++i) { + if (IsSeeminglyValidAC3Header(&ptr[i], size - i)) { + startOffset = i; + break; + } + } + + if (startOffset < 0) { + return ERROR_MALFORMED; + } + + if (startOffset > 0) { + ALOGI("found something resembling an AC3 syncword at " + "offset %d", + startOffset); + } + + data = &ptr[startOffset]; + size -= startOffset; + break; + } + case MPEG_AUDIO: { uint8_t *ptr = (uint8_t *)data; @@ -328,6 +471,8 @@ sp ElementaryStreamQueue::dequeueAccessUnit() { return dequeueAccessUnitH264(); case AAC: return dequeueAccessUnitAAC(); + case AC3: + return dequeueAccessUnitAC3(); case MPEG_VIDEO: return dequeueAccessUnitMPEGVideo(); case MPEG4_VIDEO: @@ -340,6 +485,51 @@ sp ElementaryStreamQueue::dequeueAccessUnit() { } } +sp ElementaryStreamQueue::dequeueAccessUnitAC3() { + unsigned syncStartPos = 0; // in bytes + unsigned payloadSize = 0; + sp format = new MetaData; + while (true) { + if (syncStartPos + 2 >= mBuffer->size()) { + return NULL; + } + + payloadSize = parseAC3SyncFrame( + mBuffer->data() + syncStartPos, + mBuffer->size() - syncStartPos, + &format); + if (payloadSize > 0) { + break; + } + ++syncStartPos; + } + + if (mBuffer->size() < syncStartPos + payloadSize) { + ALOGV("Not enough buffer size for AC3"); + return NULL; + } + + if (mFormat == NULL) { + mFormat = format; + } + + sp accessUnit = new ABuffer(syncStartPos + payloadSize); + memcpy(accessUnit->data(), mBuffer->data(), syncStartPos + payloadSize); + + int64_t timeUs = fetchTimestamp(syncStartPos + payloadSize); + CHECK_GE(timeUs, 0ll); + accessUnit->meta()->setInt64("timeUs", timeUs); + + memmove( + mBuffer->data(), + mBuffer->data() + syncStartPos + payloadSize, + mBuffer->size() - syncStartPos - payloadSize); + + mBuffer->setRange(0, mBuffer->size() - syncStartPos - payloadSize); + + return accessUnit; +} + sp ElementaryStreamQueue::dequeueAccessUnitPCMAudio() { if (mBuffer->size() < 4) { return NULL; diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h index 66a8087..a2cca77 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.h +++ b/media/libstagefright/mpeg2ts/ESQueue.h @@ -32,6 +32,7 @@ struct ElementaryStreamQueue { enum Mode { H264, AAC, + AC3, MPEG_AUDIO, MPEG_VIDEO, MPEG4_VIDEO, @@ -67,6 +68,7 @@ private: sp dequeueAccessUnitH264(); sp dequeueAccessUnitAAC(); + sp dequeueAccessUnitAC3(); sp dequeueAccessUnitMPEGAudio(); sp dequeueAccessUnitMPEGVideo(); sp dequeueAccessUnitMPEG4Video(); -- cgit v1.1 From 0f11b51a57bc9062c4fe8af73747319cedabc5d6 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 31 Jan 2014 16:18:54 -0800 Subject: Fix unused parameter warnings in audio Change-Id: I665ba3358dd9502f0adec70d486e7bf8a2e1b0fe --- media/libmedia/AudioEffect.cpp | 4 ++-- media/libmedia/AudioRecord.cpp | 2 +- media/libmedia/AudioSystem.cpp | 2 +- media/libnbaio/PipeReader.cpp | 2 +- media/mediaserver/main_mediaserver.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp index 8dfffb3..35f6557 100644 --- a/media/libmedia/AudioEffect.cpp +++ b/media/libmedia/AudioEffect.cpp @@ -380,9 +380,9 @@ void AudioEffect::enableStatusChanged(bool enabled) } void AudioEffect::commandExecuted(uint32_t cmdCode, - uint32_t cmdSize, + uint32_t cmdSize __unused, void *cmdData, - uint32_t replySize, + uint32_t replySize __unused, void *replyData) { if (cmdData == NULL || replyData == NULL) { diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index b69e3ae..286096e 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -87,7 +87,7 @@ AudioRecord::AudioRecord( int notificationFrames, int sessionId, transfer_type transferType, - audio_input_flags_t flags) + audio_input_flags_t flags __unused) : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index dcb72f8..1ab94fa 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -333,7 +333,7 @@ status_t AudioSystem::getOutputLatency(uint32_t* latency, audio_stream_type_t st } status_t AudioSystem::getLatency(audio_io_handle_t output, - audio_stream_type_t streamType, + audio_stream_type_t streamType __unused, uint32_t* latency) { OutputDescriptor *outputDesc; diff --git a/media/libnbaio/PipeReader.cpp b/media/libnbaio/PipeReader.cpp index d786b84..24da1bd 100644 --- a/media/libnbaio/PipeReader.cpp +++ b/media/libnbaio/PipeReader.cpp @@ -59,7 +59,7 @@ ssize_t PipeReader::availableToRead() return avail; } -ssize_t PipeReader::read(void *buffer, size_t count, int64_t readPTS) +ssize_t PipeReader::read(void *buffer, size_t count, int64_t readPTS __unused) { ssize_t avail = availableToRead(); if (CC_UNLIKELY(avail <= 0)) { diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp index d5207d5..a347951 100644 --- a/media/mediaserver/main_mediaserver.cpp +++ b/media/mediaserver/main_mediaserver.cpp @@ -37,7 +37,7 @@ using namespace android; -int main(int argc, char** argv) +int main(int argc __unused, char** argv) { signal(SIGPIPE, SIG_IGN); char value[PROPERTY_VALUE_MAX]; -- cgit v1.1 From 69634506fbfe79605c37f337a8d6748cda4445b1 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 23 Jan 2014 14:25:32 -0800 Subject: AnotherPacketSource support to get latest buffered MetaData. Change-Id: Ib3b6e0984036082bf3c4eb7901a2b29be52fdd29 --- .../libstagefright/mpeg2ts/AnotherPacketSource.cpp | 24 ++++++++++++++++++++-- media/libstagefright/mpeg2ts/AnotherPacketSource.h | 3 +++ 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index 52fb2a5..2b0bf30 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -34,7 +34,8 @@ AnotherPacketSource::AnotherPacketSource(const sp &meta) : mIsAudio(false), mFormat(NULL), mLastQueuedTimeUs(0), - mEOSResult(OK) { + mEOSResult(OK), + mLatestEnqueuedMeta(NULL) { setFormat(meta); } @@ -182,12 +183,24 @@ void AnotherPacketSource::queueAccessUnit(const sp &buffer) { return; } - CHECK(buffer->meta()->findInt64("timeUs", &mLastQueuedTimeUs)); + int64_t lastQueuedTimeUs; + CHECK(buffer->meta()->findInt64("timeUs", &lastQueuedTimeUs)); + mLastQueuedTimeUs = lastQueuedTimeUs; ALOGV("queueAccessUnit timeUs=%lld us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6); Mutex::Autolock autoLock(mLock); mBuffers.push_back(buffer); mCondition.signal(); + + if (!mLatestEnqueuedMeta.get()) { + mLatestEnqueuedMeta = buffer->meta(); + } else { + int64_t latestTimeUs = 0; + CHECK(mLatestEnqueuedMeta->findInt64("timeUs", &latestTimeUs)); + if (lastQueuedTimeUs > latestTimeUs) { + mLatestEnqueuedMeta = buffer->meta(); + } + } } void AnotherPacketSource::clear() { @@ -197,6 +210,7 @@ void AnotherPacketSource::clear() { mEOSResult = OK; mFormat = NULL; + mLatestEnqueuedMeta = NULL; } void AnotherPacketSource::queueDiscontinuity( @@ -221,6 +235,7 @@ void AnotherPacketSource::queueDiscontinuity( mEOSResult = OK; mLastQueuedTimeUs = 0; + mLatestEnqueuedMeta = NULL; sp buffer = new ABuffer(0); buffer->meta()->setInt32("discontinuity", static_cast(type)); @@ -308,4 +323,9 @@ bool AnotherPacketSource::isFinished(int64_t duration) const { return (mEOSResult != OK); } +sp AnotherPacketSource::getLatestMeta() { + Mutex::Autolock autoLock(mLock); + return mLatestEnqueuedMeta; +} + } // namespace android diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h index e16cf78..9b193a2 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h @@ -62,6 +62,8 @@ struct AnotherPacketSource : public MediaSource { bool isFinished(int64_t duration) const; + sp getLatestMeta(); + protected: virtual ~AnotherPacketSource(); @@ -74,6 +76,7 @@ private: int64_t mLastQueuedTimeUs; List > mBuffers; status_t mEOSResult; + sp mLatestEnqueuedMeta; bool wasFormatChange(int32_t discontinuityType) const; -- cgit v1.1 From 51d53cd993043d9286e12cba884e6ee4d10b5fac Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 31 Jan 2014 09:38:33 -0800 Subject: Change Format_Invalid from enum to global const This is in preparation for changing the typedef to a struct Change-Id: I36d1fe81d2f974224750f753453753303c224591 --- media/libnbaio/NBAIO.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'media') diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index 290604e..8a8155d 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -33,6 +33,8 @@ size_t Format_frameBitShift(const NBAIO_Format& format) return Format_channelCount(format); } +const NBAIO_Format Format_Invalid = { 0 }; + enum { Format_SR_8000, Format_SR_11025, -- cgit v1.1 From 403484d6d76ede31fc71c88495b69108a4df8319 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 3 Feb 2014 14:33:16 -0800 Subject: Allow for larger codec private data This change adds support for multibyte sizes in the ESDS. Previously the Matroska extractor only supported single byte sizes, so codec private data had to be less than 108 bytes, and would crash if it was bigger. b/12584090 Change-Id: I9edfc2f687187d1e98bcfd2fe56576312435df3e --- .../libstagefright/matroska/MatroskaExtractor.cpp | 80 ++++++++++++++-------- 1 file changed, 50 insertions(+), 30 deletions(-) (limited to 'media') diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index d260d0f..dcb1cda 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -716,41 +716,61 @@ bool MatroskaExtractor::isLiveStreaming() const { return mIsLiveStreaming; } +static int bytesForSize(size_t size) { + // use at most 28 bits (4 times 7) + CHECK(size <= 0xfffffff); + + if (size > 0x1fffff) { + return 4; + } else if (size > 0x3fff) { + return 3; + } else if (size > 0x7f) { + return 2; + } + return 1; +} + +static void storeSize(uint8_t *data, size_t &idx, size_t size) { + int numBytes = bytesForSize(size); + idx += numBytes; + + data += idx; + size_t next = 0; + while (numBytes--) { + *--data = (size & 0x7f) | next; + size >>= 7; + next = 0x80; + } +} + static void addESDSFromCodecPrivate( const sp &meta, bool isAudio, const void *priv, size_t privSize) { - static const uint8_t kStaticESDS[] = { - 0x03, 22, - 0x00, 0x00, // ES_ID - 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag - - 0x04, 17, - 0x40, // ObjectTypeIndication - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - 0x05, - // CodecSpecificInfo (with size prefix) follows - }; - // Make sure all sizes can be coded in a single byte. - CHECK(privSize + 22 - 2 < 128); - size_t esdsSize = sizeof(kStaticESDS) + privSize + 1; + int privSizeBytesRequired = bytesForSize(privSize); + int esdsSize2 = 14 + privSizeBytesRequired + privSize; + int esdsSize2BytesRequired = bytesForSize(esdsSize2); + int esdsSize1 = 4 + esdsSize2BytesRequired + esdsSize2; + int esdsSize1BytesRequired = bytesForSize(esdsSize1); + size_t esdsSize = 1 + esdsSize1BytesRequired + esdsSize1; uint8_t *esds = new uint8_t[esdsSize]; - memcpy(esds, kStaticESDS, sizeof(kStaticESDS)); - uint8_t *ptr = esds + sizeof(kStaticESDS); - *ptr++ = privSize; - memcpy(ptr, priv, privSize); - - // Increment by codecPrivateSize less 2 bytes that are accounted for - // already in lengths of 22/17 - esds[1] += privSize - 2; - esds[6] += privSize - 2; - - // Set ObjectTypeIndication. - esds[7] = isAudio ? 0x40 // Audio ISO/IEC 14496-3 - : 0x20; // Visual ISO/IEC 14496-2 + + size_t idx = 0; + esds[idx++] = 0x03; + storeSize(esds, idx, esdsSize1); + esds[idx++] = 0x00; // ES_ID + esds[idx++] = 0x00; // ES_ID + esds[idx++] = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag + esds[idx++] = 0x04; + storeSize(esds, idx, esdsSize2); + esds[idx++] = isAudio ? 0x40 // Audio ISO/IEC 14496-3 + : 0x20; // Visual ISO/IEC 14496-2 + for (int i = 0; i < 12; i++) { + esds[idx++] = 0x00; + } + esds[idx++] = 0x05; + storeSize(esds, idx, privSize); + memcpy(esds + idx, priv, privSize); meta->setData(kKeyESDS, 0, esds, esdsSize); -- cgit v1.1 From cc1e0e807ee9a9f163a4685cbd6efd6ae55849cf Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 31 Jan 2014 09:48:42 -0800 Subject: Add Format_isValid() and Format_isEqual() to NBAIO This is in preparation for changing the typedef to a struct. Change-Id: I8eb1c7d98fd12f997641e462359864fdb834abe6 --- media/libnbaio/NBAIO.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'media') diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index 8a8155d..cc12671 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -235,4 +235,14 @@ ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers, return (ssize_t) NEGOTIATE; } +bool Format_isValid(const NBAIO_Format& format) +{ + return format != Format_Invalid; +} + +bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2) +{ + return format1 == format2; +} + } // namespace android -- cgit v1.1 From 6e0d67d7b496ce17c0970a4ffd3a6f808860949c Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 31 Jan 2014 09:41:08 -0800 Subject: Use Format_isValid() and Format_isEqual() instead of direct comparison Change-Id: Ie87607aa514976947540a77775e6425c4e56e7d9 --- media/libnbaio/AudioBufferProviderSource.cpp | 2 +- media/libnbaio/AudioStreamInSource.cpp | 4 ++-- media/libnbaio/AudioStreamOutSink.cpp | 4 ++-- media/libnbaio/NBAIO.cpp | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'media') diff --git a/media/libnbaio/AudioBufferProviderSource.cpp b/media/libnbaio/AudioBufferProviderSource.cpp index e952a00..4a69104 100644 --- a/media/libnbaio/AudioBufferProviderSource.cpp +++ b/media/libnbaio/AudioBufferProviderSource.cpp @@ -28,7 +28,7 @@ AudioBufferProviderSource::AudioBufferProviderSource(AudioBufferProvider *provid NBAIO_Source(format), mProvider(provider), mConsumed(0) { ALOG_ASSERT(provider != NULL); - ALOG_ASSERT(format != Format_Invalid); + ALOG_ASSERT(Format_isValid(format)); } AudioBufferProviderSource::~AudioBufferProviderSource() diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp index 05273f6..ae8fac8 100644 --- a/media/libnbaio/AudioStreamInSource.cpp +++ b/media/libnbaio/AudioStreamInSource.cpp @@ -40,7 +40,7 @@ AudioStreamInSource::~AudioStreamInSource() ssize_t AudioStreamInSource::negotiate(const NBAIO_Format offers[], size_t numOffers, NBAIO_Format counterOffers[], size_t& numCounterOffers) { - if (mFormat == Format_Invalid) { + if (!Format_isValid(mFormat)) { mStreamBufferSizeBytes = mStream->common.get_buffer_size(&mStream->common); audio_format_t streamFormat = mStream->common.get_format(&mStream->common); if (streamFormat == AUDIO_FORMAT_PCM_16_BIT) { @@ -67,7 +67,7 @@ size_t AudioStreamInSource::framesOverrun() ssize_t AudioStreamInSource::read(void *buffer, size_t count) { - if (CC_UNLIKELY(mFormat == Format_Invalid)) { + if (CC_UNLIKELY(!Format_isValid(mFormat))) { return NEGOTIATE; } ssize_t bytesRead = mStream->read(mStream, buffer, count << mBitShift); diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp index e4341d7..aa9810e 100644 --- a/media/libnbaio/AudioStreamOutSink.cpp +++ b/media/libnbaio/AudioStreamOutSink.cpp @@ -37,7 +37,7 @@ AudioStreamOutSink::~AudioStreamOutSink() ssize_t AudioStreamOutSink::negotiate(const NBAIO_Format offers[], size_t numOffers, NBAIO_Format counterOffers[], size_t& numCounterOffers) { - if (mFormat == Format_Invalid) { + if (!Format_isValid(mFormat)) { mStreamBufferSizeBytes = mStream->common.get_buffer_size(&mStream->common); audio_format_t streamFormat = mStream->common.get_format(&mStream->common); if (streamFormat == AUDIO_FORMAT_PCM_16_BIT) { @@ -56,7 +56,7 @@ ssize_t AudioStreamOutSink::write(const void *buffer, size_t count) if (!mNegotiated) { return NEGOTIATE; } - ALOG_ASSERT(mFormat != Format_Invalid); + ALOG_ASSERT(Format_isValid(mFormat)); ssize_t ret = mStream->write(mStream, buffer, count << mBitShift); if (ret > 0) { ret >>= mBitShift; diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index cc12671..18e0252 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -55,7 +55,7 @@ enum { unsigned Format_sampleRate(const NBAIO_Format& format) { - if (format == Format_Invalid) { + if (!Format_isValid(format)) { return 0; } switch (format & Format_SR_Mask) { @@ -82,7 +82,7 @@ unsigned Format_sampleRate(const NBAIO_Format& format) unsigned Format_channelCount(const NBAIO_Format& format) { - if (format == Format_Invalid) { + if (!Format_isValid(format)) { return 0; } switch (format & Format_C_Mask) { @@ -218,9 +218,9 @@ ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers, { ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u", offers, numOffers, counterOffers, numCounterOffers); - if (mFormat != Format_Invalid) { + if (Format_isValid(mFormat)) { for (size_t i = 0; i < numOffers; ++i) { - if (offers[i] == mFormat) { + if (Format_isEqual(offers[i], mFormat)) { mNegotiated = true; return i; } -- cgit v1.1 From c4b8b32dec91a11a83d0a7ab49747606d16d39a5 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 31 Jan 2014 09:39:01 -0800 Subject: Change NBAIO_Format from typedef to struct This will make it easier to support arbitrary sample rates, channel counts, and sample formats in NBAIO. Change-Id: I5eda412648b094358f5eefc38300e9ec8a734cd3 --- media/libnbaio/NBAIO.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index 18e0252..f630236 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -58,7 +58,7 @@ unsigned Format_sampleRate(const NBAIO_Format& format) if (!Format_isValid(format)) { return 0; } - switch (format & Format_SR_Mask) { + switch (format.mPacked & Format_SR_Mask) { case Format_SR_8000: return 8000; case Format_SR_11025: @@ -85,7 +85,7 @@ unsigned Format_channelCount(const NBAIO_Format& format) if (!Format_isValid(format)) { return 0; } - switch (format & Format_C_Mask) { + switch (format.mPacked & Format_C_Mask) { case Format_C_1: return 1; case Format_C_2: @@ -97,7 +97,7 @@ unsigned Format_channelCount(const NBAIO_Format& format) NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount) { - NBAIO_Format format; + unsigned format; switch (sampleRate) { case 8000: format = Format_SR_8000; @@ -136,7 +136,9 @@ NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount) default: return Format_Invalid; } - return format; + NBAIO_Format ret; + ret.mPacked = format; + return ret; } // This is a default implementation; it is expected that subclasses will optimize this. @@ -237,12 +239,12 @@ ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers, bool Format_isValid(const NBAIO_Format& format) { - return format != Format_Invalid; + return format.mPacked != Format_Invalid.mPacked; } bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2) { - return format1 == format2; + return format1.mPacked == format2.mPacked; } } // namespace android -- cgit v1.1 From 1ec712f180072a7eb2131be09862921ae62dc2b4 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 31 Jan 2014 09:47:15 -0800 Subject: Add FIXMEs about audio_format_t assumption Change-Id: I0d38241b61f70013573f4a0b9306547afe5f38ad --- media/libnbaio/NBAIO.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'media') diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index f630236..26ef8c4 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -24,11 +24,13 @@ namespace android { size_t Format_frameSize(const NBAIO_Format& format) { + // FIXME The sample format is hard-coded to AUDIO_FORMAT_PCM_16_BIT return Format_channelCount(format) * sizeof(short); } size_t Format_frameBitShift(const NBAIO_Format& format) { + // FIXME The sample format is hard-coded to AUDIO_FORMAT_PCM_16_BIT // sizeof(short) == 2, so frame size == 1 << channels return Format_channelCount(format); } -- cgit v1.1 From 4d7b3f876b21997680ae32a340d746ed1cae6ab1 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 31 Jan 2014 10:38:16 -0800 Subject: Change Format_frameBitShift() API for non-power-of-2 sizes Change-Id: Ie39ff51ab8c403ca9d9898396297efdaa3193588 --- media/libnbaio/NBAIO.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index 26ef8c4..51514de 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -28,11 +28,12 @@ size_t Format_frameSize(const NBAIO_Format& format) return Format_channelCount(format) * sizeof(short); } -size_t Format_frameBitShift(const NBAIO_Format& format) +int Format_frameBitShift(const NBAIO_Format& format) { // FIXME The sample format is hard-coded to AUDIO_FORMAT_PCM_16_BIT // sizeof(short) == 2, so frame size == 1 << channels return Format_channelCount(format); + // FIXME must return -1 for non-power of 2 } const NBAIO_Format Format_Invalid = { 0 }; -- cgit v1.1 From 1b86fe063badb5f28c467ade39be0f4008688947 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Wed, 29 Jan 2014 11:13:26 -0800 Subject: FINAL ATTEMPT: HTTP services are now provided from JAVA and made available to media code Change-Id: I9f74a86e70422187c9cf0ca1318a29019700192d --- media/libmedia/Android.mk | 2 + media/libmedia/IMediaHTTPConnection.cpp | 158 ++++++++++++++++ media/libmedia/IMediaHTTPService.cpp | 58 ++++++ media/libmedia/IMediaMetadataRetriever.cpp | 19 +- media/libmedia/IMediaPlayer.cpp | 19 +- media/libmedia/IMediaPlayerService.cpp | 30 ++- media/libmedia/SoundPool.cpp | 10 +- media/libmedia/mediametadataretriever.cpp | 7 +- media/libmedia/mediaplayer.cpp | 16 +- media/libmediaplayerservice/MediaPlayerService.cpp | 20 +- media/libmediaplayerservice/MediaPlayerService.h | 13 +- .../MetadataRetrieverClient.cpp | 7 +- .../MetadataRetrieverClient.h | 5 +- media/libmediaplayerservice/MidiFile.cpp | 4 +- media/libmediaplayerservice/MidiFile.h | 4 +- .../MidiMetadataRetriever.cpp | 8 +- .../libmediaplayerservice/MidiMetadataRetriever.h | 4 +- media/libmediaplayerservice/StagefrightPlayer.cpp | 6 +- media/libmediaplayerservice/StagefrightPlayer.h | 4 +- media/libmediaplayerservice/TestPlayerStub.cpp | 6 +- media/libmediaplayerservice/TestPlayerStub.h | 4 +- .../nuplayer/GenericSource.cpp | 3 +- .../libmediaplayerservice/nuplayer/GenericSource.h | 1 + .../nuplayer/HTTPLiveSource.cpp | 4 + .../nuplayer/HTTPLiveSource.h | 2 + media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 16 +- media/libmediaplayerservice/nuplayer/NuPlayer.h | 4 +- .../nuplayer/NuPlayerDriver.cpp | 6 +- .../nuplayer/NuPlayerDriver.h | 4 +- .../libmediaplayerservice/nuplayer/RTSPSource.cpp | 4 + media/libmediaplayerservice/nuplayer/RTSPSource.h | 2 + media/libstagefright/Android.mk | 1 + media/libstagefright/AwesomePlayer.cpp | 41 +++-- media/libstagefright/DataSource.cpp | 9 +- media/libstagefright/HTTPBase.cpp | 15 -- media/libstagefright/NuCachedSource2.cpp | 9 +- media/libstagefright/NuMediaExtractor.cpp | 6 +- media/libstagefright/StagefrightMediaScanner.cpp | 3 +- .../StagefrightMetadataRetriever.cpp | 7 +- media/libstagefright/http/Android.mk | 22 +++ media/libstagefright/http/HTTPHelper.cpp | 70 +++++++ media/libstagefright/http/HTTPHelper.h | 31 ++++ media/libstagefright/http/MediaHTTP.cpp | 201 +++++++++++++++++++++ media/libstagefright/httplive/LiveSession.cpp | 14 +- media/libstagefright/httplive/LiveSession.h | 7 +- media/libstagefright/include/AwesomePlayer.h | 3 + media/libstagefright/include/HTTPBase.h | 2 - media/libstagefright/include/SDPLoader.h | 8 +- .../include/StagefrightMetadataRetriever.h | 1 + media/libstagefright/omx/tests/OMXHarness.cpp | 4 +- media/libstagefright/rtsp/APacketSource.cpp | 2 +- media/libstagefright/rtsp/ARTSPConnection.cpp | 2 +- media/libstagefright/rtsp/Android.mk | 2 +- media/libstagefright/rtsp/SDPLoader.cpp | 19 +- media/libstagefright/timedtext/TimedTextDriver.cpp | 6 +- .../wifi-display/source/PlaybackSession.cpp | 4 +- 56 files changed, 827 insertions(+), 112 deletions(-) create mode 100644 media/libmedia/IMediaHTTPConnection.cpp create mode 100644 media/libmedia/IMediaHTTPService.cpp create mode 100644 media/libstagefright/http/Android.mk create mode 100644 media/libstagefright/http/HTTPHelper.cpp create mode 100644 media/libstagefright/http/HTTPHelper.h create mode 100644 media/libstagefright/http/MediaHTTP.cpp (limited to 'media') diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index 8aa54dc..fc4b2a5 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -25,6 +25,8 @@ LOCAL_SRC_FILES:= \ AudioRecord.cpp \ AudioSystem.cpp \ mediaplayer.cpp \ + IMediaHTTPConnection.cpp \ + IMediaHTTPService.cpp \ IMediaLogService.cpp \ IMediaPlayerService.cpp \ IMediaPlayerClient.cpp \ diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp new file mode 100644 index 0000000..622d9cf --- /dev/null +++ b/media/libmedia/IMediaHTTPConnection.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "IMediaHTTPConnection" +#include + +#include + +#include +#include +#include +#include + +namespace android { + +enum { + CONNECT = IBinder::FIRST_CALL_TRANSACTION, + DISCONNECT, + READ_AT, + GET_SIZE, + GET_MIME_TYPE, +}; + +struct BpMediaHTTPConnection : public BpInterface { + BpMediaHTTPConnection(const sp &impl) + : BpInterface(impl) { + } + + virtual bool connect( + const char *uri, const KeyedVector *headers) { + Parcel data, reply; + data.writeInterfaceToken( + IMediaHTTPConnection::getInterfaceDescriptor()); + + String16 tmp(uri); + data.writeString16(tmp); + + tmp = String16(""); + if (headers != NULL) { + for (size_t i = 0; i < headers->size(); ++i) { + String16 key(headers->keyAt(i).string()); + String16 val(headers->valueAt(i).string()); + + tmp.append(key); + tmp.append(String16(": ")); + tmp.append(val); + tmp.append(String16("\r\n")); + } + } + data.writeString16(tmp); + + remote()->transact(CONNECT, data, &reply); + + int32_t exceptionCode = reply.readExceptionCode(); + + if (exceptionCode) { + return UNKNOWN_ERROR; + } + + sp binder = reply.readStrongBinder(); + mMemory = interface_cast(binder); + + return mMemory != NULL; + } + + virtual void disconnect() { + Parcel data, reply; + data.writeInterfaceToken( + IMediaHTTPConnection::getInterfaceDescriptor()); + + remote()->transact(DISCONNECT, data, &reply); + } + + virtual ssize_t readAt(off64_t offset, void *buffer, size_t size) { + Parcel data, reply; + data.writeInterfaceToken( + IMediaHTTPConnection::getInterfaceDescriptor()); + + data.writeInt64(offset); + data.writeInt32(size); + + status_t err = remote()->transact(READ_AT, data, &reply); + CHECK_EQ(err, (status_t)OK); + + int32_t exceptionCode = reply.readExceptionCode(); + + if (exceptionCode) { + return UNKNOWN_ERROR; + } + + int32_t len = reply.readInt32(); + + if (len > 0) { + memcpy(buffer, mMemory->pointer(), len); + } + + return len; + } + + virtual off64_t getSize() { + Parcel data, reply; + data.writeInterfaceToken( + IMediaHTTPConnection::getInterfaceDescriptor()); + + remote()->transact(GET_SIZE, data, &reply); + + int32_t exceptionCode = reply.readExceptionCode(); + + if (exceptionCode) { + return UNKNOWN_ERROR; + } + + return reply.readInt64(); + } + + virtual status_t getMIMEType(String8 *mimeType) { + *mimeType = String8(""); + + Parcel data, reply; + data.writeInterfaceToken( + IMediaHTTPConnection::getInterfaceDescriptor()); + + remote()->transact(GET_MIME_TYPE, data, &reply); + + int32_t exceptionCode = reply.readExceptionCode(); + + if (exceptionCode) { + return UNKNOWN_ERROR; + } + + *mimeType = String8(reply.readString16()); + + return OK; + } + +private: + sp mMemory; +}; + +IMPLEMENT_META_INTERFACE( + MediaHTTPConnection, "android.media.IMediaHTTPConnection"); + +} // namespace android + diff --git a/media/libmedia/IMediaHTTPService.cpp b/media/libmedia/IMediaHTTPService.cpp new file mode 100644 index 0000000..1260582 --- /dev/null +++ b/media/libmedia/IMediaHTTPService.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "IMediaHTTPService" +#include + +#include + +#include +#include + +namespace android { + +enum { + MAKE_HTTP = IBinder::FIRST_CALL_TRANSACTION, +}; + +struct BpMediaHTTPService : public BpInterface { + BpMediaHTTPService(const sp &impl) + : BpInterface(impl) { + } + + virtual sp makeHTTPConnection() { + Parcel data, reply; + data.writeInterfaceToken( + IMediaHTTPService::getInterfaceDescriptor()); + + remote()->transact(MAKE_HTTP, data, &reply); + + status_t err = reply.readInt32(); + + if (err != OK) { + return NULL; + } + + return interface_cast(reply.readStrongBinder()); + } +}; + +IMPLEMENT_META_INTERFACE( + MediaHTTPService, "android.media.IMediaHTTPService"); + +} // namespace android + diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp index bb066a0..c7d9d51 100644 --- a/media/libmedia/IMediaMetadataRetriever.cpp +++ b/media/libmedia/IMediaMetadataRetriever.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -84,10 +85,16 @@ public: } status_t setDataSource( - const char *srcUrl, const KeyedVector *headers) + const sp &httpService, + const char *srcUrl, + const KeyedVector *headers) { Parcel data, reply; data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); + data.writeInt32(httpService != NULL); + if (httpService != NULL) { + data.writeStrongBinder(httpService->asBinder()); + } data.writeCString(srcUrl); if (headers == NULL) { @@ -195,6 +202,13 @@ status_t BnMediaMetadataRetriever::onTransact( } break; case SET_DATA_SOURCE_URL: { CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); + + sp httpService; + if (data.readInt32()) { + httpService = + interface_cast(data.readStrongBinder()); + } + const char* srcUrl = data.readCString(); KeyedVector headers; @@ -206,7 +220,8 @@ status_t BnMediaMetadataRetriever::onTransact( } reply->writeInt32( - setDataSource(srcUrl, numHeaders > 0 ? &headers : NULL)); + setDataSource( + httpService, srcUrl, numHeaders > 0 ? &headers : NULL)); return NO_ERROR; } break; diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp index e79bcd2..d778d05 100644 --- a/media/libmedia/IMediaPlayer.cpp +++ b/media/libmedia/IMediaPlayer.cpp @@ -21,6 +21,7 @@ #include +#include #include #include @@ -75,11 +76,17 @@ public: remote()->transact(DISCONNECT, data, &reply); } - status_t setDataSource(const char* url, + status_t setDataSource( + const sp &httpService, + const char* url, const KeyedVector* headers) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + data.writeInt32(httpService != NULL); + if (httpService != NULL) { + data.writeStrongBinder(httpService->asBinder()); + } data.writeCString(url); if (headers == NULL) { data.writeInt32(0); @@ -355,6 +362,13 @@ status_t BnMediaPlayer::onTransact( } break; case SET_DATA_SOURCE_URL: { CHECK_INTERFACE(IMediaPlayer, data, reply); + + sp httpService; + if (data.readInt32()) { + httpService = + interface_cast(data.readStrongBinder()); + } + const char* url = data.readCString(); KeyedVector headers; int32_t numHeaders = data.readInt32(); @@ -363,7 +377,8 @@ status_t BnMediaPlayer::onTransact( String8 value = data.readString8(); headers.add(key, value); } - reply->writeInt32(setDataSource(url, numHeaders > 0 ? &headers : NULL)); + reply->writeInt32(setDataSource( + httpService, url, numHeaders > 0 ? &headers : NULL)); return NO_ERROR; } break; case SET_DATA_SOURCE_FD: { diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index 3c22b4c..190adf2 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -86,12 +87,21 @@ public: return interface_cast(reply.readStrongBinder()); } - virtual status_t decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, - audio_format_t* pFormat, - const sp& heap, size_t *pSize) + virtual status_t decode( + const sp &httpService, + const char* url, + uint32_t *pSampleRate, + int* pNumChannels, + audio_format_t* pFormat, + const sp& heap, + size_t *pSize) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + data.writeInt32(httpService != NULL); + if (httpService != NULL) { + data.writeStrongBinder(httpService->asBinder()); + } data.writeCString(url); data.writeStrongBinder(heap->asBinder()); status_t status = remote()->transact(DECODE_URL, data, &reply); @@ -222,13 +232,25 @@ status_t BnMediaPlayerService::onTransact( } break; case DECODE_URL: { CHECK_INTERFACE(IMediaPlayerService, data, reply); + sp httpService; + if (data.readInt32()) { + httpService = + interface_cast(data.readStrongBinder()); + } const char* url = data.readCString(); sp heap = interface_cast(data.readStrongBinder()); uint32_t sampleRate; int numChannels; audio_format_t format; size_t size; - status_t status = decode(url, &sampleRate, &numChannels, &format, heap, &size); + status_t status = + decode(httpService, + url, + &sampleRate, + &numChannels, + &format, + heap, + &size); reply->writeInt32(status); if (status == NO_ERROR) { reply->writeInt32(sampleRate); diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp index 98acd1f..9ed010d 100644 --- a/media/libmedia/SoundPool.cpp +++ b/media/libmedia/SoundPool.cpp @@ -21,6 +21,7 @@ #define USE_SHARED_MEM_BUFFER #include +#include #include #include #include "SoundPoolThread.h" @@ -496,7 +497,14 @@ status_t Sample::doLoad() ALOGV("Start decode"); if (mUrl) { - status = MediaPlayer::decode(mUrl, &sampleRate, &numChannels, &format, mHeap, &mSize); + status = MediaPlayer::decode( + NULL /* httpService */, + mUrl, + &sampleRate, + &numChannels, + &format, + mHeap, + &mSize); } else { status = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format, mHeap, &mSize); diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp index bad2494..1d6bb6f 100644 --- a/media/libmedia/mediametadataretriever.cpp +++ b/media/libmedia/mediametadataretriever.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -93,7 +94,9 @@ void MediaMetadataRetriever::disconnect() } status_t MediaMetadataRetriever::setDataSource( - const char *srcUrl, const KeyedVector *headers) + const sp &httpService, + const char *srcUrl, + const KeyedVector *headers) { ALOGV("setDataSource"); Mutex::Autolock _l(mLock); @@ -106,7 +109,7 @@ status_t MediaMetadataRetriever::setDataSource( return UNKNOWN_ERROR; } ALOGV("data source (%s)", srcUrl); - return mRetriever->setDataSource(srcUrl, headers); + return mRetriever->setDataSource(httpService, srcUrl, headers); } status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length) diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 7a6f31d..a4d4b1a 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -136,6 +136,7 @@ status_t MediaPlayer::attachNewPlayer(const sp& player) } status_t MediaPlayer::setDataSource( + const sp &httpService, const char *url, const KeyedVector *headers) { ALOGV("setDataSource(%s)", url); @@ -145,7 +146,7 @@ status_t MediaPlayer::setDataSource( if (service != 0) { sp player(service->create(this, mAudioSessionId)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || - (NO_ERROR != player->setDataSource(url, headers))) { + (NO_ERROR != player->setDataSource(httpService, url, headers))) { player.clear(); } err = attachNewPlayer(player); @@ -776,15 +777,20 @@ void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj) } } -/*static*/ status_t MediaPlayer::decode(const char* url, uint32_t *pSampleRate, - int* pNumChannels, audio_format_t* pFormat, - const sp& heap, size_t *pSize) +/*static*/ status_t MediaPlayer::decode( + const sp &httpService, + const char* url, + uint32_t *pSampleRate, + int* pNumChannels, + audio_format_t* pFormat, + const sp& heap, + size_t *pSize) { ALOGV("decode(%s)", url); status_t status; const sp& service = getMediaPlayerService(); if (service != 0) { - status = service->decode(url, pSampleRate, pNumChannels, pFormat, heap, pSize); + status = service->decode(httpService, url, pSampleRate, pNumChannels, pFormat, heap, pSize); } else { ALOGE("Unable to locate media service"); status = DEAD_OBJECT; diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 9ac9105..1c6018c 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -622,7 +623,9 @@ void MediaPlayerService::Client::setDataSource_post( } status_t MediaPlayerService::Client::setDataSource( - const char *url, const KeyedVector *headers) + const sp &httpService, + const char *url, + const KeyedVector *headers) { ALOGV("setDataSource(%s)", url); if (url == NULL) @@ -657,7 +660,7 @@ status_t MediaPlayerService::Client::setDataSource( return NO_INIT; } - setDataSource_post(p, p->setDataSource(url, headers)); + setDataSource_post(p, p->setDataSource(httpService, url, headers)); return mStatus; } } @@ -1176,9 +1179,14 @@ int Antagonizer::callbackThread(void* user) } #endif -status_t MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, - audio_format_t* pFormat, - const sp& heap, size_t *pSize) +status_t MediaPlayerService::decode( + const sp &httpService, + const char* url, + uint32_t *pSampleRate, + int* pNumChannels, + audio_format_t* pFormat, + const sp& heap, + size_t *pSize) { ALOGV("decode(%s)", url); sp player; @@ -1206,7 +1214,7 @@ status_t MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* static_cast(player.get())->setAudioSink(cache); // set data source - if (player->setDataSource(url) != NO_ERROR) goto Exit; + if (player->setDataSource(httpService, url) != NO_ERROR) goto Exit; ALOGV("prepare"); player->prepareAsync(); diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 9c084e1..6749f4a 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -256,9 +256,15 @@ public: virtual sp create(const sp& client, int audioSessionId); - virtual status_t decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, - audio_format_t* pFormat, - const sp& heap, size_t *pSize); + virtual status_t decode( + const sp &httpService, + const char* url, + uint32_t *pSampleRate, + int* pNumChannels, + audio_format_t* pFormat, + const sp& heap, + size_t *pSize); + virtual status_t decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat, @@ -356,6 +362,7 @@ private: sp createPlayer(player_type playerType); virtual status_t setDataSource( + const sp &httpService, const char *url, const KeyedVector *headers); diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp index 348957f..c61cf89 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp +++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -106,7 +107,9 @@ static sp createRetriever(player_type playerType) } status_t MetadataRetrieverClient::setDataSource( - const char *url, const KeyedVector *headers) + const sp &httpService, + const char *url, + const KeyedVector *headers) { ALOGV("setDataSource(%s)", url); Mutex::Autolock lock(mLock); @@ -127,7 +130,7 @@ status_t MetadataRetrieverClient::setDataSource( ALOGV("player type = %d", playerType); sp p = createRetriever(playerType); if (p == NULL) return NO_INIT; - status_t ret = p->setDataSource(url, headers); + status_t ret = p->setDataSource(httpService, url, headers); if (ret == NO_ERROR) mRetriever = p; return ret; } diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h index f08f933..9d3fbe9 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.h +++ b/media/libmediaplayerservice/MetadataRetrieverClient.h @@ -30,6 +30,7 @@ namespace android { +struct IMediaHTTPService; class IMediaPlayerService; class MemoryDealer; @@ -43,7 +44,9 @@ public: virtual void disconnect(); virtual status_t setDataSource( - const char *url, const KeyedVector *headers); + const sp &httpService, + const char *url, + const KeyedVector *headers); virtual status_t setDataSource(int fd, int64_t offset, int64_t length); virtual sp getFrameAtTime(int64_t timeUs, int option); diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp index 0a6aa90..deeddd1 100644 --- a/media/libmediaplayerservice/MidiFile.cpp +++ b/media/libmediaplayerservice/MidiFile.cpp @@ -114,7 +114,9 @@ MidiFile::~MidiFile() { } status_t MidiFile::setDataSource( - const char* path, const KeyedVector *) { + const sp &httpService, + const char* path, + const KeyedVector *) { ALOGV("MidiFile::setDataSource url=%s", path); Mutex::Autolock lock(mMutex); diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h index 24d59b4..12802ba 100644 --- a/media/libmediaplayerservice/MidiFile.h +++ b/media/libmediaplayerservice/MidiFile.h @@ -32,7 +32,9 @@ public: virtual status_t initCheck(); virtual status_t setDataSource( - const char* path, const KeyedVector *headers); + const sp &httpService, + const char* path, + const KeyedVector *headers); virtual status_t setDataSource(int fd, int64_t offset, int64_t length); virtual status_t setVideoSurfaceTexture( diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.cpp b/media/libmediaplayerservice/MidiMetadataRetriever.cpp index 465209f..f3cf6ef 100644 --- a/media/libmediaplayerservice/MidiMetadataRetriever.cpp +++ b/media/libmediaplayerservice/MidiMetadataRetriever.cpp @@ -22,6 +22,8 @@ #include "MidiMetadataRetriever.h" #include +#include + namespace android { static status_t ERROR_NOT_OPEN = -1; @@ -36,7 +38,9 @@ void MidiMetadataRetriever::clearMetadataValues() } status_t MidiMetadataRetriever::setDataSource( - const char *url, const KeyedVector *headers) + const sp &httpService, + const char *url, + const KeyedVector *headers) { ALOGV("setDataSource: %s", url? url: "NULL pointer"); Mutex::Autolock lock(mLock); @@ -44,7 +48,7 @@ status_t MidiMetadataRetriever::setDataSource( if (mMidiPlayer == 0) { mMidiPlayer = new MidiFile(); } - return mMidiPlayer->setDataSource(url, headers); + return mMidiPlayer->setDataSource(httpService, url, headers); } status_t MidiMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length) diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.h b/media/libmediaplayerservice/MidiMetadataRetriever.h index 4cee42d..b8214ee 100644 --- a/media/libmediaplayerservice/MidiMetadataRetriever.h +++ b/media/libmediaplayerservice/MidiMetadataRetriever.h @@ -32,7 +32,9 @@ public: ~MidiMetadataRetriever() {} virtual status_t setDataSource( - const char *url, const KeyedVector *headers); + const sp &httpService, + const char *url, + const KeyedVector *headers); virtual status_t setDataSource(int fd, int64_t offset, int64_t length); virtual const char* extractMetadata(int keyCode); diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp index de61d9b..b19e8bf 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.cpp +++ b/media/libmediaplayerservice/StagefrightPlayer.cpp @@ -54,8 +54,10 @@ status_t StagefrightPlayer::setUID(uid_t uid) { } status_t StagefrightPlayer::setDataSource( - const char *url, const KeyedVector *headers) { - return mPlayer->setDataSource(url, headers); + const sp &httpService, + const char *url, + const KeyedVector *headers) { + return mPlayer->setDataSource(httpService, url, headers); } // Warning: The filedescriptor passed into this method will only be valid until diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h index 600945e..e6c30ff 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.h +++ b/media/libmediaplayerservice/StagefrightPlayer.h @@ -34,7 +34,9 @@ public: virtual status_t setUID(uid_t uid); virtual status_t setDataSource( - const char *url, const KeyedVector *headers); + const sp &httpService, + const char *url, + const KeyedVector *headers); virtual status_t setDataSource(int fd, int64_t offset, int64_t length); diff --git a/media/libmediaplayerservice/TestPlayerStub.cpp b/media/libmediaplayerservice/TestPlayerStub.cpp index 5d9728a..5795773 100644 --- a/media/libmediaplayerservice/TestPlayerStub.cpp +++ b/media/libmediaplayerservice/TestPlayerStub.cpp @@ -113,7 +113,9 @@ status_t TestPlayerStub::parseUrl() // Create the test player. // Call setDataSource on the test player with the url in param. status_t TestPlayerStub::setDataSource( - const char *url, const KeyedVector *headers) { + const sp &httpService, + const char *url, + const KeyedVector *headers) { if (!isTestUrl(url) || NULL != mHandle) { return INVALID_OPERATION; } @@ -162,7 +164,7 @@ status_t TestPlayerStub::setDataSource( } mPlayer = (*mNewPlayer)(); - return mPlayer->setDataSource(mContentUrl, headers); + return mPlayer->setDataSource(httpService, mContentUrl, headers); } // Internal cleanup. diff --git a/media/libmediaplayerservice/TestPlayerStub.h b/media/libmediaplayerservice/TestPlayerStub.h index a3802eb..55bf2c8 100644 --- a/media/libmediaplayerservice/TestPlayerStub.h +++ b/media/libmediaplayerservice/TestPlayerStub.h @@ -66,7 +66,9 @@ class TestPlayerStub : public MediaPlayerInterface { // @param url Should be a test url. See class comment. virtual status_t setDataSource( - const char* url, const KeyedVector *headers); + const sp &httpService, + const char* url, + const KeyedVector *headers); // Test player for a file descriptor source is not supported. virtual status_t setDataSource(int, int64_t, int64_t) { diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index b04e7a6..837e5b6 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -33,6 +33,7 @@ namespace android { NuPlayer::GenericSource::GenericSource( const sp ¬ify, + const sp &httpService, const char *url, const KeyedVector *headers, bool uidValid, @@ -43,7 +44,7 @@ NuPlayer::GenericSource::GenericSource( DataSource::RegisterDefaultSniffers(); sp dataSource = - DataSource::CreateFromURI(url, headers); + DataSource::CreateFromURI(httpService, url, headers); CHECK(dataSource != NULL); initFromDataSource(dataSource); diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 2da680c..6d7e1d6 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -33,6 +33,7 @@ struct MediaSource; struct NuPlayer::GenericSource : public NuPlayer::Source { GenericSource( const sp ¬ify, + const sp &httpService, const char *url, const KeyedVector *headers, bool uidValid = false, diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp index f1782cc..e4145e6 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp @@ -24,6 +24,7 @@ #include "LiveDataSource.h" #include "LiveSession.h" +#include #include #include #include @@ -34,10 +35,12 @@ namespace android { NuPlayer::HTTPLiveSource::HTTPLiveSource( const sp ¬ify, + const sp &httpService, const char *url, const KeyedVector *headers, bool uidValid, uid_t uid) : Source(notify), + mHTTPService(httpService), mURL(url), mUIDValid(uidValid), mUID(uid), @@ -79,6 +82,7 @@ void NuPlayer::HTTPLiveSource::prepareAsync() { mLiveSession = new LiveSession( notify, (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0, + mHTTPService, mUIDValid, mUID); diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h index bcc3f8b..a60d38e 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h @@ -28,6 +28,7 @@ struct LiveSession; struct NuPlayer::HTTPLiveSource : public NuPlayer::Source { HTTPLiveSource( const sp ¬ify, + const sp &httpService, const char *url, const KeyedVector *headers, bool uidValid = false, @@ -61,6 +62,7 @@ private: kWhatFetchSubtitleData, }; + sp mHTTPService; AString mURL; KeyedVector mExtraHeaders; bool mUIDValid; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 3669a5b..93fe594 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -212,7 +212,9 @@ static bool IsHTTPLiveURL(const char *url) { } void NuPlayer::setDataSourceAsync( - const char *url, const KeyedVector *headers) { + const sp &httpService, + const char *url, + const KeyedVector *headers) { sp msg = new AMessage(kWhatSetDataSource, id()); size_t len = strlen(url); @@ -220,16 +222,20 @@ void NuPlayer::setDataSourceAsync( sp source; if (IsHTTPLiveURL(url)) { - source = new HTTPLiveSource(notify, url, headers, mUIDValid, mUID); + source = new HTTPLiveSource( + notify, httpService, url, headers, mUIDValid, mUID); } else if (!strncasecmp(url, "rtsp://", 7)) { - source = new RTSPSource(notify, url, headers, mUIDValid, mUID); + source = new RTSPSource( + notify, httpService, url, headers, mUIDValid, mUID); } else if ((!strncasecmp(url, "http://", 7) || !strncasecmp(url, "https://", 8)) && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) || strstr(url, ".sdp?"))) { - source = new RTSPSource(notify, url, headers, mUIDValid, mUID, true); + source = new RTSPSource( + notify, httpService, url, headers, mUIDValid, mUID, true); } else { - source = new GenericSource(notify, url, headers, mUIDValid, mUID); + source = new GenericSource( + notify, httpService, url, headers, mUIDValid, mUID); } msg->setObject("source", source); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 590e1f2..9dfe4a0 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -38,7 +38,9 @@ struct NuPlayer : public AHandler { void setDataSourceAsync(const sp &source); void setDataSourceAsync( - const char *url, const KeyedVector *headers); + const sp &httpService, + const char *url, + const KeyedVector *headers); void setDataSourceAsync(int fd, int64_t offset, int64_t length); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 47834fd..d35d1df 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -70,7 +70,9 @@ status_t NuPlayerDriver::setUID(uid_t uid) { } status_t NuPlayerDriver::setDataSource( - const char *url, const KeyedVector *headers) { + const sp &httpService, + const char *url, + const KeyedVector *headers) { Mutex::Autolock autoLock(mLock); if (mState != STATE_IDLE) { @@ -79,7 +81,7 @@ status_t NuPlayerDriver::setDataSource( mState = STATE_SET_DATASOURCE_PENDING; - mPlayer->setDataSourceAsync(url, headers); + mPlayer->setDataSourceAsync(httpService, url, headers); while (mState == STATE_SET_DATASOURCE_PENDING) { mCondition.wait(mLock); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index 99f72a6..0148fb1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -31,7 +31,9 @@ struct NuPlayerDriver : public MediaPlayerInterface { virtual status_t setUID(uid_t uid); virtual status_t setDataSource( - const char *url, const KeyedVector *headers); + const sp &httpService, + const char *url, + const KeyedVector *headers); virtual status_t setDataSource(int fd, int64_t offset, int64_t length); diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index 18cf6d1..6cdf0c9 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -24,6 +24,7 @@ #include "MyHandler.h" #include "SDPLoader.h" +#include #include #include @@ -33,12 +34,14 @@ const int64_t kNearEOSTimeoutUs = 2000000ll; // 2 secs NuPlayer::RTSPSource::RTSPSource( const sp ¬ify, + const sp &httpService, const char *url, const KeyedVector *headers, bool uidValid, uid_t uid, bool isSDP) : Source(notify), + mHTTPService(httpService), mURL(url), mUIDValid(uidValid), mUID(uid), @@ -92,6 +95,7 @@ void NuPlayer::RTSPSource::prepareAsync() { if (mIsSDP) { mSDPLoader = new SDPLoader(notify, (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0, + mHTTPService, mUIDValid, mUID); mSDPLoader->load( diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h index 8cf34a0..3718bf9 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.h +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h @@ -34,6 +34,7 @@ struct SDPLoader; struct NuPlayer::RTSPSource : public NuPlayer::Source { RTSPSource( const sp ¬ify, + const sp &httpService, const char *url, const KeyedVector *headers, bool uidValid = false, @@ -88,6 +89,7 @@ private: bool mNPTMappingValid; }; + sp mHTTPService; AString mURL; KeyedVector mExtraHeaders; bool mUIDValid; diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 6a2a696..c6cee5d 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -32,6 +32,7 @@ LOCAL_SRC_FILES:= \ MediaCodecList.cpp \ MediaDefs.cpp \ MediaExtractor.cpp \ + http/MediaHTTP.cpp \ MediaMuxer.cpp \ MediaSource.cpp \ MetaData.cpp \ diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index aae6800..67ea052 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -34,6 +34,8 @@ #include #include +#include +#include #include #include #include @@ -44,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -276,15 +279,20 @@ void AwesomePlayer::setUID(uid_t uid) { } status_t AwesomePlayer::setDataSource( - const char *uri, const KeyedVector *headers) { + const sp &httpService, + const char *uri, + const KeyedVector *headers) { Mutex::Autolock autoLock(mLock); - return setDataSource_l(uri, headers); + return setDataSource_l(httpService, uri, headers); } status_t AwesomePlayer::setDataSource_l( - const char *uri, const KeyedVector *headers) { + const sp &httpService, + const char *uri, + const KeyedVector *headers) { reset_l(); + mHTTPService = httpService; mUri = uri; if (headers) { @@ -581,6 +589,7 @@ void AwesomePlayer::reset_l() { mSeekNotificationSent = true; mSeekTimeUs = 0; + mHTTPService.clear(); mUri.setTo(""); mUriHeaders.clear(); @@ -1482,7 +1491,7 @@ void AwesomePlayer::addTextSource_l(size_t trackIndex, const sp& so CHECK(source != NULL); if (mTextDriver == NULL) { - mTextDriver = new TimedTextDriver(mListener); + mTextDriver = new TimedTextDriver(mListener, mHTTPService); } mTextDriver->addInBandTextSource(trackIndex, source); @@ -2192,15 +2201,14 @@ status_t AwesomePlayer::finishSetDataSource_l() { if (!strncasecmp("http://", mUri.string(), 7) || !strncasecmp("https://", mUri.string(), 8) || isWidevineStreaming) { - mConnectingDataSource = HTTPBase::Create( - (mFlags & INCOGNITO) - ? HTTPBase::kFlagIncognito - : 0); - - if (mUIDValid) { - mConnectingDataSource->setUID(mUID); + if (mHTTPService == NULL) { + ALOGE("Attempt to play media from http URI without HTTP service."); + return UNKNOWN_ERROR; } + sp conn = mHTTPService->makeHTTPConnection(); + mConnectingDataSource = new MediaHTTP(conn); + String8 cacheConfig; bool disconnectAtHighwatermark; NuCachedSource2::RemoveCacheSpecificHeaders( @@ -2316,7 +2324,8 @@ status_t AwesomePlayer::finishSetDataSource_l() { } } } else { - dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders); + dataSource = DataSource::CreateFromURI( + mHTTPService, mUri.string(), &mUriHeaders); } if (dataSource == NULL) { @@ -2758,7 +2767,7 @@ status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) { { Mutex::Autolock autoLock(mLock); if (mTextDriver == NULL) { - mTextDriver = new TimedTextDriver(mListener); + mTextDriver = new TimedTextDriver(mListener, mHTTPService); } // String values written in Parcel are UTF-16 values. String8 uri(request.readString16()); @@ -2770,7 +2779,7 @@ status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) { { Mutex::Autolock autoLock(mLock); if (mTextDriver == NULL) { - mTextDriver = new TimedTextDriver(mListener); + mTextDriver = new TimedTextDriver(mListener, mHTTPService); } int fd = request.readFileDescriptor(); off64_t offset = request.readInt64(); @@ -2899,6 +2908,8 @@ void AwesomePlayer::onAudioTearDownEvent() { // get current position so we can start recreated stream from here getPosition(&mAudioTearDownPosition); + sp savedHTTPService = mHTTPService; + // Reset and recreate reset_l(); @@ -2908,7 +2919,7 @@ void AwesomePlayer::onAudioTearDownEvent() { mFileSource = fileSource; err = setDataSource_l(fileSource); } else { - err = setDataSource_l(uri, &uriHeaders); + err = setDataSource_l(savedHTTPService, uri, &uriHeaders); } mFlags |= PREPARING; diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 97987e2..9ff9ca2 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -35,10 +35,13 @@ #include "matroska/MatroskaExtractor.h" +#include +#include #include #include #include #include +#include #include #include @@ -180,7 +183,9 @@ void DataSource::RegisterDefaultSniffers() { // static sp DataSource::CreateFromURI( - const char *uri, const KeyedVector *headers) { + const sp &httpService, + const char *uri, + const KeyedVector *headers) { bool isWidevine = !strncasecmp("widevine://", uri, 11); sp source; @@ -189,7 +194,7 @@ sp DataSource::CreateFromURI( } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8) || isWidevine) { - sp httpSource = HTTPBase::Create(); + sp httpSource = new MediaHTTP(httpService->makeHTTPConnection()); String8 tmp; if (isWidevine) { diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp index 5fa4b6f..f3b1ef9 100644 --- a/media/libstagefright/HTTPBase.cpp +++ b/media/libstagefright/HTTPBase.cpp @@ -46,21 +46,6 @@ HTTPBase::HTTPBase() } // static -sp HTTPBase::Create(uint32_t flags) { -#if CHROMIUM_AVAILABLE - HTTPBase *dataSource = createChromiumHTTPDataSource(flags); - if (dataSource) { - return dataSource; - } -#endif - { - TRESPASS(); - - return NULL; - } -} - -// static status_t HTTPBase::UpdateProxyConfig( const char *host, int32_t port, const char *exclusionList) { #if CHROMIUM_AVAILABLE diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index 05e599b..1287fb1 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -213,7 +213,14 @@ NuCachedSource2::NuCachedSource2( mLooper->setName("NuCachedSource2"); mLooper->registerHandler(mReflector); - mLooper->start(); + + // Since it may not be obvious why our looper thread needs to be + // able to call into java since it doesn't appear to do so at all... + // IMediaHTTPConnection may be (and most likely is) implemented in JAVA + // and a local JAVA IBinder will call directly into JNI methods. + // So whenever we call DataSource::readAt it may end up in a call to + // IMediaHTTPConnection::readAt and therefore call back into JAVA. + mLooper->start(false /* runOnCallingThread */, true /* canCallJava */); Mutex::Autolock autoLock(mLock); (new AMessage(kWhatFetchMore, mReflector->id()))->post(); diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp index 7bc7da2..64f56e9 100644 --- a/media/libstagefright/NuMediaExtractor.cpp +++ b/media/libstagefright/NuMediaExtractor.cpp @@ -58,7 +58,9 @@ NuMediaExtractor::~NuMediaExtractor() { } status_t NuMediaExtractor::setDataSource( - const char *path, const KeyedVector *headers) { + const sp &httpService, + const char *path, + const KeyedVector *headers) { Mutex::Autolock autoLock(mLock); if (mImpl != NULL) { @@ -66,7 +68,7 @@ status_t NuMediaExtractor::setDataSource( } sp dataSource = - DataSource::CreateFromURI(path, headers); + DataSource::CreateFromURI(httpService, path, headers); if (dataSource == NULL) { return -ENOENT; diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp index af8186c..edd12fc 100644 --- a/media/libstagefright/StagefrightMediaScanner.cpp +++ b/media/libstagefright/StagefrightMediaScanner.cpp @@ -24,6 +24,7 @@ #include +#include #include #include @@ -147,7 +148,7 @@ MediaScanResult StagefrightMediaScanner::processFileInternal( status_t status; if (fd < 0) { // couldn't open it locally, maybe the media server can? - status = mRetriever->setDataSource(path); + status = mRetriever->setDataSource(NULL /* httpService */, path); } else { status = mRetriever->setDataSource(fd, 0, 0x7ffffffffffffffL); close(fd); diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index 19af4fb..b4f906e 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -20,6 +20,7 @@ #include "include/StagefrightMetadataRetriever.h" +#include #include #include #include @@ -50,7 +51,9 @@ StagefrightMetadataRetriever::~StagefrightMetadataRetriever() { } status_t StagefrightMetadataRetriever::setDataSource( - const char *uri, const KeyedVector *headers) { + const sp &httpService, + const char *uri, + const KeyedVector *headers) { ALOGV("setDataSource(%s)", uri); mParsedMetaData = false; @@ -58,7 +61,7 @@ status_t StagefrightMetadataRetriever::setDataSource( delete mAlbumArt; mAlbumArt = NULL; - mSource = DataSource::CreateFromURI(uri, headers); + mSource = DataSource::CreateFromURI(httpService, uri, headers); if (mSource == NULL) { ALOGE("Unable to create data source for '%s'.", uri); diff --git a/media/libstagefright/http/Android.mk b/media/libstagefright/http/Android.mk new file mode 100644 index 0000000..baef9ab --- /dev/null +++ b/media/libstagefright/http/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + HTTPHelper.cpp \ + +LOCAL_C_INCLUDES:= \ + $(TOP)/frameworks/av/media/libstagefright \ + $(TOP)/frameworks/native/include/media/openmax \ + $(TOP)/frameworks/base/core/jni \ + +LOCAL_SHARED_LIBRARIES := \ + libstagefright liblog libutils libbinder libstagefright_foundation \ + libandroid_runtime \ + libmedia + +LOCAL_MODULE:= libstagefright_http_support + +LOCAL_CFLAGS += -Wno-multichar + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/http/HTTPHelper.cpp b/media/libstagefright/http/HTTPHelper.cpp new file mode 100644 index 0000000..77845e2 --- /dev/null +++ b/media/libstagefright/http/HTTPHelper.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "HTTPHelper" +#include + +#include "HTTPHelper.h" + +#include "android_runtime/AndroidRuntime.h" +#include "android_util_Binder.h" +#include +#include +#include +#include "jni.h" + +namespace android { + +sp CreateHTTPServiceInCurrentJavaContext() { + if (AndroidRuntime::getJavaVM() == NULL) { + ALOGE("CreateHTTPServiceInCurrentJavaContext called outside " + "JAVA environment."); + return NULL; + } + + JNIEnv *env = AndroidRuntime::getJNIEnv(); + + ScopedLocalRef clazz( + env, env->FindClass("android/media/MediaHTTPService")); + CHECK(clazz.get() != NULL); + + jmethodID constructID = env->GetMethodID(clazz.get(), "", "()V"); + CHECK(constructID != NULL); + + ScopedLocalRef httpServiceObj( + env, env->NewObject(clazz.get(), constructID)); + + sp httpService; + if (httpServiceObj.get() != NULL) { + jmethodID asBinderID = + env->GetMethodID(clazz.get(), "asBinder", "()Landroid/os/IBinder;"); + CHECK(asBinderID != NULL); + + ScopedLocalRef httpServiceBinderObj( + env, env->CallObjectMethod(httpServiceObj.get(), asBinderID)); + CHECK(httpServiceBinderObj.get() != NULL); + + sp binder = + ibinderForJavaObject(env, httpServiceBinderObj.get()); + + httpService = interface_cast(binder); + } + + return httpService; +} + +} // namespace android diff --git a/media/libstagefright/http/HTTPHelper.h b/media/libstagefright/http/HTTPHelper.h new file mode 100644 index 0000000..8aef115 --- /dev/null +++ b/media/libstagefright/http/HTTPHelper.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014 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 HTTP_HELPER_H_ + +#define HTTP_HELPER_H_ + +#include + +namespace android { + +struct IMediaHTTPService; + +sp CreateHTTPServiceInCurrentJavaContext(); + +} // namespace android + +#endif // HTTP_HELPER_H_ diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp new file mode 100644 index 0000000..157d967 --- /dev/null +++ b/media/libstagefright/http/MediaHTTP.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaHTTP" +#include + +#include + +#include +#include +#include +#include + +#include + +namespace android { + +MediaHTTP::MediaHTTP(const sp &conn) + : mInitCheck(NO_INIT), + mHTTPConnection(conn), + mCachedSizeValid(false), + mCachedSize(0ll), + mDrmManagerClient(NULL) { + mInitCheck = OK; +} + +MediaHTTP::~MediaHTTP() { + clearDRMState_l(); +} + +status_t MediaHTTP::connect( + const char *uri, + const KeyedVector *headers, + off64_t /* offset */) { + if (mInitCheck != OK) { + return mInitCheck; + } + + KeyedVector extHeaders; + if (headers != NULL) { + extHeaders = *headers; + } + extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str())); + + bool success = mHTTPConnection->connect(uri, &extHeaders); + + mLastHeaders = extHeaders; + mLastURI = uri; + + mCachedSizeValid = false; + + return success ? OK : UNKNOWN_ERROR; +} + +void MediaHTTP::disconnect() { + if (mInitCheck != OK) { + return; + } + + mHTTPConnection->disconnect(); +} + +status_t MediaHTTP::initCheck() const { + return mInitCheck; +} + +ssize_t MediaHTTP::readAt(off64_t offset, void *data, size_t size) { + if (mInitCheck != OK) { + return mInitCheck; + } + + int64_t startTimeUs = ALooper::GetNowUs(); + + size_t numBytesRead = 0; + while (numBytesRead < size) { + size_t copy = size - numBytesRead; + + if (copy > 64 * 1024) { + // limit the buffer sizes transferred across binder boundaries + // to avoid spurious transaction failures. + copy = 64 * 1024; + } + + ssize_t n = mHTTPConnection->readAt( + offset + numBytesRead, (uint8_t *)data + numBytesRead, copy); + + if (n < 0) { + return n; + } else if (n == 0) { + break; + } + + numBytesRead += n; + } + + int64_t delayUs = ALooper::GetNowUs() - startTimeUs; + + addBandwidthMeasurement(numBytesRead, delayUs); + + return numBytesRead; +} + +status_t MediaHTTP::getSize(off64_t *size) { + if (mInitCheck != OK) { + return mInitCheck; + } + + // Caching the returned size so that it stays valid even after a + // disconnect. NuCachedSource2 relies on this. + + if (!mCachedSizeValid) { + mCachedSize = mHTTPConnection->getSize(); + mCachedSizeValid = true; + } + + *size = mCachedSize; + + return *size < 0 ? *size : OK; +} + +uint32_t MediaHTTP::flags() { + return kWantsPrefetching | kIsHTTPBasedSource; +} + +status_t MediaHTTP::reconnectAtOffset(off64_t offset) { + return connect(mLastURI.c_str(), &mLastHeaders, offset); +} + +// DRM... + +sp MediaHTTP::DrmInitialization(const char* mime) { + if (mDrmManagerClient == NULL) { + mDrmManagerClient = new DrmManagerClient(); + } + + if (mDrmManagerClient == NULL) { + return NULL; + } + + if (mDecryptHandle == NULL) { + mDecryptHandle = mDrmManagerClient->openDecryptSession( + String8(mLastURI.c_str()), mime); + } + + if (mDecryptHandle == NULL) { + delete mDrmManagerClient; + mDrmManagerClient = NULL; + } + + return mDecryptHandle; +} + +void MediaHTTP::getDrmInfo( + sp &handle, DrmManagerClient **client) { + handle = mDecryptHandle; + *client = mDrmManagerClient; +} + +String8 MediaHTTP::getUri() { + return String8(mLastURI.c_str()); +} + +String8 MediaHTTP::getMIMEType() const { + if (mInitCheck != OK) { + return String8("application/octet-stream"); + } + + String8 mimeType; + status_t err = mHTTPConnection->getMIMEType(&mimeType); + + if (err != OK) { + return String8("application/octet-stream"); + } + + return mimeType; +} + +void MediaHTTP::clearDRMState_l() { + if (mDecryptHandle != NULL) { + // To release mDecryptHandle + CHECK(mDrmManagerClient); + mDrmManagerClient->closeDecryptSession(mDecryptHandle); + mDecryptHandle = NULL; + } +} + +} // namespace android diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 233db44..dbdca5c 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -27,6 +27,8 @@ #include "mpeg2ts/AnotherPacketSource.h" #include +#include +#include #include #include #include @@ -34,6 +36,7 @@ #include #include #include +#include #include #include @@ -44,17 +47,16 @@ namespace android { LiveSession::LiveSession( - const sp ¬ify, uint32_t flags, bool uidValid, uid_t uid) + const sp ¬ify, uint32_t flags, + const sp &httpService, + bool uidValid, uid_t uid) : mNotify(notify), mFlags(flags), + mHTTPService(httpService), mUIDValid(uidValid), mUID(uid), mInPreparationPhase(true), - mHTTPDataSource( - HTTPBase::Create( - (mFlags & kFlagIncognito) - ? HTTPBase::kFlagIncognito - : 0)), + mHTTPDataSource(new MediaHTTP(mHTTPService->makeHTTPConnection())), mPrevBandwidthIndex(-1), mStreamMask(0), mCheckBandwidthGeneration(0), diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 99b480a8..16fc65a 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -28,6 +28,7 @@ struct ABuffer; struct AnotherPacketSource; struct DataSource; struct HTTPBase; +struct IMediaHTTPService; struct LiveDataSource; struct M3UParser; struct PlaylistFetcher; @@ -40,7 +41,10 @@ struct LiveSession : public AHandler { }; LiveSession( const sp ¬ify, - uint32_t flags = 0, bool uidValid = false, uid_t uid = 0); + uint32_t flags, + const sp &httpService, + bool uidValid = false, + uid_t uid = 0); enum StreamType { STREAMTYPE_AUDIO = 1, @@ -107,6 +111,7 @@ private: sp mNotify; uint32_t mFlags; + sp mHTTPService; bool mUIDValid; uid_t mUID; diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 271df8e..a81bbba 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -63,6 +63,7 @@ struct AwesomePlayer { void setUID(uid_t uid); status_t setDataSource( + const sp &httpService, const char *uri, const KeyedVector *headers = NULL); @@ -159,6 +160,7 @@ private: SystemTimeSource mSystemTimeSource; TimeSource *mTimeSource; + sp mHTTPService; String8 mUri; KeyedVector mUriHeaders; @@ -247,6 +249,7 @@ private: sp mExtractor; status_t setDataSource_l( + const sp &httpService, const char *uri, const KeyedVector *headers = NULL); diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h index d4b7f9f..f891b56 100644 --- a/media/libstagefright/include/HTTPBase.h +++ b/media/libstagefright/include/HTTPBase.h @@ -54,8 +54,6 @@ struct HTTPBase : public DataSource { void setUID(uid_t uid); bool getUID(uid_t *uid) const; - static sp Create(uint32_t flags = 0); - static void RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag); static void UnRegisterSocketUserTag(int sockfd); diff --git a/media/libstagefright/include/SDPLoader.h b/media/libstagefright/include/SDPLoader.h index ca59dc0..223bd92 100644 --- a/media/libstagefright/include/SDPLoader.h +++ b/media/libstagefright/include/SDPLoader.h @@ -25,6 +25,7 @@ namespace android { struct HTTPBase; +struct IMediaHTTPService; struct SDPLoader : public AHandler { enum Flags { @@ -34,7 +35,12 @@ struct SDPLoader : public AHandler { enum { kWhatSDPLoaded = 'sdpl' }; - SDPLoader(const sp ¬ify, uint32_t flags = 0, bool uidValid = false, uid_t uid = 0); + SDPLoader( + const sp ¬ify, + uint32_t flags, + const sp &httpService, + bool uidValid = false, + uid_t uid = 0); void load(const char* url, const KeyedVector *headers); diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h index b02ed0e..6632c27 100644 --- a/media/libstagefright/include/StagefrightMetadataRetriever.h +++ b/media/libstagefright/include/StagefrightMetadataRetriever.h @@ -33,6 +33,7 @@ struct StagefrightMetadataRetriever : public MediaMetadataRetrieverInterface { virtual ~StagefrightMetadataRetriever(); virtual status_t setDataSource( + const sp &httpService, const char *url, const KeyedVector *headers); diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp index 4bee808..499545e 100644 --- a/media/libstagefright/omx/tests/OMXHarness.cpp +++ b/media/libstagefright/omx/tests/OMXHarness.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -241,7 +242,8 @@ private: }; static sp CreateExtractorFromURI(const char *uri) { - sp source = DataSource::CreateFromURI(uri); + sp source = + DataSource::CreateFromURI(NULL /* httpService */, uri); if (source == NULL) { return NULL; diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp index 462c384..09f52bc 100644 --- a/media/libstagefright/rtsp/APacketSource.cpp +++ b/media/libstagefright/rtsp/APacketSource.cpp @@ -23,7 +23,7 @@ #include "ARawAudioAssembler.h" #include "ASessionDescription.h" -#include "avc_utils.h" +#include "include/avc_utils.h" #include diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp index efde7a9..4054da6 100644 --- a/media/libstagefright/rtsp/ARTSPConnection.cpp +++ b/media/libstagefright/rtsp/ARTSPConnection.cpp @@ -33,7 +33,7 @@ #include #include -#include "HTTPBase.h" +#include "include/HTTPBase.h" namespace android { diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk index e77c69c..02e44f4 100644 --- a/media/libstagefright/rtsp/Android.mk +++ b/media/libstagefright/rtsp/Android.mk @@ -20,7 +20,7 @@ LOCAL_SRC_FILES:= \ SDPLoader.cpp \ LOCAL_C_INCLUDES:= \ - $(TOP)/frameworks/av/media/libstagefright/include \ + $(TOP)/frameworks/av/media/libstagefright \ $(TOP)/frameworks/native/include/media/openmax \ $(TOP)/external/openssl/include diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp index ed3fa7e..6710923 100644 --- a/media/libstagefright/rtsp/SDPLoader.cpp +++ b/media/libstagefright/rtsp/SDPLoader.cpp @@ -18,11 +18,13 @@ #define LOG_TAG "SDPLoader" #include -#include "SDPLoader.h" +#include "include/SDPLoader.h" #include "ASessionDescription.h" -#include "HTTPBase.h" +#include +#include +#include #include #include @@ -30,18 +32,19 @@ namespace android { -SDPLoader::SDPLoader(const sp ¬ify, uint32_t flags, bool uidValid, uid_t uid) +SDPLoader::SDPLoader( + const sp ¬ify, + uint32_t flags, + const sp &httpService, + bool uidValid, + uid_t uid) : mNotify(notify), mFlags(flags), mUIDValid(uidValid), mUID(uid), mNetLooper(new ALooper), mCancelled(false), - mHTTPDataSource( - HTTPBase::Create( - (mFlags & kFlagIncognito) - ? HTTPBase::kFlagIncognito - : 0)) { + mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())) { if (mUIDValid) { mHTTPDataSource->setUID(mUID); } diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp index 12fd7f4..05d6d02 100644 --- a/media/libstagefright/timedtext/TimedTextDriver.cpp +++ b/media/libstagefright/timedtext/TimedTextDriver.cpp @@ -20,6 +20,7 @@ #include +#include #include #include #include @@ -40,7 +41,8 @@ namespace android { TimedTextDriver::TimedTextDriver( - const wp &listener) + const wp &listener, + const sp &httpService) : mLooper(new ALooper), mListener(listener), mState(UNINITIALIZED), @@ -207,7 +209,7 @@ status_t TimedTextDriver::addOutOfBandTextSource( } sp dataSource = - DataSource::CreateFromURI(uri); + DataSource::CreateFromURI(mHTTPService, uri); return createOutOfBandTextSource(trackIndex, mimeType, dataSource); } diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp index 286ea13..1a5acba 100644 --- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp +++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -749,7 +750,8 @@ status_t WifiDisplaySource::PlaybackSession::setupMediaPacketizer( mExtractor = new NuMediaExtractor; - status_t err = mExtractor->setDataSource(mMediaPath.c_str()); + status_t err = mExtractor->setDataSource( + NULL /* httpService */, mMediaPath.c_str()); if (err != OK) { return err; -- cgit v1.1 From b3b2e23fcf7e050710d23b82a6682c0f3d869b69 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 5 Feb 2014 11:10:26 -0800 Subject: Add AudioRecord::mReqFrameCount similar to AudioTrack Change-Id: I62d6534a9581e84ae20c2422f7ad9aeda9b7c4df --- media/libmedia/AudioRecord.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 286096e..a9ba154 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -228,7 +228,8 @@ status_t AudioRecord::set( ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount); return BAD_VALUE; } - mFrameCount = frameCount; + // mFrameCount is initialized in openRecord_l + mReqFrameCount = frameCount; mNotificationFramesReq = notificationFrames; mNotificationFramesAct = 0; @@ -449,11 +450,12 @@ status_t AudioRecord::openRecord_l(size_t epoch) } mNotificationFramesAct = mNotificationFramesReq; + size_t frameCount = mReqFrameCount; if (!(mFlags & AUDIO_INPUT_FLAG_FAST)) { // Make sure that application is notified with sufficient margin before overrun - if (mNotificationFramesAct == 0 || mNotificationFramesAct > mFrameCount/2) { - mNotificationFramesAct = mFrameCount/2; + if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/2) { + mNotificationFramesAct = frameCount/2; } } @@ -467,7 +469,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger, // we must release it ourselves if anything goes wrong. - size_t temp = mFrameCount; // temp may be replaced by a revised value of frameCount, + size_t temp = frameCount; // temp may be replaced by a revised value of frameCount, // but we will still need the original value also int originalSessionId = mSessionId; sp record = audioFlinger->openRecord(input, @@ -510,10 +512,15 @@ status_t AudioRecord::openRecord_l(size_t epoch) audio_track_cblk_t* cblk = static_cast(iMemPointer); mCblk = cblk; // note that temp is the (possibly revised) value of mFrameCount - if (temp < mFrameCount || (mFrameCount == 0 && temp == 0)) { - ALOGW("Requested frameCount %u but received frameCount %u", mFrameCount, temp); + if (temp < frameCount || (frameCount == 0 && temp == 0)) { + ALOGW("Requested frameCount %u but received frameCount %u", frameCount, temp); + } + frameCount = temp; + // If IAudioRecord is re-created, don't let the requested frameCount + // decrease. This can confuse clients that cache frameCount(). + if (frameCount > mReqFrameCount) { + mReqFrameCount = frameCount; } - mFrameCount = temp; // FIXME missing fast track frameCount logic mAwaitBoost = false; @@ -538,6 +545,8 @@ status_t AudioRecord::openRecord_l(size_t epoch) // starting address of buffers in shared memory void *buffers = (char*)cblk + sizeof(audio_track_cblk_t); + mFrameCount = frameCount; + // update proxy mProxy = new AudioRecordClientProxy(cblk, buffers, mFrameCount, mFrameSize); mProxy->setEpoch(epoch); -- cgit v1.1 From 81e68448f3361eaf8618930471fdc3c21bdf5cbc Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Wed, 5 Feb 2014 11:52:33 -0800 Subject: Remove no longer needed http proxy handling code, it's obsolete now since we started to use java's HTTPConnection instead of the native implementation. Also remove other remnants of the previous http implementation, such as accounting for the http user's uid. Change-Id: I60bfd31381ea40d2220db587ec5c433093b60034 --- media/libmedia/IMediaPlayerService.cpp | 38 -- media/libmedia/mediaplayer.cpp | 11 - media/libmediaplayerservice/MediaPlayerService.cpp | 5 - media/libmediaplayerservice/MediaPlayerService.h | 3 - .../nuplayer/GenericSource.cpp | 4 +- .../libmediaplayerservice/nuplayer/GenericSource.h | 4 +- .../nuplayer/HTTPLiveSource.cpp | 9 +- .../nuplayer/HTTPLiveSource.h | 6 +- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 6 +- .../libmediaplayerservice/nuplayer/RTSPSource.cpp | 3 +- media/libstagefright/Android.mk | 7 - media/libstagefright/DataSource.cpp | 9 - media/libstagefright/HTTPBase.cpp | 33 +- media/libstagefright/chromium_http/Android.mk | 37 -- .../chromium_http/ChromiumHTTPDataSource.cpp | 350 ------------- .../libstagefright/chromium_http/DataUriSource.cpp | 68 --- .../chromium_http/chromium_http_stub.cpp | 38 -- media/libstagefright/chromium_http/support.cpp | 558 --------------------- media/libstagefright/chromium_http/support.h | 178 ------- media/libstagefright/chromium_http_stub.cpp | 102 ---- media/libstagefright/httplive/LiveSession.cpp | 9 +- media/libstagefright/httplive/LiveSession.h | 6 +- .../include/ChromiumHTTPDataSource.h | 124 ----- media/libstagefright/include/HTTPBase.h | 9 - media/libstagefright/include/SDPLoader.h | 6 +- media/libstagefright/include/chromium_http_stub.h | 34 -- media/libstagefright/rtsp/SDPLoader.cpp | 12 +- 27 files changed, 14 insertions(+), 1655 deletions(-) delete mode 100644 media/libstagefright/chromium_http/Android.mk delete mode 100644 media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp delete mode 100644 media/libstagefright/chromium_http/DataUriSource.cpp delete mode 100644 media/libstagefright/chromium_http/chromium_http_stub.cpp delete mode 100644 media/libstagefright/chromium_http/support.cpp delete mode 100644 media/libstagefright/chromium_http/support.h delete mode 100644 media/libstagefright/chromium_http_stub.cpp delete mode 100644 media/libstagefright/include/ChromiumHTTPDataSource.h delete mode 100644 media/libstagefright/include/chromium_http_stub.h (limited to 'media') diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index 190adf2..d116b14 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -49,7 +49,6 @@ enum { ADD_BATTERY_DATA, PULL_BATTERY_DATA, LISTEN_FOR_REMOTE_DISPLAY, - UPDATE_PROXY_CONFIG, }; class BpMediaPlayerService: public BpInterface @@ -192,25 +191,6 @@ public: remote()->transact(LISTEN_FOR_REMOTE_DISPLAY, data, &reply); return interface_cast(reply.readStrongBinder()); } - - virtual status_t updateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - Parcel data, reply; - - data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); - if (host == NULL) { - data.writeInt32(0); - } else { - data.writeInt32(1); - data.writeCString(host); - data.writeInt32(port); - data.writeCString(exclusionList); - } - - remote()->transact(UPDATE_PROXY_CONFIG, data, &reply); - - return reply.readInt32(); - } }; IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService"); @@ -338,24 +318,6 @@ status_t BnMediaPlayerService::onTransact( reply->writeStrongBinder(display->asBinder()); return NO_ERROR; } break; - case UPDATE_PROXY_CONFIG: - { - CHECK_INTERFACE(IMediaPlayerService, data, reply); - - const char *host = NULL; - int32_t port = 0; - const char *exclusionList = NULL; - - if (data.readInt32()) { - host = data.readCString(); - port = data.readInt32(); - exclusionList = data.readCString(); - } - - reply->writeInt32(updateProxyConfig(host, port, exclusionList)); - - return OK; - } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index a4d4b1a..24663ad 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -838,15 +838,4 @@ status_t MediaPlayer::setNextMediaPlayer(const sp& next) { return mPlayer->setNextPlayer(next == NULL ? NULL : next->mPlayer); } -status_t MediaPlayer::updateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - const sp& service = getMediaPlayerService(); - - if (service != NULL) { - return service->updateProxyConfig(host, port, exclusionList); - } - - return INVALID_OPERATION; -} - }; // namespace android diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 1c6018c..f1bc79c 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -307,11 +307,6 @@ sp MediaPlayerService::listenForRemoteDisplay( return new RemoteDisplay(client, iface.string()); } -status_t MediaPlayerService::updateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - return HTTPBase::UpdateProxyConfig(host, port, exclusionList); -} - status_t MediaPlayerService::AudioCache::dump(int fd, const Vector& args) const { const size_t SIZE = 256; diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 6749f4a..65b28dc 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -278,9 +278,6 @@ public: const String8& iface); virtual status_t dump(int fd, const Vector& args); - virtual status_t updateProxyConfig( - const char *host, int32_t port, const char *exclusionList); - void removeClient(wp client); // For battery usage tracking purpose diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 837e5b6..06aac33 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -35,9 +35,7 @@ NuPlayer::GenericSource::GenericSource( const sp ¬ify, const sp &httpService, const char *url, - const KeyedVector *headers, - bool uidValid, - uid_t uid) + const KeyedVector *headers) : Source(notify), mDurationUs(0ll), mAudioIsVorbis(false) { diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 6d7e1d6..20d597e 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -35,9 +35,7 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { const sp ¬ify, const sp &httpService, const char *url, - const KeyedVector *headers, - bool uidValid = false, - uid_t uid = 0); + const KeyedVector *headers); GenericSource( const sp ¬ify, diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp index e4145e6..ac2aab8 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp @@ -37,13 +37,10 @@ NuPlayer::HTTPLiveSource::HTTPLiveSource( const sp ¬ify, const sp &httpService, const char *url, - const KeyedVector *headers, - bool uidValid, uid_t uid) + const KeyedVector *headers) : Source(notify), mHTTPService(httpService), mURL(url), - mUIDValid(uidValid), - mUID(uid), mFlags(0), mFinalResult(OK), mOffset(0), @@ -82,9 +79,7 @@ void NuPlayer::HTTPLiveSource::prepareAsync() { mLiveSession = new LiveSession( notify, (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0, - mHTTPService, - mUIDValid, - mUID); + mHTTPService); mLiveLooper->registerHandler(mLiveSession); diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h index a60d38e..4d7251f 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h @@ -30,9 +30,7 @@ struct NuPlayer::HTTPLiveSource : public NuPlayer::Source { const sp ¬ify, const sp &httpService, const char *url, - const KeyedVector *headers, - bool uidValid = false, - uid_t uid = 0); + const KeyedVector *headers); virtual void prepareAsync(); virtual void start(); @@ -65,8 +63,6 @@ private: sp mHTTPService; AString mURL; KeyedVector mExtraHeaders; - bool mUIDValid; - uid_t mUID; uint32_t mFlags; status_t mFinalResult; off64_t mOffset; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 93fe594..817395a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -222,8 +222,7 @@ void NuPlayer::setDataSourceAsync( sp source; if (IsHTTPLiveURL(url)) { - source = new HTTPLiveSource( - notify, httpService, url, headers, mUIDValid, mUID); + source = new HTTPLiveSource(notify, httpService, url, headers); } else if (!strncasecmp(url, "rtsp://", 7)) { source = new RTSPSource( notify, httpService, url, headers, mUIDValid, mUID); @@ -234,8 +233,7 @@ void NuPlayer::setDataSourceAsync( source = new RTSPSource( notify, httpService, url, headers, mUIDValid, mUID, true); } else { - source = new GenericSource( - notify, httpService, url, headers, mUIDValid, mUID); + source = new GenericSource(notify, httpService, url, headers); } msg->setObject("source", source); diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index 6cdf0c9..94800ba 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -95,8 +95,7 @@ void NuPlayer::RTSPSource::prepareAsync() { if (mIsSDP) { mSDPLoader = new SDPLoader(notify, (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0, - mHTTPService, - mUIDValid, mUID); + mHTTPService); mSDPLoader->load( mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index c6cee5d..4c4e4ce 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -104,13 +104,6 @@ LOCAL_STATIC_LIBRARIES := \ libFLAC \ libmedia_helper -LOCAL_SRC_FILES += \ - chromium_http_stub.cpp -LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1 - -LOCAL_SHARED_LIBRARIES += libstlport -include external/stlport/libstlport.mk - LOCAL_SHARED_LIBRARIES += \ libstagefright_enc_common \ libstagefright_avc_common \ diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 9ff9ca2..2704b74 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -16,10 +16,6 @@ #include "include/AMRExtractor.h" -#if CHROMIUM_AVAILABLE -#include "include/chromium_http_stub.h" -#endif - #include "include/AACExtractor.h" #include "include/DRMExtractor.h" #include "include/FLACExtractor.h" @@ -225,11 +221,6 @@ sp DataSource::CreateFromURI( // in the widevine:// case. source = httpSource; } - -# if CHROMIUM_AVAILABLE - } else if (!strncasecmp("data:", uri, 5)) { - source = createDataUriSource(uri); -#endif } else { // Assume it's a filename. source = new FileSource(uri); diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp index f3b1ef9..ca68c3d 100644 --- a/media/libstagefright/HTTPBase.cpp +++ b/media/libstagefright/HTTPBase.cpp @@ -20,10 +20,6 @@ #include "include/HTTPBase.h" -#if CHROMIUM_AVAILABLE -#include "include/chromium_http_stub.h" -#endif - #include #include @@ -40,19 +36,7 @@ HTTPBase::HTTPBase() mTotalTransferBytes(0), mPrevBandwidthMeasureTimeUs(0), mPrevEstimatedBandWidthKbps(0), - mBandWidthCollectFreqMs(5000), - mUIDValid(false), - mUID(0) { -} - -// static -status_t HTTPBase::UpdateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { -#if CHROMIUM_AVAILABLE - return UpdateChromiumHTTPDataSourceProxyConfig(host, port, exclusionList); -#else - return INVALID_OPERATION; -#endif + mBandWidthCollectFreqMs(5000) { } void HTTPBase::addBandwidthMeasurement( @@ -120,21 +104,6 @@ status_t HTTPBase::setBandwidthStatCollectFreq(int32_t freqMs) { return OK; } -void HTTPBase::setUID(uid_t uid) { - mUIDValid = true; - mUID = uid; -} - -bool HTTPBase::getUID(uid_t *uid) const { - if (!mUIDValid) { - return false; - } - - *uid = mUID; - - return true; -} - // static void HTTPBase::RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag) { int res = qtaguid_tagSocket(sockfd, kTag, uid); diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk deleted file mode 100644 index f26f386..0000000 --- a/media/libstagefright/chromium_http/Android.mk +++ /dev/null @@ -1,37 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -ifneq ($(TARGET_BUILD_PDK), true) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - DataUriSource.cpp \ - ChromiumHTTPDataSource.cpp \ - support.cpp \ - chromium_http_stub.cpp - -LOCAL_C_INCLUDES:= \ - $(TOP)/frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax \ - external/chromium \ - external/chromium/android - -LOCAL_CFLAGS += -Wno-multichar - -LOCAL_SHARED_LIBRARIES += \ - libstlport \ - libchromium_net \ - libutils \ - libcutils \ - liblog \ - libstagefright_foundation \ - libstagefright \ - libdrmframework - -include external/stlport/libstlport.mk - -LOCAL_MODULE:= libstagefright_chromium_http - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) -endif diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp deleted file mode 100644 index a862d8b..0000000 --- a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "ChromiumHTTPDataSource" -#include - -#include "include/ChromiumHTTPDataSource.h" - -#include -#include - -#include "support.h" - -#include // for property_get - -namespace android { - -ChromiumHTTPDataSource::ChromiumHTTPDataSource(uint32_t flags) - : mFlags(flags), - mState(DISCONNECTED), - mDelegate(new SfDelegate), - mCurrentOffset(0), - mIOResult(OK), - mContentSize(-1), - mDecryptHandle(NULL), - mDrmManagerClient(NULL) { - mDelegate->setOwner(this); -} - -ChromiumHTTPDataSource::~ChromiumHTTPDataSource() { - disconnect(); - - delete mDelegate; - mDelegate = NULL; - - clearDRMState_l(); - - if (mDrmManagerClient != NULL) { - delete mDrmManagerClient; - mDrmManagerClient = NULL; - } -} - -status_t ChromiumHTTPDataSource::connect( - const char *uri, - const KeyedVector *headers, - off64_t offset) { - Mutex::Autolock autoLock(mLock); - - uid_t uid; - if (getUID(&uid)) { - mDelegate->setUID(uid); - } - -#if defined(LOG_NDEBUG) && !LOG_NDEBUG - LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "connect on behalf of uid %d", uid); -#endif - - return connect_l(uri, headers, offset); -} - -status_t ChromiumHTTPDataSource::connect_l( - const char *uri, - const KeyedVector *headers, - off64_t offset) { - if (mState != DISCONNECTED) { - disconnect_l(); - } - -#if defined(LOG_NDEBUG) && !LOG_NDEBUG - LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, - "connect to @%lld", offset); -#endif - - mURI = uri; - mContentType = String8("application/octet-stream"); - - if (headers != NULL) { - mHeaders = *headers; - } else { - mHeaders.clear(); - } - - mState = CONNECTING; - mContentSize = -1; - mCurrentOffset = offset; - - mDelegate->initiateConnection(mURI.c_str(), &mHeaders, offset); - - while (mState == CONNECTING || mState == DISCONNECTING) { - mCondition.wait(mLock); - } - - return mState == CONNECTED ? OK : mIOResult; -} - -void ChromiumHTTPDataSource::onConnectionEstablished( - int64_t contentSize, const char *contentType) { - Mutex::Autolock autoLock(mLock); - - if (mState != CONNECTING) { - // We may have initiated disconnection. - CHECK_EQ(mState, DISCONNECTING); - return; - } - - mState = CONNECTED; - mContentSize = (contentSize < 0) ? -1 : contentSize + mCurrentOffset; - mContentType = String8(contentType); - mCondition.broadcast(); -} - -void ChromiumHTTPDataSource::onConnectionFailed(status_t err) { - Mutex::Autolock autoLock(mLock); - mState = DISCONNECTED; - mCondition.broadcast(); - - // mURI.clear(); - - mIOResult = err; -} - -void ChromiumHTTPDataSource::disconnect() { - Mutex::Autolock autoLock(mLock); - disconnect_l(); -} - -void ChromiumHTTPDataSource::disconnect_l() { - if (mState == DISCONNECTED) { - return; - } - - mState = DISCONNECTING; - mIOResult = -EINTR; - - mDelegate->initiateDisconnect(); - - while (mState == DISCONNECTING) { - mCondition.wait(mLock); - } - - CHECK_EQ((int)mState, (int)DISCONNECTED); -} - -status_t ChromiumHTTPDataSource::initCheck() const { - Mutex::Autolock autoLock(mLock); - - return mState == CONNECTED ? OK : NO_INIT; -} - -ssize_t ChromiumHTTPDataSource::readAt(off64_t offset, void *data, size_t size) { - Mutex::Autolock autoLock(mLock); - - if (mState != CONNECTED) { - return INVALID_OPERATION; - } - -#if 0 - char value[PROPERTY_VALUE_MAX]; - if (property_get("media.stagefright.disable-net", value, 0) - && (!strcasecmp(value, "true") || !strcmp(value, "1"))) { - LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Simulating that the network is down."); - disconnect_l(); - return ERROR_IO; - } -#endif - - if (offset != mCurrentOffset) { - AString tmp = mURI; - KeyedVector tmpHeaders = mHeaders; - - disconnect_l(); - - status_t err = connect_l(tmp.c_str(), &tmpHeaders, offset); - - if (err != OK) { - return err; - } - } - - mState = READING; - - int64_t startTimeUs = ALooper::GetNowUs(); - - mDelegate->initiateRead(data, size); - - while (mState == READING) { - mCondition.wait(mLock); - } - - if (mIOResult < OK) { - return mIOResult; - } - - if (mState == CONNECTED) { - int64_t delayUs = ALooper::GetNowUs() - startTimeUs; - - // The read operation was successful, mIOResult contains - // the number of bytes read. - addBandwidthMeasurement(mIOResult, delayUs); - - mCurrentOffset += mIOResult; - return mIOResult; - } - - return ERROR_IO; -} - -void ChromiumHTTPDataSource::onReadCompleted(ssize_t size) { - Mutex::Autolock autoLock(mLock); - - mIOResult = size; - - if (mState == READING) { - mState = CONNECTED; - mCondition.broadcast(); - } -} - -status_t ChromiumHTTPDataSource::getSize(off64_t *size) { - Mutex::Autolock autoLock(mLock); - - if (mContentSize < 0) { - return ERROR_UNSUPPORTED; - } - - *size = mContentSize; - - return OK; -} - -uint32_t ChromiumHTTPDataSource::flags() { - return kWantsPrefetching | kIsHTTPBasedSource; -} - -// static -void ChromiumHTTPDataSource::InitiateRead( - ChromiumHTTPDataSource *me, void *data, size_t size) { - me->initiateRead(data, size); -} - -void ChromiumHTTPDataSource::initiateRead(void *data, size_t size) { - mDelegate->initiateRead(data, size); -} - -void ChromiumHTTPDataSource::onDisconnectComplete() { - Mutex::Autolock autoLock(mLock); - CHECK_EQ((int)mState, (int)DISCONNECTING); - - mState = DISCONNECTED; - // mURI.clear(); - mIOResult = -ENOTCONN; - - mCondition.broadcast(); -} - -sp ChromiumHTTPDataSource::DrmInitialization(const char* mime) { - Mutex::Autolock autoLock(mLock); - - if (mDrmManagerClient == NULL) { - mDrmManagerClient = new DrmManagerClient(); - } - - if (mDrmManagerClient == NULL) { - return NULL; - } - - if (mDecryptHandle == NULL) { - /* Note if redirect occurs, mUri is the redirect uri instead of the - * original one - */ - mDecryptHandle = mDrmManagerClient->openDecryptSession( - String8(mURI.c_str()), mime); - } - - if (mDecryptHandle == NULL) { - delete mDrmManagerClient; - mDrmManagerClient = NULL; - } - - return mDecryptHandle; -} - -void ChromiumHTTPDataSource::getDrmInfo( - sp &handle, DrmManagerClient **client) { - Mutex::Autolock autoLock(mLock); - - handle = mDecryptHandle; - *client = mDrmManagerClient; -} - -String8 ChromiumHTTPDataSource::getUri() { - Mutex::Autolock autoLock(mLock); - - return String8(mURI.c_str()); -} - -String8 ChromiumHTTPDataSource::getMIMEType() const { - Mutex::Autolock autoLock(mLock); - - return mContentType; -} - -void ChromiumHTTPDataSource::clearDRMState_l() { - if (mDecryptHandle != NULL) { - // To release mDecryptHandle - CHECK(mDrmManagerClient); - mDrmManagerClient->closeDecryptSession(mDecryptHandle); - mDecryptHandle = NULL; - } -} - -status_t ChromiumHTTPDataSource::reconnectAtOffset(off64_t offset) { - Mutex::Autolock autoLock(mLock); - - if (mURI.empty()) { - return INVALID_OPERATION; - } - - LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnecting..."); - status_t err = connect_l(mURI.c_str(), &mHeaders, offset); - if (err != OK) { - LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnect failed w/ err 0x%08x", err); - } - - return err; -} - -// static -status_t ChromiumHTTPDataSource::UpdateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - return SfDelegate::UpdateProxyConfig(host, port, exclusionList); -} - -} // namespace android - diff --git a/media/libstagefright/chromium_http/DataUriSource.cpp b/media/libstagefright/chromium_http/DataUriSource.cpp deleted file mode 100644 index ecf3fa1..0000000 --- a/media/libstagefright/chromium_http/DataUriSource.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2011 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 - -#include -#include - - -namespace android { - -DataUriSource::DataUriSource(const char *uri) : - mDataUri(uri), - mInited(NO_INIT) { - - // Copy1: const char *uri -> String8 mDataUri. - std::string mimeTypeStr, unusedCharsetStr, dataStr; - // Copy2: String8 mDataUri -> std::string - const bool ret = net::DataURL::Parse( - GURL(std::string(mDataUri.string())), - &mimeTypeStr, &unusedCharsetStr, &dataStr); - // Copy3: std::string dataStr -> AString mData - mData.setTo(dataStr.data(), dataStr.length()); - mInited = ret ? OK : UNKNOWN_ERROR; - - // The chromium data url implementation defaults to using "text/plain" - // if no mime type is specified. We prefer to leave this unspecified - // instead, since the mime type is sniffed in most cases. - if (mimeTypeStr != "text/plain") { - mMimeType = mimeTypeStr.c_str(); - } -} - -ssize_t DataUriSource::readAt(off64_t offset, void *out, size_t size) { - if (mInited != OK) { - return mInited; - } - - const off64_t length = mData.size(); - if (offset >= length) { - return UNKNOWN_ERROR; - } - - const char *dataBuf = mData.c_str(); - const size_t bytesToCopy = - offset + size >= length ? (length - offset) : size; - - if (bytesToCopy > 0) { - memcpy(out, dataBuf + offset, bytesToCopy); - } - - return bytesToCopy; -} - -} // namespace android diff --git a/media/libstagefright/chromium_http/chromium_http_stub.cpp b/media/libstagefright/chromium_http/chromium_http_stub.cpp deleted file mode 100644 index 289f6de..0000000 --- a/media/libstagefright/chromium_http/chromium_http_stub.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2012 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 - -#include -#include -#include - -namespace android { - -HTTPBase *createChromiumHTTPDataSource(uint32_t flags) { - return new ChromiumHTTPDataSource(flags); -} - -status_t UpdateChromiumHTTPDataSourceProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - return ChromiumHTTPDataSource::UpdateProxyConfig(host, port, exclusionList); -} - -DataSource *createDataUriSource(const char *uri) { - return new DataUriSource(uri); -} - -} diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp deleted file mode 100644 index 0a8e3e3..0000000 --- a/media/libstagefright/chromium_http/support.cpp +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "ChromiumHTTPDataSourceSupport" -#include - -#include - -#include "support.h" - -#include "android/net/android_network_library_impl.h" -#include "base/logging.h" -#include "base/threading/thread.h" -#include "net/base/cert_verifier.h" -#include "net/base/cookie_monster.h" -#include "net/base/host_resolver.h" -#include "net/base/ssl_config_service.h" -#include "net/http/http_auth_handler_factory.h" -#include "net/http/http_cache.h" -#include "net/proxy/proxy_config_service_android.h" - -#include "include/ChromiumHTTPDataSource.h" - -#include -#include -#include -#include - -namespace android { - -static Mutex gNetworkThreadLock; -static base::Thread *gNetworkThread = NULL; -static scoped_refptr gReqContext; -static scoped_ptr gNetworkChangeNotifier; - -bool logMessageHandler( - int severity, - const char* file, - int line, - size_t message_start, - const std::string& str) { - int androidSeverity = ANDROID_LOG_VERBOSE; - switch(severity) { - case logging::LOG_FATAL: - androidSeverity = ANDROID_LOG_FATAL; - break; - case logging::LOG_ERROR_REPORT: - case logging::LOG_ERROR: - androidSeverity = ANDROID_LOG_ERROR; - break; - case logging::LOG_WARNING: - androidSeverity = ANDROID_LOG_WARN; - break; - default: - androidSeverity = ANDROID_LOG_VERBOSE; - break; - } - android_printLog(androidSeverity, "chromium-libstagefright", - "%s:%d: %s", file, line, str.c_str()); - return false; -} - -struct AutoPrioritySaver { - AutoPrioritySaver() - : mTID(androidGetTid()), - mPrevPriority(androidGetThreadPriority(mTID)) { - androidSetThreadPriority(mTID, ANDROID_PRIORITY_NORMAL); - } - - ~AutoPrioritySaver() { - androidSetThreadPriority(mTID, mPrevPriority); - } - -private: - pid_t mTID; - int mPrevPriority; - - DISALLOW_EVIL_CONSTRUCTORS(AutoPrioritySaver); -}; - -static void InitializeNetworkThreadIfNecessary() { - Mutex::Autolock autoLock(gNetworkThreadLock); - - if (gNetworkThread == NULL) { - // Make sure any threads spawned by the chromium framework are - // running at normal priority instead of inheriting this thread's. - AutoPrioritySaver saver; - - gNetworkThread = new base::Thread("network"); - base::Thread::Options options; - options.message_loop_type = MessageLoop::TYPE_IO; - CHECK(gNetworkThread->StartWithOptions(options)); - - gReqContext = new SfRequestContext; - - gNetworkChangeNotifier.reset(net::NetworkChangeNotifier::Create()); - - net::AndroidNetworkLibrary::RegisterSharedInstance( - new SfNetworkLibrary); - logging::SetLogMessageHandler(logMessageHandler); - } -} - -static void MY_LOGI(const char *s) { - LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "%s", s); -} - -static void MY_LOGV(const char *s) { -#if !defined(LOG_NDEBUG) || LOG_NDEBUG == 0 - LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "%s", s); -#endif -} - -SfNetLog::SfNetLog() - : mNextID(1) { -} - -void SfNetLog::AddEntry( - EventType type, - const base::TimeTicks &time, - const Source &source, - EventPhase phase, - EventParameters *params) { -#if 0 - MY_LOGI(StringPrintf( - "AddEntry time=%s type=%s source=%s phase=%s\n", - TickCountToString(time).c_str(), - EventTypeToString(type), - SourceTypeToString(source.type), - EventPhaseToString(phase)).c_str()); -#endif -} - -uint32 SfNetLog::NextID() { - return mNextID++; -} - -net::NetLog::LogLevel SfNetLog::GetLogLevel() const { - return LOG_BASIC; -} - -//////////////////////////////////////////////////////////////////////////////// - -SfRequestContext::SfRequestContext() { - mUserAgent = MakeUserAgent().c_str(); - - set_net_log(new SfNetLog()); - - set_host_resolver( - net::CreateSystemHostResolver( - net::HostResolver::kDefaultParallelism, - NULL /* resolver_proc */, - net_log())); - - set_ssl_config_service( - net::SSLConfigService::CreateSystemSSLConfigService()); - - mProxyConfigService = new net::ProxyConfigServiceAndroid; - - set_proxy_service(net::ProxyService::CreateWithoutProxyResolver( - mProxyConfigService, net_log())); - - set_http_transaction_factory(new net::HttpCache( - host_resolver(), - new net::CertVerifier(), - dnsrr_resolver(), - dns_cert_checker(), - proxy_service(), - ssl_config_service(), - net::HttpAuthHandlerFactory::CreateDefault(host_resolver()), - network_delegate(), - net_log(), - NULL)); // backend_factory - - set_cookie_store(new net::CookieMonster(NULL, NULL)); -} - -const std::string &SfRequestContext::GetUserAgent(const GURL &url) const { - return mUserAgent; -} - -status_t SfRequestContext::updateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - Mutex::Autolock autoLock(mProxyConfigLock); - - if (host == NULL || *host == '\0') { - MY_LOGV("updateProxyConfig NULL"); - - std::string proxy; - std::string exList; - mProxyConfigService->UpdateProxySettings(proxy, exList); - } else { -#if !defined(LOG_NDEBUG) || LOG_NDEBUG == 0 - LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, - "updateProxyConfig %s:%d, exclude '%s'", - host, port, exclusionList); -#endif - - std::string proxy = StringPrintf("%s:%d", host, port).c_str(); - std::string exList = exclusionList; - mProxyConfigService->UpdateProxySettings(proxy, exList); - } - - return OK; -} - -//////////////////////////////////////////////////////////////////////////////// - -SfNetworkLibrary::SfNetworkLibrary() {} - -SfNetworkLibrary::VerifyResult SfNetworkLibrary::VerifyX509CertChain( - const std::vector& cert_chain, - const std::string& hostname, - const std::string& auth_type) { - return VERIFY_OK; -} - -//////////////////////////////////////////////////////////////////////////////// - -SfDelegate::SfDelegate() - : mOwner(NULL), - mURLRequest(NULL), - mReadBuffer(new net::IOBufferWithSize(8192)), - mNumBytesRead(0), - mNumBytesTotal(0), - mDataDestination(NULL), - mAtEOS(false) { - InitializeNetworkThreadIfNecessary(); -} - -SfDelegate::~SfDelegate() { - CHECK(mURLRequest == NULL); -} - -// static -status_t SfDelegate::UpdateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - InitializeNetworkThreadIfNecessary(); - - return gReqContext->updateProxyConfig(host, port, exclusionList); -} - -void SfDelegate::setOwner(ChromiumHTTPDataSource *owner) { - mOwner = owner; -} - -void SfDelegate::setUID(uid_t uid) { - gReqContext->setUID(uid); -} - -bool SfDelegate::getUID(uid_t *uid) const { - return gReqContext->getUID(uid); -} - -void SfDelegate::OnReceivedRedirect( - net::URLRequest *request, const GURL &new_url, bool *defer_redirect) { - MY_LOGV("OnReceivedRedirect"); -} - -void SfDelegate::OnAuthRequired( - net::URLRequest *request, net::AuthChallengeInfo *auth_info) { - MY_LOGV("OnAuthRequired"); - - inherited::OnAuthRequired(request, auth_info); -} - -void SfDelegate::OnCertificateRequested( - net::URLRequest *request, net::SSLCertRequestInfo *cert_request_info) { - MY_LOGV("OnCertificateRequested"); - - inherited::OnCertificateRequested(request, cert_request_info); -} - -void SfDelegate::OnSSLCertificateError( - net::URLRequest *request, int cert_error, net::X509Certificate *cert) { - fprintf(stderr, "OnSSLCertificateError cert_error=%d\n", cert_error); - - inherited::OnSSLCertificateError(request, cert_error, cert); -} - -void SfDelegate::OnGetCookies(net::URLRequest *request, bool blocked_by_policy) { - MY_LOGV("OnGetCookies"); -} - -void SfDelegate::OnSetCookie( - net::URLRequest *request, - const std::string &cookie_line, - const net::CookieOptions &options, - bool blocked_by_policy) { - MY_LOGV("OnSetCookie"); -} - -void SfDelegate::OnResponseStarted(net::URLRequest *request) { - if (request->status().status() != net::URLRequestStatus::SUCCESS) { - MY_LOGI(StringPrintf( - "Request failed with status %d and os_error %d", - request->status().status(), - request->status().os_error()).c_str()); - - delete mURLRequest; - mURLRequest = NULL; - - mOwner->onConnectionFailed(ERROR_IO); - return; - } else if (mRangeRequested && request->GetResponseCode() != 206) { - MY_LOGI(StringPrintf( - "We requested a content range, but server didn't " - "support that. (responded with %d)", - request->GetResponseCode()).c_str()); - - delete mURLRequest; - mURLRequest = NULL; - - mOwner->onConnectionFailed(-EPIPE); - return; - } else if ((request->GetResponseCode() / 100) != 2) { - MY_LOGI(StringPrintf( - "Server responded with http status %d", - request->GetResponseCode()).c_str()); - - delete mURLRequest; - mURLRequest = NULL; - - mOwner->onConnectionFailed(ERROR_IO); - return; - } - - MY_LOGV("OnResponseStarted"); - - std::string headers; - request->GetAllResponseHeaders(&headers); - - MY_LOGV(StringPrintf("response headers: %s", headers.c_str()).c_str()); - - std::string contentType; - request->GetResponseHeaderByName("Content-Type", &contentType); - - mOwner->onConnectionEstablished( - request->GetExpectedContentSize(), contentType.c_str()); -} - -void SfDelegate::OnReadCompleted(net::URLRequest *request, int bytes_read) { - if (bytes_read == -1) { - MY_LOGI(StringPrintf( - "OnReadCompleted, read failed, status %d", - request->status().status()).c_str()); - - mOwner->onReadCompleted(ERROR_IO); - return; - } - - MY_LOGV(StringPrintf("OnReadCompleted, read %d bytes", bytes_read).c_str()); - - if (bytes_read < 0) { - MY_LOGI(StringPrintf( - "Read failed w/ status %d\n", - request->status().status()).c_str()); - - mOwner->onReadCompleted(ERROR_IO); - return; - } else if (bytes_read == 0) { - mAtEOS = true; - mOwner->onReadCompleted(mNumBytesRead); - return; - } - - CHECK_GT(bytes_read, 0); - CHECK_LE(mNumBytesRead + bytes_read, mNumBytesTotal); - - memcpy((uint8_t *)mDataDestination + mNumBytesRead, - mReadBuffer->data(), - bytes_read); - - mNumBytesRead += bytes_read; - - readMore(request); -} - -void SfDelegate::readMore(net::URLRequest *request) { - while (mNumBytesRead < mNumBytesTotal) { - size_t copy = mNumBytesTotal - mNumBytesRead; - if (copy > mReadBuffer->size()) { - copy = mReadBuffer->size(); - } - - int n; - if (request->Read(mReadBuffer, copy, &n)) { - MY_LOGV(StringPrintf("Read %d bytes directly.", n).c_str()); - - CHECK_LE((size_t)n, copy); - - memcpy((uint8_t *)mDataDestination + mNumBytesRead, - mReadBuffer->data(), - n); - - mNumBytesRead += n; - - if (n == 0) { - mAtEOS = true; - break; - } - } else { - MY_LOGV("readMore pending read"); - - if (request->status().status() != net::URLRequestStatus::IO_PENDING) { - MY_LOGI(StringPrintf( - "Direct read failed w/ status %d\n", - request->status().status()).c_str()); - - mOwner->onReadCompleted(ERROR_IO); - return; - } - - return; - } - } - - mOwner->onReadCompleted(mNumBytesRead); -} - -void SfDelegate::initiateConnection( - const char *uri, - const KeyedVector *headers, - off64_t offset) { - GURL url(uri); - - MessageLoop *loop = gNetworkThread->message_loop(); - loop->PostTask( - FROM_HERE, - NewRunnableFunction( - &SfDelegate::OnInitiateConnectionWrapper, - this, - url, - headers, - offset)); - -} - -// static -void SfDelegate::OnInitiateConnectionWrapper( - SfDelegate *me, GURL url, - const KeyedVector *headers, - off64_t offset) { - me->onInitiateConnection(url, headers, offset); -} - -void SfDelegate::onInitiateConnection( - const GURL &url, - const KeyedVector *extra, - off64_t offset) { - CHECK(mURLRequest == NULL); - - mURLRequest = new net::URLRequest(url, this); - mAtEOS = false; - - mRangeRequested = false; - - if (offset != 0 || extra != NULL) { - net::HttpRequestHeaders headers = - mURLRequest->extra_request_headers(); - - if (offset != 0) { - headers.AddHeaderFromString( - StringPrintf("Range: bytes=%lld-", offset).c_str()); - - mRangeRequested = true; - } - - if (extra != NULL) { - for (size_t i = 0; i < extra->size(); ++i) { - AString s; - s.append(extra->keyAt(i).string()); - s.append(": "); - s.append(extra->valueAt(i).string()); - - headers.AddHeaderFromString(s.c_str()); - } - } - - mURLRequest->SetExtraRequestHeaders(headers); - } - - mURLRequest->set_context(gReqContext); - - mURLRequest->Start(); -} - -void SfDelegate::initiateDisconnect() { - MessageLoop *loop = gNetworkThread->message_loop(); - loop->PostTask( - FROM_HERE, - NewRunnableFunction( - &SfDelegate::OnInitiateDisconnectWrapper, this)); -} - -// static -void SfDelegate::OnInitiateDisconnectWrapper(SfDelegate *me) { - me->onInitiateDisconnect(); -} - -void SfDelegate::onInitiateDisconnect() { - if (mURLRequest == NULL) { - return; - } - - mURLRequest->Cancel(); - - delete mURLRequest; - mURLRequest = NULL; - - mOwner->onDisconnectComplete(); -} - -void SfDelegate::initiateRead(void *data, size_t size) { - MessageLoop *loop = gNetworkThread->message_loop(); - loop->PostTask( - FROM_HERE, - NewRunnableFunction( - &SfDelegate::OnInitiateReadWrapper, this, data, size)); -} - -// static -void SfDelegate::OnInitiateReadWrapper( - SfDelegate *me, void *data, size_t size) { - me->onInitiateRead(data, size); -} - -void SfDelegate::onInitiateRead(void *data, size_t size) { - CHECK(mURLRequest != NULL); - - mNumBytesRead = 0; - mNumBytesTotal = size; - mDataDestination = data; - - if (mAtEOS) { - mOwner->onReadCompleted(0); - return; - } - - readMore(mURLRequest); -} - -} // namespace android - diff --git a/media/libstagefright/chromium_http/support.h b/media/libstagefright/chromium_http/support.h deleted file mode 100644 index 975a1d3..0000000 --- a/media/libstagefright/chromium_http/support.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2011 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 SUPPORT_H_ - -#define SUPPORT_H_ - -#include - -#include "net/base/net_log.h" -#include "net/url_request/url_request.h" -#include "net/url_request/url_request_context.h" -#include "net/base/android_network_library.h" -#include "net/base/io_buffer.h" - -#include -#include -#include - -namespace net { - struct ProxyConfigServiceAndroid; -}; - -namespace android { - -struct SfNetLog : public net::NetLog { - SfNetLog(); - - virtual void AddEntry( - EventType type, - const base::TimeTicks &time, - const Source &source, - EventPhase phase, - EventParameters *params); - - virtual uint32 NextID(); - virtual LogLevel GetLogLevel() const; - -private: - uint32 mNextID; - - DISALLOW_EVIL_CONSTRUCTORS(SfNetLog); -}; - -struct SfRequestContext : public net::URLRequestContext { - SfRequestContext(); - - virtual const std::string &GetUserAgent(const GURL &url) const; - - status_t updateProxyConfig( - const char *host, int32_t port, const char *exclusionList); - -private: - Mutex mProxyConfigLock; - - std::string mUserAgent; - net::ProxyConfigServiceAndroid *mProxyConfigService; - - DISALLOW_EVIL_CONSTRUCTORS(SfRequestContext); -}; - -// This is required for https support, we don't really verify certificates, -// we accept anything... -struct SfNetworkLibrary : public net::AndroidNetworkLibrary { - SfNetworkLibrary(); - - virtual VerifyResult VerifyX509CertChain( - const std::vector& cert_chain, - const std::string& hostname, - const std::string& auth_type); - -private: - DISALLOW_EVIL_CONSTRUCTORS(SfNetworkLibrary); -}; - -struct ChromiumHTTPDataSource; - -struct SfDelegate : public net::URLRequest::Delegate { - SfDelegate(); - virtual ~SfDelegate(); - - void initiateConnection( - const char *uri, - const KeyedVector *headers, - off64_t offset); - - void initiateDisconnect(); - void initiateRead(void *data, size_t size); - - void setOwner(ChromiumHTTPDataSource *mOwner); - - // Gets the UID of the calling process - bool getUID(uid_t *uid) const; - - void setUID(uid_t uid); - - virtual void OnReceivedRedirect( - net::URLRequest *request, const GURL &new_url, bool *defer_redirect); - - virtual void OnAuthRequired( - net::URLRequest *request, net::AuthChallengeInfo *auth_info); - - virtual void OnCertificateRequested( - net::URLRequest *request, net::SSLCertRequestInfo *cert_request_info); - - virtual void OnSSLCertificateError( - net::URLRequest *request, int cert_error, net::X509Certificate *cert); - - virtual void OnGetCookies(net::URLRequest *request, bool blocked_by_policy); - - virtual void OnSetCookie( - net::URLRequest *request, - const std::string &cookie_line, - const net::CookieOptions &options, - bool blocked_by_policy); - - virtual void OnResponseStarted(net::URLRequest *request); - - virtual void OnReadCompleted(net::URLRequest *request, int bytes_read); - - static status_t UpdateProxyConfig( - const char *host, int32_t port, const char *exclusionList); - -private: - typedef Delegate inherited; - - ChromiumHTTPDataSource *mOwner; - - net::URLRequest *mURLRequest; - scoped_refptr mReadBuffer; - - size_t mNumBytesRead; - size_t mNumBytesTotal; - void *mDataDestination; - - bool mRangeRequested; - bool mAtEOS; - - void readMore(net::URLRequest *request); - - static void OnInitiateConnectionWrapper( - SfDelegate *me, - GURL url, - const KeyedVector *headers, - off64_t offset); - - static void OnInitiateDisconnectWrapper(SfDelegate *me); - - static void OnInitiateReadWrapper( - SfDelegate *me, void *data, size_t size); - - void onInitiateConnection( - const GURL &url, - const KeyedVector *headers, - off64_t offset); - - void onInitiateDisconnect(); - void onInitiateRead(void *data, size_t size); - - DISALLOW_EVIL_CONSTRUCTORS(SfDelegate); -}; - -} // namespace android - -#endif // SUPPORT_H_ diff --git a/media/libstagefright/chromium_http_stub.cpp b/media/libstagefright/chromium_http_stub.cpp deleted file mode 100644 index ed8a878..0000000 --- a/media/libstagefright/chromium_http_stub.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2012 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 - -#include - -#include "include/chromium_http_stub.h" -#include "include/HTTPBase.h" - -namespace android { - -static bool gFirst = true; -static void *gHandle; -static Mutex gLibMutex; - -HTTPBase *(*gLib_createChromiumHTTPDataSource)(uint32_t flags); -DataSource *(*gLib_createDataUriSource)(const char *uri); - -status_t (*gLib_UpdateChromiumHTTPDataSourceProxyConfig)( - const char *host, int32_t port, const char *exclusionList); - -static bool load_libstagefright_chromium_http() { - Mutex::Autolock autoLock(gLibMutex); - void *sym; - - if (!gFirst) { - return (gHandle != NULL); - } - - gFirst = false; - - gHandle = dlopen("libstagefright_chromium_http.so", RTLD_NOW); - if (gHandle == NULL) { - return false; - } - - sym = dlsym(gHandle, "createChromiumHTTPDataSource"); - if (sym == NULL) { - gHandle = NULL; - return false; - } - gLib_createChromiumHTTPDataSource = (HTTPBase *(*)(uint32_t))sym; - - sym = dlsym(gHandle, "createDataUriSource"); - if (sym == NULL) { - gHandle = NULL; - return false; - } - gLib_createDataUriSource = (DataSource *(*)(const char *))sym; - - sym = dlsym(gHandle, "UpdateChromiumHTTPDataSourceProxyConfig"); - if (sym == NULL) { - gHandle = NULL; - return false; - } - gLib_UpdateChromiumHTTPDataSourceProxyConfig = - (status_t (*)(const char *, int32_t, const char *))sym; - - return true; -} - -HTTPBase *createChromiumHTTPDataSource(uint32_t flags) { - if (!load_libstagefright_chromium_http()) { - return NULL; - } - - return gLib_createChromiumHTTPDataSource(flags); -} - -status_t UpdateChromiumHTTPDataSourceProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - if (!load_libstagefright_chromium_http()) { - return INVALID_OPERATION; - } - - return gLib_UpdateChromiumHTTPDataSourceProxyConfig( - host, port, exclusionList); -} - -DataSource *createDataUriSource(const char *uri) { - if (!load_libstagefright_chromium_http()) { - return NULL; - } - - return gLib_createDataUriSource(uri); -} - -} diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index dbdca5c..149a817 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -48,13 +48,10 @@ namespace android { LiveSession::LiveSession( const sp ¬ify, uint32_t flags, - const sp &httpService, - bool uidValid, uid_t uid) + const sp &httpService) : mNotify(notify), mFlags(flags), mHTTPService(httpService), - mUIDValid(uidValid), - mUID(uid), mInPreparationPhase(true), mHTTPDataSource(new MediaHTTP(mHTTPService->makeHTTPConnection())), mPrevBandwidthIndex(-1), @@ -64,10 +61,6 @@ LiveSession::LiveSession( mRealTimeBaseUs(0ll), mReconfigurationInProgress(false), mDisconnectReplyID(0) { - if (mUIDValid) { - mHTTPDataSource->setUID(mUID); - } - mPacketSources.add( STREAMTYPE_AUDIO, new AnotherPacketSource(NULL /* meta */)); diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 16fc65a..ee10e70 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -42,9 +42,7 @@ struct LiveSession : public AHandler { LiveSession( const sp ¬ify, uint32_t flags, - const sp &httpService, - bool uidValid = false, - uid_t uid = 0); + const sp &httpService); enum StreamType { STREAMTYPE_AUDIO = 1, @@ -112,8 +110,6 @@ private: sp mNotify; uint32_t mFlags; sp mHTTPService; - bool mUIDValid; - uid_t mUID; bool mInPreparationPhase; diff --git a/media/libstagefright/include/ChromiumHTTPDataSource.h b/media/libstagefright/include/ChromiumHTTPDataSource.h deleted file mode 100644 index 785f939..0000000 --- a/media/libstagefright/include/ChromiumHTTPDataSource.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2011 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 CHROME_HTTP_DATA_SOURCE_H_ - -#define CHROME_HTTP_DATA_SOURCE_H_ - -#include -#include - -#include "HTTPBase.h" - -namespace android { - -struct SfDelegate; - -struct ChromiumHTTPDataSource : public HTTPBase { - ChromiumHTTPDataSource(uint32_t flags = 0); - - virtual status_t connect( - const char *uri, - const KeyedVector *headers = NULL, - off64_t offset = 0); - - virtual void disconnect(); - - virtual status_t initCheck() const; - - virtual ssize_t readAt(off64_t offset, void *data, size_t size); - virtual status_t getSize(off64_t *size); - virtual uint32_t flags(); - - virtual sp DrmInitialization(const char *mime); - - virtual void getDrmInfo(sp &handle, DrmManagerClient **client); - - virtual String8 getUri(); - - virtual String8 getMIMEType() const; - - virtual status_t reconnectAtOffset(off64_t offset); - - static status_t UpdateProxyConfig( - const char *host, int32_t port, const char *exclusionList); - -protected: - virtual ~ChromiumHTTPDataSource(); - -private: - friend struct SfDelegate; - - enum State { - DISCONNECTED, - CONNECTING, - CONNECTED, - READING, - DISCONNECTING - }; - - const uint32_t mFlags; - - mutable Mutex mLock; - Condition mCondition; - - State mState; - - SfDelegate *mDelegate; - - AString mURI; - KeyedVector mHeaders; - - off64_t mCurrentOffset; - - // Any connection error or the result of a read operation - // (for the lattter this is the number of bytes read, if successful). - ssize_t mIOResult; - - int64_t mContentSize; - - String8 mContentType; - - sp mDecryptHandle; - DrmManagerClient *mDrmManagerClient; - - void disconnect_l(); - - status_t connect_l( - const char *uri, - const KeyedVector *headers, - off64_t offset); - - static void InitiateRead( - ChromiumHTTPDataSource *me, void *data, size_t size); - - void initiateRead(void *data, size_t size); - - void onConnectionEstablished( - int64_t contentSize, const char *contentType); - - void onConnectionFailed(status_t err); - void onReadCompleted(ssize_t size); - void onDisconnectComplete(); - - void clearDRMState_l(); - - DISALLOW_EVIL_CONSTRUCTORS(ChromiumHTTPDataSource); -}; - -} // namespace android - -#endif // CHROME_HTTP_DATA_SOURCE_H_ diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h index f891b56..1c3cd5e 100644 --- a/media/libstagefright/include/HTTPBase.h +++ b/media/libstagefright/include/HTTPBase.h @@ -48,12 +48,6 @@ struct HTTPBase : public DataSource { virtual status_t setBandwidthStatCollectFreq(int32_t freqMs); - static status_t UpdateProxyConfig( - const char *host, int32_t port, const char *exclusionList); - - void setUID(uid_t uid); - bool getUID(uid_t *uid) const; - static void RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag); static void UnRegisterSocketUserTag(int sockfd); @@ -85,9 +79,6 @@ private: int32_t mPrevEstimatedBandWidthKbps; int32_t mBandWidthCollectFreqMs; - bool mUIDValid; - uid_t mUID; - DISALLOW_EVIL_CONSTRUCTORS(HTTPBase); }; diff --git a/media/libstagefright/include/SDPLoader.h b/media/libstagefright/include/SDPLoader.h index 223bd92..2c4f543 100644 --- a/media/libstagefright/include/SDPLoader.h +++ b/media/libstagefright/include/SDPLoader.h @@ -38,9 +38,7 @@ struct SDPLoader : public AHandler { SDPLoader( const sp ¬ify, uint32_t flags, - const sp &httpService, - bool uidValid = false, - uid_t uid = 0); + const sp &httpService); void load(const char* url, const KeyedVector *headers); @@ -61,8 +59,6 @@ private: sp mNotify; const char* mUrl; uint32_t mFlags; - bool mUIDValid; - uid_t mUID; sp mNetLooper; bool mCancelled; diff --git a/media/libstagefright/include/chromium_http_stub.h b/media/libstagefright/include/chromium_http_stub.h deleted file mode 100644 index e0651a4..0000000 --- a/media/libstagefright/include/chromium_http_stub.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2012 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 CHROMIUM_HTTP_STUB_H_ -#define CHROMIUM_HTTP_STUB_H_ - -#include -#include - -namespace android { -extern "C" { -HTTPBase *createChromiumHTTPDataSource(uint32_t flags); - -status_t UpdateChromiumHTTPDataSourceProxyConfig( - const char *host, int32_t port, const char *exclusionList); - -DataSource *createDataUriSource(const char *uri); -} -} - -#endif diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp index 6710923..ce1e89d 100644 --- a/media/libstagefright/rtsp/SDPLoader.cpp +++ b/media/libstagefright/rtsp/SDPLoader.cpp @@ -35,20 +35,12 @@ namespace android { SDPLoader::SDPLoader( const sp ¬ify, uint32_t flags, - const sp &httpService, - bool uidValid, - uid_t uid) + const sp &httpService) : mNotify(notify), mFlags(flags), - mUIDValid(uidValid), - mUID(uid), mNetLooper(new ALooper), mCancelled(false), mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())) { - if (mUIDValid) { - mHTTPDataSource->setUID(mUID); - } - mNetLooper->setName("sdp net"); mNetLooper->start(false /* runOnCallingThread */, false /* canCallJava */, @@ -133,7 +125,7 @@ void SDPLoader::onLoad(const sp &msg) { ssize_t readSize = mHTTPDataSource->readAt(0, buffer->data(), sdpSize); if (readSize < 0) { - ALOGE("Failed to read SDP, error code = %ld", readSize); + ALOGE("Failed to read SDP, error code = %d", readSize); err = UNKNOWN_ERROR; } else { desc = new ASessionDescription; -- cgit v1.1 From 6e56e8024c98c3e6e62772e1dd345dd2c1c36717 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 5 Feb 2014 13:56:33 -0800 Subject: Fix restart after EOS for mp3 b/12890850 Change-Id: I985a1ae94d7d62701296d95da34974eb29fcc535 --- media/libstagefright/codecs/mp3dec/SoftMP3.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'media') diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp index 877e3cb..61df65e 100644 --- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp +++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp @@ -335,6 +335,9 @@ void SoftMP3::onPortFlushCompleted(OMX_U32 portIndex) { // depend on fragments from the last one decoded. pvmp3_InitDecoder(mConfig, mDecoderBuf); mIsFirst = true; + mSignalledError = false; + mSawInputEos = false; + mSignalledOutputEos = false; } } -- cgit v1.1 From 72cecca17d735db6532c45f0a7e10c47ee6f065a Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 26 Dec 2013 01:38:35 -0800 Subject: Change StagefrightRecorder to use MediaCodec Bug: 12305192 Change-Id: I72d7cb571be5bd348b58ad650f3269d24c15d350 --- .../libmediaplayerservice/StagefrightRecorder.cpp | 330 ++++---- media/libmediaplayerservice/StagefrightRecorder.h | 26 +- media/libstagefright/ACodec.cpp | 43 +- media/libstagefright/Android.mk | 1 + media/libstagefright/MPEG4Writer.cpp | 15 +- media/libstagefright/MediaCodecSource.cpp | 881 +++++++++++++++++++++ media/libstagefright/omx/GraphicBufferSource.cpp | 22 +- media/libstagefright/omx/GraphicBufferSource.h | 9 +- media/libstagefright/omx/OMXNodeInstance.cpp | 12 +- .../tests/SurfaceMediaSource_test.cpp | 9 +- 10 files changed, 1152 insertions(+), 196 deletions(-) create mode 100644 media/libstagefright/MediaCodecSource.cpp (limited to 'media') diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 78dad19..1ee0ee4 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -24,8 +24,10 @@ #include #include -#include +#include #include +#include +#include #include #include #include @@ -35,13 +37,12 @@ #include #include #include +#include #include #include -#include #include #include #include -#include #include #include @@ -71,8 +72,7 @@ StagefrightRecorder::StagefrightRecorder() mAudioSource(AUDIO_SOURCE_CNT), mVideoSource(VIDEO_SOURCE_LIST_END), mCaptureTimeLapse(false), - mStarted(false), - mSurfaceMediaSource(NULL) { + mStarted(false) { ALOGV("Constructor"); reset(); @@ -81,10 +81,19 @@ StagefrightRecorder::StagefrightRecorder() StagefrightRecorder::~StagefrightRecorder() { ALOGV("Destructor"); stop(); + + if (mLooper != NULL) { + mLooper->stop(); + } } status_t StagefrightRecorder::init() { ALOGV("init"); + + mLooper = new ALooper; + mLooper->setName("recorder_looper"); + mLooper->start(); + return OK; } @@ -93,7 +102,7 @@ status_t StagefrightRecorder::init() { // while encoding GL Frames sp StagefrightRecorder::querySurfaceMediaSource() const { ALOGV("Get SurfaceMediaSource"); - return mSurfaceMediaSource->getBufferQueue(); + return mGraphicBufferProducer; } status_t StagefrightRecorder::setAudioSource(audio_source_t as) { @@ -739,18 +748,14 @@ status_t StagefrightRecorder::setClientName(const String16& clientName) { } status_t StagefrightRecorder::prepare() { - return OK; -} - -status_t StagefrightRecorder::start() { - CHECK_GE(mOutputFd, 0); + ALOGV("prepare"); + if (mOutputFd < 0) { + ALOGE("Output file descriptor is invalid"); + return INVALID_OPERATION; + } // Get UID here for permission checking mClientUid = IPCThreadState::self()->getCallingUid(); - if (mWriter != NULL) { - ALOGE("File writer is not avaialble"); - return UNKNOWN_ERROR; - } status_t status = OK; @@ -758,25 +763,25 @@ status_t StagefrightRecorder::start() { case OUTPUT_FORMAT_DEFAULT: case OUTPUT_FORMAT_THREE_GPP: case OUTPUT_FORMAT_MPEG_4: - status = startMPEG4Recording(); + status = setupMPEG4Recording(); break; case OUTPUT_FORMAT_AMR_NB: case OUTPUT_FORMAT_AMR_WB: - status = startAMRRecording(); + status = setupAMRRecording(); break; case OUTPUT_FORMAT_AAC_ADIF: case OUTPUT_FORMAT_AAC_ADTS: - status = startAACRecording(); + status = setupAACRecording(); break; case OUTPUT_FORMAT_RTP_AVP: - status = startRTPRecording(); + status = setupRTPRecording(); break; case OUTPUT_FORMAT_MPEG2TS: - status = startMPEG2TSRecording(); + status = setupMPEG2TSRecording(); break; default: @@ -785,6 +790,60 @@ status_t StagefrightRecorder::start() { break; } + return status; +} + +status_t StagefrightRecorder::start() { + ALOGV("start"); + if (mOutputFd < 0) { + ALOGE("Output file descriptor is invalid"); + return INVALID_OPERATION; + } + + // Get UID here for permission checking + mClientUid = IPCThreadState::self()->getCallingUid(); + if (mWriter == NULL) { + ALOGE("File writer is not avaialble"); + return UNKNOWN_ERROR; + } + + status_t status = OK; + + switch (mOutputFormat) { + case OUTPUT_FORMAT_DEFAULT: + case OUTPUT_FORMAT_THREE_GPP: + case OUTPUT_FORMAT_MPEG_4: + { + sp meta = new MetaData; + setupMPEG4MetaData(&meta); + status = mWriter->start(meta.get()); + break; + } + + case OUTPUT_FORMAT_AMR_NB: + case OUTPUT_FORMAT_AMR_WB: + case OUTPUT_FORMAT_AAC_ADIF: + case OUTPUT_FORMAT_AAC_ADTS: + case OUTPUT_FORMAT_RTP_AVP: + case OUTPUT_FORMAT_MPEG2TS: + { + status = mWriter->start(); + break; + } + + default: + { + ALOGE("Unsupported output file format: %d", mOutputFormat); + status = UNKNOWN_ERROR; + break; + } + } + + if (status != OK) { + mWriter.clear(); + mWriter = NULL; + } + if ((status == OK) && (!mStarted)) { mStarted = true; @@ -816,58 +875,54 @@ sp StagefrightRecorder::createAudioSource() { return NULL; } - sp encMeta = new MetaData; + sp format = new AMessage; const char *mime; switch (mAudioEncoder) { case AUDIO_ENCODER_AMR_NB: case AUDIO_ENCODER_DEFAULT: - mime = MEDIA_MIMETYPE_AUDIO_AMR_NB; + format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB); break; case AUDIO_ENCODER_AMR_WB: - mime = MEDIA_MIMETYPE_AUDIO_AMR_WB; + format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_WB); break; case AUDIO_ENCODER_AAC: - mime = MEDIA_MIMETYPE_AUDIO_AAC; - encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectLC); + format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC); + format->setInt32("aac-profile", OMX_AUDIO_AACObjectLC); break; case AUDIO_ENCODER_HE_AAC: - mime = MEDIA_MIMETYPE_AUDIO_AAC; - encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectHE); + format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC); + format->setInt32("aac-profile", OMX_AUDIO_AACObjectHE); break; case AUDIO_ENCODER_AAC_ELD: - mime = MEDIA_MIMETYPE_AUDIO_AAC; - encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectELD); + format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC); + format->setInt32("aac-profile", OMX_AUDIO_AACObjectELD); break; default: ALOGE("Unknown audio encoder: %d", mAudioEncoder); return NULL; } - encMeta->setCString(kKeyMIMEType, mime); int32_t maxInputSize; CHECK(audioSource->getFormat()->findInt32( kKeyMaxInputSize, &maxInputSize)); - encMeta->setInt32(kKeyMaxInputSize, maxInputSize); - encMeta->setInt32(kKeyChannelCount, mAudioChannels); - encMeta->setInt32(kKeySampleRate, mSampleRate); - encMeta->setInt32(kKeyBitRate, mAudioBitRate); + format->setInt32("max-input-size", maxInputSize); + format->setInt32("channel-count", mAudioChannels); + format->setInt32("sample-rate", mSampleRate); + format->setInt32("bitrate", mAudioBitRate); if (mAudioTimeScale > 0) { - encMeta->setInt32(kKeyTimeScale, mAudioTimeScale); + format->setInt32("time-scale", mAudioTimeScale); } - OMXClient client; - CHECK_EQ(client.connect(), (status_t)OK); sp audioEncoder = - OMXCodec::Create(client.interface(), encMeta, - true /* createEncoder */, audioSource); + MediaCodecSource::Create(mLooper, format, audioSource); mAudioSourceNode = audioSource; return audioEncoder; } -status_t StagefrightRecorder::startAACRecording() { +status_t StagefrightRecorder::setupAACRecording() { // FIXME: // Add support for OUTPUT_FORMAT_AAC_ADIF CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_AAC_ADTS); @@ -878,16 +933,10 @@ status_t StagefrightRecorder::startAACRecording() { CHECK(mAudioSource != AUDIO_SOURCE_CNT); mWriter = new AACWriter(mOutputFd); - status_t status = startRawAudioRecording(); - if (status != OK) { - mWriter.clear(); - mWriter = NULL; - } - - return status; + return setupRawAudioRecording(); } -status_t StagefrightRecorder::startAMRRecording() { +status_t StagefrightRecorder::setupAMRRecording() { CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB || mOutputFormat == OUTPUT_FORMAT_AMR_WB); @@ -907,15 +956,10 @@ status_t StagefrightRecorder::startAMRRecording() { } mWriter = new AMRWriter(mOutputFd); - status_t status = startRawAudioRecording(); - if (status != OK) { - mWriter.clear(); - mWriter = NULL; - } - return status; + return setupRawAudioRecording(); } -status_t StagefrightRecorder::startRawAudioRecording() { +status_t StagefrightRecorder::setupRawAudioRecording() { if (mAudioSource >= AUDIO_SOURCE_CNT) { ALOGE("Invalid audio source: %d", mAudioSource); return BAD_VALUE; @@ -941,12 +985,11 @@ status_t StagefrightRecorder::startRawAudioRecording() { mWriter->setMaxFileSize(mMaxFileSizeBytes); } mWriter->setListener(mListener); - mWriter->start(); return OK; } -status_t StagefrightRecorder::startRTPRecording() { +status_t StagefrightRecorder::setupRTPRecording() { CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_RTP_AVP); if ((mAudioSource != AUDIO_SOURCE_CNT @@ -983,10 +1026,10 @@ status_t StagefrightRecorder::startRTPRecording() { mWriter->addSource(source); mWriter->setListener(mListener); - return mWriter->start(); + return OK; } -status_t StagefrightRecorder::startMPEG2TSRecording() { +status_t StagefrightRecorder::setupMPEG2TSRecording() { CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS); sp writer = new MPEG2TSWriter(mOutputFd); @@ -1036,7 +1079,7 @@ status_t StagefrightRecorder::startMPEG2TSRecording() { mWriter = writer; - return mWriter->start(); + return OK; } void StagefrightRecorder::clipVideoFrameRate() { @@ -1277,49 +1320,14 @@ status_t StagefrightRecorder::setupMediaSource( return err; } *mediaSource = cameraSource; - } else if (mVideoSource == VIDEO_SOURCE_GRALLOC_BUFFER) { - // If using GRAlloc buffers, setup surfacemediasource. - // Later a handle to that will be passed - // to the client side when queried - status_t err = setupSurfaceMediaSource(); - if (err != OK) { - return err; - } - *mediaSource = mSurfaceMediaSource; + } else if (mVideoSource == VIDEO_SOURCE_SURFACE) { + *mediaSource = NULL; } else { return INVALID_OPERATION; } return OK; } -// setupSurfaceMediaSource creates a source with the given -// width and height and framerate. -// TODO: This could go in a static function inside SurfaceMediaSource -// similar to that in CameraSource -status_t StagefrightRecorder::setupSurfaceMediaSource() { - status_t err = OK; - mSurfaceMediaSource = new SurfaceMediaSource(mVideoWidth, mVideoHeight); - if (mSurfaceMediaSource == NULL) { - return NO_INIT; - } - - if (mFrameRate == -1) { - int32_t frameRate = 0; - CHECK (mSurfaceMediaSource->getFormat()->findInt32( - kKeyFrameRate, &frameRate)); - ALOGI("Frame rate is not explicitly set. Use the current frame " - "rate (%d fps)", frameRate); - mFrameRate = frameRate; - } else { - err = mSurfaceMediaSource->setFrameRate(mFrameRate); - } - CHECK(mFrameRate != -1); - - mIsMetaDataStoredInVideoBuffers = - mSurfaceMediaSource->isMetaDataStoredInVideoBuffers(); - return err; -} - status_t StagefrightRecorder::setupCameraSource( sp *cameraSource) { status_t err = OK; @@ -1386,21 +1394,19 @@ status_t StagefrightRecorder::setupVideoEncoder( sp *source) { source->clear(); - sp enc_meta = new MetaData; - enc_meta->setInt32(kKeyBitRate, mVideoBitRate); - enc_meta->setInt32(kKeyFrameRate, mFrameRate); + sp format = new AMessage(); switch (mVideoEncoder) { case VIDEO_ENCODER_H263: - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); + format->setString("mime", MEDIA_MIMETYPE_VIDEO_H263); break; case VIDEO_ENCODER_MPEG_4_SP: - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); + format->setString("mime", MEDIA_MIMETYPE_VIDEO_MPEG4); break; case VIDEO_ENCODER_H264: - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); + format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC); break; default: @@ -1408,59 +1414,69 @@ status_t StagefrightRecorder::setupVideoEncoder( break; } - sp meta = cameraSource->getFormat(); + if (cameraSource != NULL) { + sp meta = cameraSource->getFormat(); - int32_t width, height, stride, sliceHeight, colorFormat; - CHECK(meta->findInt32(kKeyWidth, &width)); - CHECK(meta->findInt32(kKeyHeight, &height)); - CHECK(meta->findInt32(kKeyStride, &stride)); - CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight)); - CHECK(meta->findInt32(kKeyColorFormat, &colorFormat)); + int32_t width, height, stride, sliceHeight, colorFormat; + CHECK(meta->findInt32(kKeyWidth, &width)); + CHECK(meta->findInt32(kKeyHeight, &height)); + CHECK(meta->findInt32(kKeyStride, &stride)); + CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight)); + CHECK(meta->findInt32(kKeyColorFormat, &colorFormat)); + + format->setInt32("width", width); + format->setInt32("height", height); + format->setInt32("stride", stride); + format->setInt32("slice-height", sliceHeight); + format->setInt32("color-format", colorFormat); + } else { + format->setInt32("width", mVideoWidth); + format->setInt32("height", mVideoHeight); + format->setInt32("stride", mVideoWidth); + format->setInt32("slice-height", mVideoWidth); + format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque); + } + + format->setInt32("bitrate", mVideoBitRate); + format->setInt32("frame-rate", mFrameRate); + format->setInt32("i-frame-interval", mIFramesIntervalSec); - enc_meta->setInt32(kKeyWidth, width); - enc_meta->setInt32(kKeyHeight, height); - enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec); - enc_meta->setInt32(kKeyStride, stride); - enc_meta->setInt32(kKeySliceHeight, sliceHeight); - enc_meta->setInt32(kKeyColorFormat, colorFormat); if (mVideoTimeScale > 0) { - enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale); + format->setInt32("time-scale", mVideoTimeScale); } if (mVideoEncoderProfile != -1) { - enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile); + format->setInt32("profile", mVideoEncoderProfile); } if (mVideoEncoderLevel != -1) { - enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel); + format->setInt32("level", mVideoEncoderLevel); } - OMXClient client; - CHECK_EQ(client.connect(), (status_t)OK); - - uint32_t encoder_flags = 0; + uint32_t flags = 0; if (mIsMetaDataStoredInVideoBuffers) { - encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers; + flags |= MediaCodecSource::FLAG_USE_METADATA_INPUT; } - // Do not wait for all the input buffers to become available. - // This give timelapse video recording faster response in - // receiving output from video encoder component. - if (mCaptureTimeLapse) { - encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime; + if (cameraSource == NULL) { + flags |= MediaCodecSource::FLAG_USE_SURFACE_INPUT; } - sp encoder = OMXCodec::Create( - client.interface(), enc_meta, - true /* createEncoder */, cameraSource, - NULL, encoder_flags); + sp encoder = + MediaCodecSource::Create(mLooper, format, cameraSource, flags); if (encoder == NULL) { ALOGW("Failed to create the encoder"); // When the encoder fails to be created, we need // release the camera source due to the camera's lock // and unlock mechanism. - cameraSource->stop(); + if (cameraSource != NULL) { + cameraSource->stop(); + } return UNKNOWN_ERROR; } + if (cameraSource == NULL) { + mGraphicBufferProducer = encoder->getGraphicBufferProducer(); + } + *source = encoder; return OK; @@ -1494,9 +1510,10 @@ status_t StagefrightRecorder::setupAudioEncoder(const sp& writer) { return OK; } -status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) { +status_t StagefrightRecorder::setupMPEG4Recording() { mWriter.clear(); - *totalBitRate = 0; + mTotalBitRate = 0; + status_t err = OK; sp writer = new MPEG4Writer(mOutputFd); @@ -1515,7 +1532,7 @@ status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) { } writer->addSource(encoder); - *totalBitRate += mVideoBitRate; + mTotalBitRate += mVideoBitRate; } // Audio source is added at the end if it exists. @@ -1524,7 +1541,7 @@ status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) { if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) { err = setupAudioEncoder(writer); if (err != OK) return err; - *totalBitRate += mAudioBitRate; + mTotalBitRate += mAudioBitRate; } if (mInterleaveDurationUs > 0) { @@ -1542,7 +1559,13 @@ status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) { writer->setMaxFileSize(mMaxFileSizeBytes); } - mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId); + if (mVideoSource == VIDEO_SOURCE_DEFAULT + || mVideoSource == VIDEO_SOURCE_CAMERA) { + mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId); + } else if (mVideoSource == VIDEO_SOURCE_SURFACE) { + // surface source doesn't need large initial delay + mStartTimeOffsetMs = 200; + } if (mStartTimeOffsetMs > 0) { reinterpret_cast(writer.get())-> setStartTimeOffsetMs(mStartTimeOffsetMs); @@ -1553,11 +1576,11 @@ status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) { return OK; } -void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate, - sp *meta) { +void StagefrightRecorder::setupMPEG4MetaData(sp *meta) { + int64_t startTimeUs = systemTime() / 1000; (*meta)->setInt64(kKeyTime, startTimeUs); (*meta)->setInt32(kKeyFileType, mOutputFormat); - (*meta)->setInt32(kKeyBitRate, totalBitRate); + (*meta)->setInt32(kKeyBitRate, mTotalBitRate); (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset); if (mMovieTimeScale > 0) { (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale); @@ -1570,25 +1593,6 @@ void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalB } } -status_t StagefrightRecorder::startMPEG4Recording() { - int32_t totalBitRate; - status_t err = setupMPEG4Recording(&totalBitRate); - if (err != OK) { - return err; - } - - int64_t startTimeUs = systemTime() / 1000; - sp meta = new MetaData; - setupMPEG4MetaData(startTimeUs, totalBitRate, &meta); - - err = mWriter->start(meta.get()); - if (err != OK) { - return err; - } - - return OK; -} - status_t StagefrightRecorder::pause() { ALOGV("pause"); if (mWriter == NULL) { @@ -1628,6 +1632,8 @@ status_t StagefrightRecorder::stop() { mWriter.clear(); } + mGraphicBufferProducer.clear(); + if (mOutputFd >= 0) { ::close(mOutputFd); mOutputFd = -1; @@ -1647,7 +1653,6 @@ status_t StagefrightRecorder::stop() { addBatteryData(params); } - return err; } @@ -1699,6 +1704,7 @@ status_t StagefrightRecorder::reset() { mRotationDegrees = 0; mLatitudex10000 = -3600000; mLongitudex10000 = -3600000; + mTotalBitRate = 0; mOutputFd = -1; diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index bc43488..7d6abd3 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -37,6 +37,7 @@ struct AudioSource; class MediaProfiles; class IGraphicBufferProducer; class SurfaceMediaSource; +class ALooper; struct StagefrightRecorder : public MediaRecorderBase { StagefrightRecorder(); @@ -106,6 +107,7 @@ private: int32_t mLatitudex10000; int32_t mLongitudex10000; int32_t mStartTimeOffsetMs; + int32_t mTotalBitRate; bool mCaptureTimeLapse; int64_t mTimeBetweenTimeLapseFrameCaptureUs; @@ -122,17 +124,16 @@ private: // An pointer // will be sent to the client side using which the // frame buffers will be queued and dequeued - sp mSurfaceMediaSource; - - status_t setupMPEG4Recording(int32_t *totalBitRate); - void setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate, - sp *meta); - status_t startMPEG4Recording(); - status_t startAMRRecording(); - status_t startAACRecording(); - status_t startRawAudioRecording(); - status_t startRTPRecording(); - status_t startMPEG2TSRecording(); + sp mGraphicBufferProducer; + sp mLooper; + + status_t setupMPEG4Recording(); + void setupMPEG4MetaData(sp *meta); + status_t setupAMRRecording(); + status_t setupAACRecording(); + status_t setupRawAudioRecording(); + status_t setupRTPRecording(); + status_t setupMPEG2TSRecording(); sp createAudioSource(); status_t checkVideoEncoderCapabilities( bool *supportsCameraSourceMetaDataMode); @@ -142,9 +143,6 @@ private: // depending on the videosource type status_t setupMediaSource(sp *mediaSource); status_t setupCameraSource(sp *cameraSource); - // setup the surfacemediasource for the encoder - status_t setupSurfaceMediaSource(); - status_t setupAudioEncoder(const sp& writer); status_t setupVideoEncoder(sp cameraSource, sp *source); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index c9f89fc..f2354b4 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -374,7 +374,8 @@ ACodec::ACodec() mStoreMetaDataInOutputBuffers(false), mMetaDataBuffersToSubmit(0), mRepeatFrameDelayUs(-1ll), - mMaxPtsGapUs(-1l) { + mMaxPtsGapUs(-1l), + mCreateInputBuffersSuspended(false) { mUninitializedState = new UninitializedState(this); mLoadedState = new LoadedState(this); mLoadedToIdleState = new LoadedToIdleState(this); @@ -1120,6 +1121,12 @@ status_t ACodec::configureCodec( if (!msg->findInt64("max-pts-gap-to-encoder", &mMaxPtsGapUs)) { mMaxPtsGapUs = -1l; } + + if (!msg->findInt32( + "create-input-buffers-suspended", + (int32_t*)&mCreateInputBuffersSuspended)) { + mCreateInputBuffersSuspended = false; + } } // Always try to enable dynamic output buffers on native surface @@ -3941,6 +3948,22 @@ void ACodec::LoadedState::onCreateInputSurface( if (err != OK) { ALOGE("[%s] Unable to configure max timestamp gap (err %d)", + mCodec->mComponentName.c_str(), + err); + } + } + + if (err == OK && mCodec->mCreateInputBuffersSuspended) { + bool suspend = true; + err = mCodec->mOMX->setInternalOption( + mCodec->mNode, + kPortIndexInput, + IOMX::INTERNAL_OPTION_SUSPEND, + &suspend, + sizeof(suspend)); + + if (err != OK) { + ALOGE("[%s] Unable to configure option to suspend (err %d)", mCodec->mComponentName.c_str(), err); } @@ -4003,6 +4026,7 @@ status_t ACodec::LoadedToIdleState::allocateBuffers() { bool ACodec::LoadedToIdleState::onMessageReceived(const sp &msg) { switch (msg->what()) { + case kWhatSetParameters: case kWhatShutdown: { mCodec->deferMessage(msg); @@ -4069,6 +4093,7 @@ void ACodec::IdleToExecutingState::stateEntered() { bool ACodec::IdleToExecutingState::onMessageReceived(const sp &msg) { switch (msg->what()) { + case kWhatSetParameters: case kWhatShutdown: { mCodec->deferMessage(msg); @@ -4338,6 +4363,22 @@ status_t ACodec::setParameters(const sp ¶ms) { } } + int64_t skipFramesBeforeUs; + if (params->findInt64("skip-frames-before", &skipFramesBeforeUs)) { + status_t err = + mOMX->setInternalOption( + mNode, + kPortIndexInput, + IOMX::INTERNAL_OPTION_START_TIME, + &skipFramesBeforeUs, + sizeof(skipFramesBeforeUs)); + + if (err != OK) { + ALOGE("Failed to set parameter 'skip-frames-before' (err %d)", err); + return err; + } + } + int32_t dropInputFrames; if (params->findInt32("drop-input-frames", &dropInputFrames)) { bool suspend = dropInputFrames != 0; diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index c6cee5d..bc08718 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -30,6 +30,7 @@ LOCAL_SRC_FILES:= \ MediaBufferGroup.cpp \ MediaCodec.cpp \ MediaCodecList.cpp \ + MediaCodecSource.cpp \ MediaDefs.cpp \ MediaExtractor.cpp \ http/MediaHTTP.cpp \ diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index b7a4b75..0fa3b2d 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -1763,7 +1763,7 @@ status_t MPEG4Writer::Track::pause() { } status_t MPEG4Writer::Track::stop() { - ALOGD("Stopping %s track", mIsAudio? "Audio": "Video"); + ALOGD("%s track stopping", mIsAudio? "Audio": "Video"); if (!mStarted) { ALOGE("Stop() called but track is not started"); return ERROR_END_OF_STREAM; @@ -1774,19 +1774,14 @@ status_t MPEG4Writer::Track::stop() { } mDone = true; + ALOGD("%s track source stopping", mIsAudio? "Audio": "Video"); + mSource->stop(); + ALOGD("%s track source stopped", mIsAudio? "Audio": "Video"); + void *dummy; pthread_join(mThread, &dummy); - status_t err = (status_t) dummy; - ALOGD("Stopping %s track source", mIsAudio? "Audio": "Video"); - { - status_t status = mSource->stop(); - if (err == OK && status != OK && status != ERROR_END_OF_STREAM) { - err = status; - } - } - ALOGD("%s track stopped", mIsAudio? "Audio": "Video"); return err; } diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp new file mode 100644 index 0000000..2c20d62 --- /dev/null +++ b/media/libstagefright/MediaCodecSource.cpp @@ -0,0 +1,881 @@ +/* + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaCodecSource" +#define DEBUG_DRIFT_TIME 0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +static void ReleaseMediaBufferReference(const sp &accessUnit) { + void *mbuf; + if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf) + && mbuf != NULL) { + ALOGV("releasing mbuf %p", mbuf); + + accessUnit->meta()->setPointer("mediaBuffer", NULL); + + static_cast(mbuf)->release(); + mbuf = NULL; + } +} + +struct MediaCodecSource::Puller : public AHandler { + Puller(const sp &source); + + status_t start(const sp &meta, const sp ¬ify); + void stopAsync(); + + void pause(); + void resume(); + +protected: + virtual void onMessageReceived(const sp &msg); + virtual ~Puller(); + +private: + enum { + kWhatStart = 'msta', + kWhatStop, + kWhatPull, + kWhatPause, + kWhatResume, + }; + + sp mSource; + sp mNotify; + sp mLooper; + int32_t mPullGeneration; + bool mIsAudio; + bool mPaused; + bool mReachedEOS; + + status_t postSynchronouslyAndReturnError(const sp &msg); + void schedulePull(); + void handleEOS(); + + DISALLOW_EVIL_CONSTRUCTORS(Puller); +}; + +MediaCodecSource::Puller::Puller(const sp &source) + : mSource(source), + mLooper(new ALooper()), + mPullGeneration(0), + mIsAudio(false), + mPaused(false), + mReachedEOS(false) { + sp meta = source->getFormat(); + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + + mIsAudio = !strncasecmp(mime, "audio/", 6); + + mLooper->setName("pull_looper"); +} + +MediaCodecSource::Puller::~Puller() { + mLooper->unregisterHandler(id()); + mLooper->stop(); +} + +status_t MediaCodecSource::Puller::postSynchronouslyAndReturnError( + const sp &msg) { + sp response; + status_t err = msg->postAndAwaitResponse(&response); + + if (err != OK) { + return err; + } + + if (!response->findInt32("err", &err)) { + err = OK; + } + + return err; +} + +status_t MediaCodecSource::Puller::start(const sp &meta, + const sp ¬ify) { + ALOGV("puller (%s) start", mIsAudio ? "audio" : "video"); + mLooper->start( + false /* runOnCallingThread */, + false /* canCallJava */, + PRIORITY_AUDIO); + mLooper->registerHandler(this); + mNotify = notify; + + sp msg = new AMessage(kWhatStart, id()); + msg->setObject("meta", meta); + return postSynchronouslyAndReturnError(msg); +} + +void MediaCodecSource::Puller::stopAsync() { + ALOGV("puller (%s) stopAsync", mIsAudio ? "audio" : "video"); + (new AMessage(kWhatStop, id()))->post(); +} + +void MediaCodecSource::Puller::pause() { + (new AMessage(kWhatPause, id()))->post(); +} + +void MediaCodecSource::Puller::resume() { + (new AMessage(kWhatResume, id()))->post(); +} + +void MediaCodecSource::Puller::schedulePull() { + sp msg = new AMessage(kWhatPull, id()); + msg->setInt32("generation", mPullGeneration); + msg->post(); +} + +void MediaCodecSource::Puller::handleEOS() { + if (!mReachedEOS) { + ALOGV("puller (%s) posting EOS", mIsAudio ? "audio" : "video"); + mReachedEOS = true; + sp notify = mNotify->dup(); + notify->setPointer("accessUnit", NULL); + notify->post(); + } +} + +void MediaCodecSource::Puller::onMessageReceived(const sp &msg) { + switch (msg->what()) { + case kWhatStart: + { + sp obj; + CHECK(msg->findObject("meta", &obj)); + + mReachedEOS = false; + + status_t err = mSource->start(static_cast(obj.get())); + + if (err == OK) { + schedulePull(); + } + + sp response = new AMessage; + response->setInt32("err", err); + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + response->postReply(replyID); + break; + } + + case kWhatStop: + { + ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video"); + mSource->stop(); + ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video"); + ++mPullGeneration; + + handleEOS(); + break; + } + + case kWhatPull: + { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + + if (generation != mPullGeneration) { + break; + } + + MediaBuffer *mbuf; + status_t err = mSource->read(&mbuf); + + if (mPaused) { + if (err == OK) { + mbuf->release(); + mbuf = NULL; + } + + msg->post(); + break; + } + + if (err != OK) { + if (err == ERROR_END_OF_STREAM) { + ALOGV("stream ended, mbuf %p", mbuf); + } else { + ALOGE("error %d reading stream.", err); + } + handleEOS(); + } else { + sp notify = mNotify->dup(); + + notify->setPointer("accessUnit", mbuf); + notify->post(); + + msg->post(); + } + break; + } + + case kWhatPause: + { + mPaused = true; + break; + } + + case kWhatResume: + { + mPaused = false; + break; + } + + default: + TRESPASS(); + } +} + +// static +sp MediaCodecSource::Create( + const sp &looper, + const sp &format, + const sp &source, + uint32_t flags) { + sp mediaSource = + new MediaCodecSource(looper, format, source, flags); + + if (mediaSource->init() == OK) { + return mediaSource; + } + return NULL; +} + +status_t MediaCodecSource::start(MetaData* params) { + sp msg = new AMessage(kWhatStart, mReflector->id()); + msg->setObject("meta", params); + return postSynchronouslyAndReturnError(msg); +} + +status_t MediaCodecSource::stop() { + sp msg = new AMessage(kWhatStop, mReflector->id()); + return postSynchronouslyAndReturnError(msg); +} + +status_t MediaCodecSource::pause() { + (new AMessage(kWhatPause, mReflector->id()))->post(); + return OK; +} + +sp MediaCodecSource::getGraphicBufferProducer() { + CHECK(mFlags & FLAG_USE_SURFACE_INPUT); + return mGraphicBufferProducer; +} + +status_t MediaCodecSource::read(MediaBuffer** buffer, + const ReadOptions* options) { + Mutex::Autolock autolock(mOutputBufferLock); + + *buffer = NULL; + while (mOutputBufferQueue.size() == 0 && !mEncodedReachedEOS) { + mOutputBufferCond.wait(mOutputBufferLock); + } + if (!mEncodedReachedEOS) { + *buffer = *mOutputBufferQueue.begin(); + mOutputBufferQueue.erase(mOutputBufferQueue.begin()); + return OK; + } + return mErrorCode; +} + +void MediaCodecSource::signalBufferReturned(MediaBuffer *buffer) { + buffer->setObserver(0); + buffer->release(); +} + +MediaCodecSource::MediaCodecSource( + const sp &looper, + const sp &outputFormat, + const sp &source, + uint32_t flags) + : mLooper(looper), + mOutputFormat(outputFormat), + mMeta(new MetaData), + mFlags(flags), + mIsVideo(false), + mStarted(false), + mStopping(false), + mDoMoreWorkPending(false), + mPullerReachedEOS(false), + mFirstSampleTimeUs(-1ll), + mEncodedReachedEOS(false), + mErrorCode(OK) { + CHECK(mLooper != NULL); + + AString mime; + CHECK(mOutputFormat->findString("mime", &mime)); + + if (!strncasecmp("video/", mime.c_str(), 6)) { + mIsVideo = true; + } + + if (!(mFlags & FLAG_USE_SURFACE_INPUT)) { + mPuller = new Puller(source); + } +} + +MediaCodecSource::~MediaCodecSource() { + releaseEncoder(); + + mCodecLooper->stop(); + mLooper->unregisterHandler(mReflector->id()); +} + +status_t MediaCodecSource::init() { + status_t err = initEncoder(); + + if (err != OK) { + releaseEncoder(); + } + + return err; +} + +status_t MediaCodecSource::initEncoder() { + mReflector = new AHandlerReflector(this); + mLooper->registerHandler(mReflector); + + mCodecLooper = new ALooper; + mCodecLooper->setName("codec_looper"); + mCodecLooper->start(); + + if (mFlags & FLAG_USE_METADATA_INPUT) { + mOutputFormat->setInt32("store-metadata-in-buffers", 1); + } + + if (mFlags & FLAG_USE_SURFACE_INPUT) { + mOutputFormat->setInt32("create-input-buffers-suspended", 1); + } + + AString outputMIME; + CHECK(mOutputFormat->findString("mime", &outputMIME)); + + mEncoder = MediaCodec::CreateByType( + mCodecLooper, outputMIME.c_str(), true /* encoder */); + + if (mEncoder == NULL) { + return NO_INIT; + } + + ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str()); + + status_t err = mEncoder->configure( + mOutputFormat, + NULL /* nativeWindow */, + NULL /* crypto */, + MediaCodec::CONFIGURE_FLAG_ENCODE); + + if (err != OK) { + return err; + } + + mEncoder->getOutputFormat(&mOutputFormat); + convertMessageToMetaData(mOutputFormat, mMeta); + + if (mFlags & FLAG_USE_SURFACE_INPUT) { + CHECK(mIsVideo); + + err = mEncoder->createInputSurface(&mGraphicBufferProducer); + + if (err != OK) { + return err; + } + } + + err = mEncoder->start(); + + if (err != OK) { + return err; + } + + err = mEncoder->getInputBuffers(&mEncoderInputBuffers); + + if (err != OK) { + return err; + } + + err = mEncoder->getOutputBuffers(&mEncoderOutputBuffers); + + if (err != OK) { + return err; + } + + mEncodedReachedEOS = false; + mErrorCode = OK; + + return OK; +} + +void MediaCodecSource::releaseEncoder() { + if (mEncoder == NULL) { + return; + } + + mEncoder->release(); + mEncoder.clear(); + + while (!mInputBufferQueue.empty()) { + MediaBuffer *mbuf = *mInputBufferQueue.begin(); + mInputBufferQueue.erase(mInputBufferQueue.begin()); + if (mbuf != NULL) { + mbuf->release(); + } + } + + for (size_t i = 0; i < mEncoderInputBuffers.size(); ++i) { + sp accessUnit = mEncoderInputBuffers.itemAt(i); + ReleaseMediaBufferReference(accessUnit); + } + + mEncoderInputBuffers.clear(); + mEncoderOutputBuffers.clear(); +} + +bool MediaCodecSource::reachedEOS() { + return mEncodedReachedEOS && ((mPuller == NULL) || mPullerReachedEOS); +} + +status_t MediaCodecSource::postSynchronouslyAndReturnError( + const sp &msg) { + sp response; + status_t err = msg->postAndAwaitResponse(&response); + + if (err != OK) { + return err; + } + + if (!response->findInt32("err", &err)) { + err = OK; + } + + return err; +} + +void MediaCodecSource::signalEOS(status_t err) { + if (!mEncodedReachedEOS) { + ALOGI("encoder (%s) reached EOS", mIsVideo ? "video" : "audio"); + { + Mutex::Autolock autoLock(mOutputBufferLock); + // release all unread media buffers + for (List::iterator it = mOutputBufferQueue.begin(); + it != mOutputBufferQueue.end(); it++) { + (*it)->release(); + } + mOutputBufferQueue.clear(); + mEncodedReachedEOS = true; + mErrorCode = err; + mOutputBufferCond.signal(); + } + + releaseEncoder(); + } + if (mStopping && reachedEOS()) { + ALOGI("MediaCodecSource (%s) fully stopped", + mIsVideo ? "video" : "audio"); + // posting reply to everyone that's waiting + List::iterator it; + for (it = mStopReplyIDQueue.begin(); + it != mStopReplyIDQueue.end(); it++) { + (new AMessage)->postReply(*it); + } + mStopReplyIDQueue.clear(); + mStopping = false; + } +} + +void MediaCodecSource::suspend() { + CHECK(mFlags & FLAG_USE_SURFACE_INPUT); + if (mEncoder != NULL) { + sp params = new AMessage; + params->setInt32("drop-input-frames", true); + mEncoder->setParameters(params); + } +} + +void MediaCodecSource::resume(int64_t skipFramesBeforeUs) { + CHECK(mFlags & FLAG_USE_SURFACE_INPUT); + if (mEncoder != NULL) { + sp params = new AMessage; + params->setInt32("drop-input-frames", false); + if (skipFramesBeforeUs > 0) { + params->setInt64("skip-frames-before", skipFramesBeforeUs); + } + mEncoder->setParameters(params); + } +} + +void MediaCodecSource::scheduleDoMoreWork() { + if (mDoMoreWorkPending) { + return; + } + + mDoMoreWorkPending = true; + + if (mEncoderActivityNotify == NULL) { + mEncoderActivityNotify = new AMessage( + kWhatEncoderActivity, mReflector->id()); + } + mEncoder->requestActivityNotification(mEncoderActivityNotify); +} + +status_t MediaCodecSource::feedEncoderInputBuffers() { + while (!mInputBufferQueue.empty() + && !mAvailEncoderInputIndices.empty()) { + MediaBuffer* mbuf = *mInputBufferQueue.begin(); + mInputBufferQueue.erase(mInputBufferQueue.begin()); + + size_t bufferIndex = *mAvailEncoderInputIndices.begin(); + mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin()); + + int64_t timeUs = 0ll; + uint32_t flags = 0; + size_t size = 0; + + if (mbuf != NULL) { + CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); + + // push decoding time for video, or drift time for audio + if (mIsVideo) { + mDecodingTimeQueue.push_back(timeUs); + } else { +#if DEBUG_DRIFT_TIME + if (mFirstSampleTimeUs < 0ll) { + mFirstSampleTimeUs = timeUs; + } + + int64_t driftTimeUs = 0; + if (mbuf->meta_data()->findInt64(kKeyDriftTime, &driftTimeUs) + && driftTimeUs) { + driftTimeUs = timeUs - mFirstSampleTimeUs - driftTimeUs; + } + mDriftTimeQueue.push_back(driftTimeUs); +#endif // DEBUG_DRIFT_TIME + } + + size = mbuf->size(); + + memcpy(mEncoderInputBuffers.itemAt(bufferIndex)->data(), + mbuf->data(), size); + + if (mIsVideo) { + // video encoder will release MediaBuffer when done + // with underlying data. + mEncoderInputBuffers.itemAt(bufferIndex)->meta() + ->setPointer("mediaBuffer", mbuf); + } else { + mbuf->release(); + } + } else { + flags = MediaCodec::BUFFER_FLAG_EOS; + } + + status_t err = mEncoder->queueInputBuffer( + bufferIndex, 0, size, timeUs, flags); + + if (err != OK) { + return err; + } + } + + return OK; +} + +status_t MediaCodecSource::doMoreWork() { + status_t err; + + if (!(mFlags & FLAG_USE_SURFACE_INPUT)) { + for (;;) { + size_t bufferIndex; + err = mEncoder->dequeueInputBuffer(&bufferIndex); + + if (err != OK) { + break; + } + + mAvailEncoderInputIndices.push_back(bufferIndex); + } + + feedEncoderInputBuffers(); + } + + for (;;) { + size_t bufferIndex; + size_t offset; + size_t size; + int64_t timeUs; + uint32_t flags; + native_handle_t* handle = NULL; + err = mEncoder->dequeueOutputBuffer( + &bufferIndex, &offset, &size, &timeUs, &flags); + + if (err != OK) { + if (err == INFO_FORMAT_CHANGED) { + continue; + } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) { + mEncoder->getOutputBuffers(&mEncoderOutputBuffers); + continue; + } + + if (err == -EAGAIN) { + err = OK; + } + break; + } + if (!(flags & MediaCodec::BUFFER_FLAG_EOS)) { + sp outbuf = mEncoderOutputBuffers.itemAt(bufferIndex); + + MediaBuffer *mbuf = new MediaBuffer(outbuf->size()); + memcpy(mbuf->data(), outbuf->data(), outbuf->size()); + + if (!(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)) { + if (mIsVideo) { + int64_t decodingTimeUs; + if (mFlags & FLAG_USE_SURFACE_INPUT) { + // GraphicBufferSource is supposed to discard samples + // queued before start, and offset timeUs by start time + CHECK_GE(timeUs, 0ll); + // TODO: + // Decoding time for surface source is unavailable, + // use presentation time for now. May need to move + // this logic into MediaCodec. + decodingTimeUs = timeUs; + } else { + CHECK(!mDecodingTimeQueue.empty()); + decodingTimeUs = *(mDecodingTimeQueue.begin()); + mDecodingTimeQueue.erase(mDecodingTimeQueue.begin()); + } + mbuf->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs); + + ALOGV("[video] time %lld us (%.2f secs), dts/pts diff %lld", + timeUs, timeUs / 1E6, decodingTimeUs - timeUs); + } else { + int64_t driftTimeUs = 0; +#if DEBUG_DRIFT_TIME + CHECK(!mDriftTimeQueue.empty()); + driftTimeUs = *(mDriftTimeQueue.begin()); + mDriftTimeQueue.erase(mDriftTimeQueue.begin()); + mbuf->meta_data()->setInt64(kKeyDriftTime, driftTimeUs); +#endif // DEBUG_DRIFT_TIME + ALOGV("[audio] time %lld us (%.2f secs), drift %lld", + timeUs, timeUs / 1E6, driftTimeUs); + } + mbuf->meta_data()->setInt64(kKeyTime, timeUs); + } else { + mbuf->meta_data()->setInt32(kKeyIsCodecConfig, true); + } + if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) { + mbuf->meta_data()->setInt32(kKeyIsSyncFrame, true); + } + mbuf->setObserver(this); + mbuf->add_ref(); + + { + Mutex::Autolock autoLock(mOutputBufferLock); + mOutputBufferQueue.push_back(mbuf); + mOutputBufferCond.signal(); + } + } + + mEncoder->releaseOutputBuffer(bufferIndex); + + if (flags & MediaCodec::BUFFER_FLAG_EOS) { + err = ERROR_END_OF_STREAM; + break; + } + } + + return err; +} + +status_t MediaCodecSource::onStart(MetaData *params) { + if (mStopping) { + ALOGE("Failed to start while we're stopping"); + return INVALID_OPERATION; + } + + if (mStarted) { + ALOGI("MediaCodecSource (%s) resuming", mIsVideo ? "video" : "audio"); + if (mFlags & FLAG_USE_SURFACE_INPUT) { + resume(); + } else { + CHECK(mPuller != NULL); + mPuller->resume(); + } + return OK; + } + + ALOGI("MediaCodecSource (%s) starting", mIsVideo ? "video" : "audio"); + + status_t err = OK; + + if (mFlags & FLAG_USE_SURFACE_INPUT) { + int64_t startTimeUs; + if (!params || !params->findInt64(kKeyTime, &startTimeUs)) { + startTimeUs = -1ll; + } + resume(startTimeUs); + scheduleDoMoreWork(); + } else { + CHECK(mPuller != NULL); + sp notify = new AMessage( + kWhatPullerNotify, mReflector->id()); + err = mPuller->start(params, notify); + if (err != OK) { + mPullerReachedEOS = true; + return err; + } + } + + ALOGI("MediaCodecSource (%s) started", mIsVideo ? "video" : "audio"); + + mStarted = true; + return OK; +} + +void MediaCodecSource::onMessageReceived(const sp &msg) { + switch (msg->what()) { + case kWhatPullerNotify: + { + MediaBuffer *mbuf; + CHECK(msg->findPointer("accessUnit", (void**)&mbuf)); + + if (mbuf == NULL) { + ALOGI("puller (%s) reached EOS", + mIsVideo ? "video" : "audio"); + mPullerReachedEOS = true; + } + + if (mEncoder == NULL) { + ALOGV("got msg '%s' after encoder shutdown.", + msg->debugString().c_str()); + + if (mbuf != NULL) { + mbuf->release(); + } else { + signalEOS(); + } + break; + } + + mInputBufferQueue.push_back(mbuf); + + feedEncoderInputBuffers(); + scheduleDoMoreWork(); + + break; + } + case kWhatEncoderActivity: + { + mDoMoreWorkPending = false; + + if (mEncoder == NULL) { + break; + } + + status_t err = doMoreWork(); + + if (err == OK) { + scheduleDoMoreWork(); + } else { + // reached EOS, or error + signalEOS(err); + } + + break; + } + case kWhatStart: + { + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + sp obj; + CHECK(msg->findObject("meta", &obj)); + MetaData *params = static_cast(obj.get()); + + sp response = new AMessage; + response->setInt32("err", onStart(params)); + response->postReply(replyID); + break; + } + case kWhatStop: + { + ALOGI("MediaCodecSource (%s) stopping", mIsVideo ? "video" : "audio"); + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + if (reachedEOS()) { + // if we already reached EOS, reply and return now + ALOGI("MediaCodecSource (%s) already stopped", + mIsVideo ? "video" : "audio"); + (new AMessage)->postReply(replyID); + break; + } + + mStopReplyIDQueue.push_back(replyID); + if (mStopping) { + // nothing to do if we're already stopping, reply will be posted + // to all when we're stopped. + break; + } + + mStopping = true; + + // if using surface, signal source EOS and wait for EOS to come back. + // otherwise, release encoder and post EOS if haven't done already + if (mFlags & FLAG_USE_SURFACE_INPUT) { + mEncoder->signalEndOfInputStream(); + } else { + CHECK(mPuller != NULL); + mPuller->stopAsync(); + signalEOS(); + } + break; + } + case kWhatPause: + { + if (mFlags && FLAG_USE_SURFACE_INPUT) { + suspend(); + } else { + CHECK(mPuller != NULL); + mPuller->pause(); + } + break; + } + default: + TRESPASS(); + } +} + +} // namespace android diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 20fa7ce..1e6de55 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -45,6 +45,7 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, mMaxTimestampGapUs(-1ll), mPrevOriginalTimeUs(-1ll), mPrevModifiedTimeUs(-1ll), + mSkipFramesBeforeNs(-1ll), mRepeatLastFrameGeneration(0), mRepeatLastFrameTimestamp(-1ll), mLatestSubmittedBufferId(-1), @@ -414,7 +415,18 @@ bool GraphicBufferSource::fillCodecBuffer_l() { mBufferSlot[item.mBuf] = item.mGraphicBuffer; } - err = submitBuffer_l(item, cbi); + err = UNKNOWN_ERROR; + + // only submit sample if start time is unspecified, or sample + // is queued after the specified start time + if (mSkipFramesBeforeNs < 0ll || item.mTimestamp >= mSkipFramesBeforeNs) { + // if start time is set, offset time stamp by start time + if (mSkipFramesBeforeNs > 0) { + item.mTimestamp -= mSkipFramesBeforeNs; + } + err = submitBuffer_l(item, cbi); + } + if (err != OK) { ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf); mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, @@ -762,6 +774,14 @@ status_t GraphicBufferSource::setMaxTimestampGapUs(int64_t maxGapUs) { return OK; } + +void GraphicBufferSource::setSkipFramesBeforeUs(int64_t skipFramesBeforeUs) { + Mutex::Autolock autoLock(mMutex); + + mSkipFramesBeforeNs = + (skipFramesBeforeUs > 0) ? (skipFramesBeforeUs * 1000) : -1ll; +} + void GraphicBufferSource::onMessageReceived(const sp &msg) { switch (msg->what()) { case kWhatRepeatLastFrame: diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index 3b0e454..153f2a0 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -118,6 +118,10 @@ public: // of suspension on input. status_t setMaxTimestampGapUs(int64_t maxGapUs); + // Sets the start time us (in system time), samples before which should + // be dropped and not submitted to encoder + void setSkipFramesBeforeUs(int64_t startTimeUs); + protected: // BufferQueue::ConsumerListener interface, called when a new frame of // data is available. If we're executing and a codec buffer is @@ -223,16 +227,17 @@ private: enum { kRepeatLastFrameCount = 10, }; - int64_t mRepeatAfterUs; - int64_t mMaxTimestampGapUs; KeyedVector mOriginalTimeUs; + int64_t mMaxTimestampGapUs; int64_t mPrevOriginalTimeUs; int64_t mPrevModifiedTimeUs; + int64_t mSkipFramesBeforeNs; sp mLooper; sp > mReflector; + int64_t mRepeatAfterUs; int32_t mRepeatLastFrameGeneration; int64_t mRepeatLastFrameTimestamp; int32_t mRepeatLastFrameCount; diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index 6c5c857..dba522f 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -850,6 +850,7 @@ status_t OMXNodeInstance::setInternalOption( case IOMX::INTERNAL_OPTION_SUSPEND: case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY: case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: + case IOMX::INTERNAL_OPTION_START_TIME: { const sp &bufferSource = getGraphicBufferSource(); @@ -874,7 +875,8 @@ status_t OMXNodeInstance::setInternalOption( int64_t delayUs = *(int64_t *)data; return bufferSource->setRepeatPreviousFrameDelayUs(delayUs); - } else { + } else if (type == + IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP){ if (size != sizeof(int64_t)) { return INVALID_OPERATION; } @@ -882,6 +884,14 @@ status_t OMXNodeInstance::setInternalOption( int64_t maxGapUs = *(int64_t *)data; return bufferSource->setMaxTimestampGapUs(maxGapUs); + } else { // IOMX::INTERNAL_OPTION_START_TIME + if (size != sizeof(int64_t)) { + return INVALID_OPERATION; + } + + int64_t skipFramesBeforeUs = *(int64_t *)data; + + bufferSource->setSkipFramesBeforeUs(skipFramesBeforeUs); } return OK; diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp index 49ffcd6..ddedad7 100644 --- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp +++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp @@ -746,9 +746,8 @@ TEST_F(SurfaceMediaSourceTest, DISABLED_EncodingFromCpuYV12BufferNpotWriteMediaS CHECK(fd >= 0); sp mr = SurfaceMediaSourceGLTest::setUpMediaRecorder(fd, - VIDEO_SOURCE_GRALLOC_BUFFER, - OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, - mYuvTexHeight, 30); + VIDEO_SOURCE_SURFACE, OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, + mYuvTexWidth, mYuvTexHeight, 30); // get the reference to the surfacemediasource living in // mediaserver that is created by stagefrightrecorder sp iST = mr->querySurfaceMediaSourceFromMediaServer(); @@ -880,7 +879,7 @@ TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaSameImageEachBufNpotWrite) { } CHECK(fd >= 0); - sp mr = setUpMediaRecorder(fd, VIDEO_SOURCE_GRALLOC_BUFFER, + sp mr = setUpMediaRecorder(fd, VIDEO_SOURCE_SURFACE, OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30); // get the reference to the surfacemediasource living in @@ -923,7 +922,7 @@ TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaDiffImageEachBufNpotWrite) { } CHECK(fd >= 0); - sp mr = setUpMediaRecorder(fd, VIDEO_SOURCE_GRALLOC_BUFFER, + sp mr = setUpMediaRecorder(fd, VIDEO_SOURCE_SURFACE, OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30); // get the reference to the surfacemediasource living in -- cgit v1.1 From 8d0c751c1d02aef9d96bb98f5c7be57676420120 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Thu, 6 Feb 2014 11:08:20 -0800 Subject: Remove libstagefright_http_support from the PDK build. Change-Id: Ie9f81b1cd2694e65fe2d7590cf2ad9e7dad162ce --- media/libstagefright/http/Android.mk | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'media') diff --git a/media/libstagefright/http/Android.mk b/media/libstagefright/http/Android.mk index baef9ab..a6b481f 100644 --- a/media/libstagefright/http/Android.mk +++ b/media/libstagefright/http/Android.mk @@ -1,5 +1,7 @@ LOCAL_PATH:= $(call my-dir) +ifneq ($(TARGET_BUILD_PDK), true) + include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ @@ -20,3 +22,5 @@ LOCAL_MODULE:= libstagefright_http_support LOCAL_CFLAGS += -Wno-multichar include $(BUILD_SHARED_LIBRARY) + +endif -- cgit v1.1 From 80520381d0bdf3451bd17c9ddef73d3fe71c58c2 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 31 Jan 2014 16:49:31 -0800 Subject: Fix warnings about unused parameters Change-Id: I27dc108e2c1f7ffd414bb7ff3d4c349651da6c26 --- media/libmedia/MediaProfiles.cpp | 20 +++++++++++++------- media/libmediaplayerservice/MediaPlayerService.h | 6 +++--- 2 files changed, 16 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp index 8319cd7..1074da9 100644 --- a/media/libmedia/MediaProfiles.cpp +++ b/media/libmedia/MediaProfiles.cpp @@ -81,8 +81,14 @@ const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = { {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA}, }; +#if LOG_NDEBUG +#define UNUSED __unused +#else +#define UNUSED +#endif + /*static*/ void -MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec) +MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec UNUSED) { ALOGV("video codec:"); ALOGV("codec = %d", codec.mCodec); @@ -93,7 +99,7 @@ MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec) } /*static*/ void -MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec) +MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec UNUSED) { ALOGV("audio codec:"); ALOGV("codec = %d", codec.mCodec); @@ -103,7 +109,7 @@ MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec) } /*static*/ void -MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap) +MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap UNUSED) { ALOGV("video encoder cap:"); ALOGV("codec = %d", cap.mCodec); @@ -114,7 +120,7 @@ MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap) } /*static*/ void -MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap) +MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap UNUSED) { ALOGV("audio encoder cap:"); ALOGV("codec = %d", cap.mCodec); @@ -124,21 +130,21 @@ MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap) } /*static*/ void -MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap) +MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap UNUSED) { ALOGV("video decoder cap:"); ALOGV("codec = %d", cap.mCodec); } /*static*/ void -MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap) +MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap UNUSED) { ALOGV("audio codec cap:"); ALOGV("codec = %d", cap.mCodec); } /*static*/ void -MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap) +MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap UNUSED) { ALOGV("videoeditor cap:"); ALOGV("mMaxInputFrameWidth = %d", cap.mMaxInputFrameWidth); diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 65b28dc..fc355b0 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -211,12 +211,12 @@ class MediaPlayerService : public BnMediaPlayerService virtual void flush() {} virtual void pause() {} virtual void close() {} - void setAudioStreamType(audio_stream_type_t streamType) {} + void setAudioStreamType(audio_stream_type_t streamType __unused) {} // stream type is not used for AudioCache virtual audio_stream_type_t getAudioStreamType() const { return AUDIO_STREAM_DEFAULT; } - void setVolume(float left, float right) {} - virtual status_t setPlaybackRatePermille(int32_t ratePermille) { return INVALID_OPERATION; } + void setVolume(float left __unused, float right __unused) {} + virtual status_t setPlaybackRatePermille(int32_t ratePermille __unused) { return INVALID_OPERATION; } uint32_t sampleRate() const { return mSampleRate; } audio_format_t format() const { return mFormat; } size_t size() const { return mSize; } -- cgit v1.1 From cac3daa6332bf6d1f7d26adc4a9915f3d7992dd9 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 7 Feb 2014 09:47:14 -0800 Subject: Use printf format %#x for audio_format_t in logs Change-Id: I1c611d1037685d52ccc84efe0fccd6413ec938e9 --- media/libmedia/AudioRecord.cpp | 6 +++--- media/libmedia/AudioSystem.cpp | 6 +++--- media/libmedia/AudioTrack.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index a9ba154..541cb51 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -52,7 +52,7 @@ status_t AudioRecord::getMinFrameCount( } if (size == 0) { - ALOGE("Unsupported configuration: sampleRate %u, format %d, channelMask %#x", + ALOGE("Unsupported configuration: sampleRate %u, format %#x, channelMask %#x", sampleRate, format, channelMask); return BAD_VALUE; } @@ -191,12 +191,12 @@ status_t AudioRecord::set( // validate parameters if (!audio_is_valid_format(format)) { - ALOGE("Invalid format %d", format); + ALOGE("Invalid format %#x", format); return BAD_VALUE; } // Temporary restriction: AudioFlinger currently supports 16-bit PCM only if (format != AUDIO_FORMAT_PCM_16_BIT) { - ALOGE("Format %d is not supported", format); + ALOGE("Format %#x is not supported", format); return BAD_VALUE; } mFormat = format; diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 1ab94fa..51dba7b 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -370,7 +370,7 @@ status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t for } inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask); if (inBuffSize == 0) { - ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %x channelMask %x", + ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %#x channelMask %x", sampleRate, format, channelMask); return BAD_VALUE; } @@ -481,7 +481,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle OutputDescriptor *outputDesc = new OutputDescriptor(*desc); gOutputs.add(ioHandle, outputDesc); - ALOGV("ioConfigChanged() new output samplingRate %u, format %d channel mask %#x frameCount %u " + ALOGV("ioConfigChanged() new output samplingRate %u, format %#x channel mask %#x frameCount %u " "latency %d", outputDesc->samplingRate, outputDesc->format, outputDesc->channelMask, outputDesc->frameCount, outputDesc->latency); @@ -505,7 +505,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle if (param2 == NULL) break; desc = (const OutputDescriptor *)param2; - ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %d channel mask %#x " + ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %#x channel mask %#x " "frameCount %d latency %d", ioHandle, desc->samplingRate, desc->format, desc->channelMask, desc->frameCount, desc->latency); diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index cfd79bc..41b4845 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -273,7 +273,7 @@ status_t AudioTrack::set( // validate parameters if (!audio_is_valid_format(format)) { - ALOGE("Invalid format %d", format); + ALOGE("Invalid format %#x", format); return BAD_VALUE; } mFormat = format; -- cgit v1.1 From 4944acb7355b3aa25748fd25945a363a69d65444 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 19 Aug 2013 08:39:20 -0700 Subject: Fix whitespace Change-Id: I9add0872030a26933f6b6dad1be299154611cc56 --- media/libmedia/AudioSystem.cpp | 36 ++++++++++++++++++++++++------------ media/libmedia/SoundPool.cpp | 3 ++- 2 files changed, 26 insertions(+), 13 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 1ab94fa..e224d20 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -84,13 +84,15 @@ const sp& AudioSystem::get_audio_flinger() return DEAD_OBJECT; } -status_t AudioSystem::muteMicrophone(bool state) { +status_t AudioSystem::muteMicrophone(bool state) +{ const sp& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; return af->setMicMute(state); } -status_t AudioSystem::isMicrophoneMuted(bool* state) { +status_t AudioSystem::isMicrophoneMuted(bool* state) +{ const sp& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; *state = af->getMicMute(); @@ -175,13 +177,15 @@ status_t AudioSystem::setMode(audio_mode_t mode) return af->setMode(mode); } -status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) { +status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) +{ const sp& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; return af->setParameters(ioHandle, keyValuePairs); } -String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& keys) { +String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& keys) +{ const sp& af = AudioSystem::get_audio_flinger(); String8 result = String8(""); if (af == 0) return result; @@ -413,7 +417,8 @@ status_t AudioSystem::getRenderPosition(audio_io_handle_t output, size_t *halFra return af->getRenderPosition(halFrames, dspFrames, output); } -uint32_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) { +uint32_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) +{ const sp& af = AudioSystem::get_audio_flinger(); uint32_t result = 0; if (af == 0) return result; @@ -423,20 +428,23 @@ uint32_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) { return result; } -int AudioSystem::newAudioSessionId() { +int AudioSystem::newAudioSessionId() +{ const sp& af = AudioSystem::get_audio_flinger(); if (af == 0) return 0; return af->newAudioSessionId(); } -void AudioSystem::acquireAudioSessionId(int audioSession) { +void AudioSystem::acquireAudioSessionId(int audioSession) +{ const sp& af = AudioSystem::get_audio_flinger(); if (af != 0) { af->acquireAudioSessionId(audioSession); } } -void AudioSystem::releaseAudioSessionId(int audioSession) { +void AudioSystem::releaseAudioSessionId(int audioSession) +{ const sp& af = AudioSystem::get_audio_flinger(); if (af != 0) { af->releaseAudioSessionId(audioSession); @@ -445,7 +453,8 @@ void AudioSystem::releaseAudioSessionId(int audioSession) { // --------------------------------------------------------------------------- -void AudioSystem::AudioFlingerClient::binderDied(const wp& who __unused) { +void AudioSystem::AudioFlingerClient::binderDied(const wp& who __unused) +{ Mutex::Autolock _l(AudioSystem::gLock); AudioSystem::gAudioFlinger.clear(); @@ -522,12 +531,14 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle } } -void AudioSystem::setErrorCallback(audio_error_callback cb) { +void AudioSystem::setErrorCallback(audio_error_callback cb) +{ Mutex::Autolock _l(gLock); gAudioErrorCallback = cb; } -bool AudioSystem::routedToA2dpOutput(audio_stream_type_t streamType) { +bool AudioSystem::routedToA2dpOutput(audio_stream_type_t streamType) +{ switch (streamType) { case AUDIO_STREAM_MUSIC: case AUDIO_STREAM_VOICE_CALL: @@ -831,7 +842,8 @@ bool AudioSystem::isOffloadSupported(const audio_offload_info_t& info) // --------------------------------------------------------------------------- -void AudioSystem::AudioPolicyServiceClient::binderDied(const wp& who __unused) { +void AudioSystem::AudioPolicyServiceClient::binderDied(const wp& who __unused) +{ Mutex::Autolock _l(AudioSystem::gLock); AudioSystem::gAudioPolicyService.clear(); diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp index 9ed010d..4885b4f 100644 --- a/media/libmedia/SoundPool.cpp +++ b/media/libmedia/SoundPool.cpp @@ -737,7 +737,8 @@ void SoundChannel::process(int event, void *info, unsigned long toggle) count = b->size; } memcpy(q, p, count); -// ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size, count); +// ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size, +// count); } else if (mPos < mAudioBufferSize) { count = mAudioBufferSize - mPos; if (count > b->size) { -- cgit v1.1 From 37abc0eee8795231cc5b2e409b24604c43fbb5d0 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Fri, 7 Feb 2014 12:05:34 -0800 Subject: set AAC MPEG version to MPEG-2 wifi display play spec only allows MPEG-2 AAC. Bug: 12747927 Change-Id: Ic96d27ce57f5c8e7da55e43b38f629b5c7333817 --- media/libstagefright/wifi-display/source/TSPacketizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp index c674700..eeb3700 100644 --- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp +++ b/media/libstagefright/wifi-display/source/TSPacketizer.cpp @@ -216,7 +216,7 @@ sp TSPacketizer::Track::prependADTSHeader( uint8_t *ptr = dup->data(); *ptr++ = 0xff; - *ptr++ = 0xf1; // b11110001, ID=0, layer=0, protection_absent=1 + *ptr++ = 0xf9; // b11111001, ID=1(MPEG-2), layer=0, protection_absent=1 *ptr++ = profile << 6 -- cgit v1.1 From 456fa912e46edf0b01ea3b7760ea922c01ca1866 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Fri, 7 Feb 2014 09:32:44 -0800 Subject: fix delay when shutting down wifi display RepeaterSource needs to stop SurfaceMediaSource before stopping its looper, otherwise the stop could get queued behind the last read(), which will not return until a new frame comes. Change SurfaceMediaSource stop to signal frame avalable first, so that its read() returns EOS to reader upon stop. Bug: 11677087 Change-Id: Ie331cc8c7f4824fd3930f3e909b53db4463902fb --- media/libstagefright/SurfaceMediaSource.cpp | 5 +++-- media/libstagefright/wifi-display/source/RepeaterSource.cpp | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index 6b934d4..94c0a1e 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -202,6 +202,9 @@ status_t SurfaceMediaSource::stop() return OK; } + mStarted = false; + mFrameAvailableCondition.signal(); + while (mNumPendingBuffers > 0) { ALOGI("Still waiting for %d buffers to be returned.", mNumPendingBuffers); @@ -215,8 +218,6 @@ status_t SurfaceMediaSource::stop() mMediaBuffersAvailableCondition.wait(mMutex); } - mStarted = false; - mFrameAvailableCondition.signal(); mMediaBuffersAvailableCondition.signal(); return mBufferQueue->consumerDisconnect(); diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.cpp b/media/libstagefright/wifi-display/source/RepeaterSource.cpp index cc8dee3..59d7e6e 100644 --- a/media/libstagefright/wifi-display/source/RepeaterSource.cpp +++ b/media/libstagefright/wifi-display/source/RepeaterSource.cpp @@ -79,6 +79,8 @@ status_t RepeaterSource::stop() { ALOGV("stopping"); + status_t err = mSource->stop(); + if (mLooper != NULL) { mLooper->stop(); mLooper.clear(); @@ -92,7 +94,6 @@ status_t RepeaterSource::stop() { mBuffer = NULL; } - status_t err = mSource->stop(); ALOGV("stopped"); -- cgit v1.1 From 6a9ebb41a8084b73e654a25d97a6ae26ff4166d4 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 7 Feb 2014 14:42:22 -0800 Subject: Fix regression CTS DecoderTest.testBug11696552 started failing again, and this fixes that Change-Id: I422c3b249a1d5eb25422573d2106d1f142ccfab6 --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 2f5eff4..4ac8999 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -377,7 +377,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { mNumSamplesOutput = 0; } - if (mIsADTS) { + if (mIsADTS && inHeader->nFilledLen) { size_t adtsHeaderSize = 0; // skip 30 bits, aac_frame_length follows. // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? -- cgit v1.1 From e175d77bb610675ba2f70f24449189995ddeaf5b Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 10 Feb 2014 09:02:15 -0800 Subject: Fix build Change-Id: I9196e316dcf7a58096658313bdc925b11b23a7de --- media/libstagefright/httplive/M3UParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 292d1c4..5ef7c0f 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -425,7 +425,7 @@ static bool MakeURL(const char *baseURL, const char *url, AString *out) { end = strlen(baseURL); } // Check for the last slash before a potential query string - for (ssize_t pos - 1 = end; pos >= 0; pos--) { + for (ssize_t pos = end - 1; pos >= 0; pos--) { if (baseURL[pos] == '/') { end = pos; break; -- cgit v1.1 From 43bdc1de363a3c72c7dcf9c9a898bac109dc7cb5 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 10 Feb 2014 09:53:55 -0800 Subject: Fix build after merge from AOSP Change-Id: I1cd3432c02db1600e49ade67e6a89e39e7a8d3ed --- media/libmedia/AudioTrack.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index fa56dc2..37ae70f 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -871,24 +871,20 @@ status_t AudioTrack::createTrack_l(size_t epoch) // Client decides whether the track is TIMED (see below), but can only express a preference // for FAST. Server will perform additional tests. - if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) && !( + if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) && !(( // either of these use cases: // use case 1: shared buffer (mSharedBuffer != 0) || // use case 2: callback handler - (mCbf != NULL))) { + (mCbf != NULL)) && + // matching sample rate + (mSampleRate == afSampleRate))) { ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client"); // once denied, do not request again if IAudioTrack is re-created mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST); } ALOGV("createTrack_l() output %d afLatency %d", output, afLatency); - if ((flags & AUDIO_OUTPUT_FLAG_FAST) && sampleRate != afSampleRate) { - ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client due to mismatching sample rate (%d vs %d)", - sampleRate, afSampleRate); - flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST); - } - // The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where // n = 1 fast track with single buffering; nBuffering is ignored // n = 2 fast track with double buffering -- cgit v1.1 From 1f1f2b1678fd0d038dfc501252dd2b65ecf10cae Mon Sep 17 00:00:00 2001 From: Rachad Date: Mon, 10 Feb 2014 16:54:46 -0800 Subject: Increased recorded MP4 max file size to 4GB (more precisely 2^32-1 bytes -- FAT32 max file size) bug: 11039801 Change-Id: I6169f798c59d123d02d5fd7afa3b9e645ebdb598 --- media/libstagefright/MPEG4Writer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 0fa3b2d..763e19d 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -43,7 +43,9 @@ namespace android { static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024; -static const int64_t kMax32BitFileSize = 0x007fffffffLL; +static const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 2^32-1 : max FAT32 + // filesystem file size + // used by most SD cards static const uint8_t kNalUnitTypeSeqParamSet = 0x07; static const uint8_t kNalUnitTypePicParamSet = 0x08; static const int64_t kInitialDelayTimeUs = 700000LL; @@ -860,11 +862,11 @@ status_t MPEG4Writer::reset() { // Fix up the size of the 'mdat' chunk. if (mUse32BitOffset) { lseek64(mFd, mMdatOffset, SEEK_SET); - int32_t size = htonl(static_cast(mOffset - mMdatOffset)); + uint32_t size = htonl(static_cast(mOffset - mMdatOffset)); ::write(mFd, &size, 4); } else { lseek64(mFd, mMdatOffset + 8, SEEK_SET); - int64_t size = mOffset - mMdatOffset; + uint64_t size = mOffset - mMdatOffset; size = hton64(size); ::write(mFd, &size, 8); } -- cgit v1.1 From 0105027f2a385ecb29a64b055f3046fb01ca2803 Mon Sep 17 00:00:00 2001 From: Dongwon Kang Date: Tue, 11 Feb 2014 18:26:40 +0900 Subject: Fix wrong channel table in ESQueue according to the A/52 table 5.8 Reference: http://www.atsc.org/cms/standards/A52-2012(12-17).pdf Bug: 12950777 Change-Id: Ic60033170b21e67408a3b3444507f6528946bdd0 --- media/libstagefright/mpeg2ts/ESQueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp index ea79885..2b0711b 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.cpp +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp @@ -60,7 +60,7 @@ void ElementaryStreamQueue::clear(bool clearFormat) { // update metadata only applicable, and return the payload size static unsigned parseAC3SyncFrame( const uint8_t *ptr, size_t size, sp *metaData) { - static const unsigned channelCountTable[] = {2, 1, 2, 3, 4, 4, 5, 6}; + static const unsigned channelCountTable[] = {2, 1, 2, 3, 3, 4, 4, 5}; static const unsigned samplingRateTable[] = {48000, 44100, 32000}; static const unsigned rates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640}; -- cgit v1.1 From 84333e0475bc911adc16417f4ca327c975cf6c36 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Fri, 7 Feb 2014 15:36:10 -0800 Subject: warnings be gone. Change-Id: Ie3bae3f037730e316d7fca12e7a3527973f752ef --- media/libmediaplayerservice/StagefrightPlayer.cpp | 2 +- .../nuplayer/HTTPLiveSource.cpp | 2 +- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 2 +- .../nuplayer/NuPlayerDriver.cpp | 12 ++-- .../nuplayer/NuPlayerSource.h | 10 ++-- media/libstagefright/AACExtractor.cpp | 4 +- media/libstagefright/AACWriter.cpp | 2 +- media/libstagefright/ACodec.cpp | 2 +- media/libstagefright/AMRExtractor.cpp | 6 +- media/libstagefright/AMRWriter.cpp | 2 +- media/libstagefright/Android.mk | 2 +- media/libstagefright/AudioPlayer.cpp | 2 +- media/libstagefright/AudioSource.cpp | 4 +- media/libstagefright/AwesomePlayer.cpp | 5 +- media/libstagefright/CameraSource.cpp | 11 +++- media/libstagefright/CameraSourceTimeLapse.cpp | 2 +- media/libstagefright/FLACExtractor.cpp | 70 ++++++++++++++-------- media/libstagefright/MP3Extractor.cpp | 3 +- media/libstagefright/MPEG2TSWriter.cpp | 5 +- media/libstagefright/MPEG4Extractor.cpp | 9 ++- media/libstagefright/MPEG4Writer.cpp | 2 +- media/libstagefright/MediaAdapter.cpp | 4 +- media/libstagefright/MediaCodec.cpp | 2 +- media/libstagefright/MediaCodecSource.cpp | 4 +- media/libstagefright/NuCachedSource2.cpp | 4 +- media/libstagefright/OggExtractor.cpp | 10 ++-- media/libstagefright/StagefrightMediaScanner.cpp | 2 +- media/libstagefright/SurfaceMediaSource.cpp | 12 ++-- media/libstagefright/TimedEventQueue.cpp | 4 +- media/libstagefright/VBRISeeker.cpp | 4 +- media/libstagefright/WAVExtractor.cpp | 4 +- media/libstagefright/avc_utils.cpp | 9 +-- media/libstagefright/codecs/aacdec/Android.mk | 2 + media/libstagefright/codecs/aacenc/Android.mk | 6 ++ .../codecs/aacenc/SoftAACEncoder2.cpp | 2 +- .../codecs/aacenc/basic_op/oper_32b.c | 4 ++ media/libstagefright/codecs/aacenc/src/aacenc.c | 8 +++ media/libstagefright/codecs/aacenc/src/adj_thr.c | 2 +- media/libstagefright/codecs/aacenc/src/bitenc.c | 3 + media/libstagefright/codecs/aacenc/src/dyn_bits.c | 3 +- media/libstagefright/codecs/aacenc/src/psy_main.c | 6 +- media/libstagefright/codecs/aacenc/src/qc_main.c | 8 +-- media/libstagefright/codecs/aacenc/src/tns.c | 4 ++ .../libstagefright/codecs/amrnb/common/Android.mk | 2 + media/libstagefright/codecs/amrnb/dec/Android.mk | 4 ++ media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp | 4 +- media/libstagefright/codecs/amrnb/enc/Android.mk | 4 ++ .../codecs/amrnb/enc/SoftAMRNBEncoder.cpp | 2 +- media/libstagefright/codecs/amrwb/Android.mk | 2 + media/libstagefright/codecs/amrwbenc/Android.mk | 4 ++ .../codecs/amrwbenc/SoftAMRWBEncoder.cpp | 2 +- .../libstagefright/codecs/amrwbenc/src/autocorr.c | 4 ++ .../libstagefright/codecs/amrwbenc/src/convolve.c | 4 ++ .../libstagefright/codecs/amrwbenc/src/syn_filt.c | 4 ++ .../codecs/amrwbenc/src/voAMRWBEnc.c | 4 ++ media/libstagefright/codecs/avc/common/Android.mk | 2 + media/libstagefright/codecs/avc/enc/Android.mk | 4 ++ .../codecs/avc/enc/SoftAVCEncoder.cpp | 15 +++-- media/libstagefright/codecs/common/Android.mk | 2 + media/libstagefright/codecs/common/cmnMemory.c | 18 ++++++ media/libstagefright/codecs/flac/enc/Android.mk | 2 + .../codecs/flac/enc/SoftFlacEncoder.cpp | 21 +++++-- media/libstagefright/codecs/g711/dec/Android.mk | 2 + media/libstagefright/codecs/g711/dec/SoftG711.cpp | 2 +- media/libstagefright/codecs/gsm/dec/Android.mk | 2 + media/libstagefright/codecs/gsm/dec/SoftGSM.cpp | 2 +- .../libstagefright/codecs/m4v_h263/dec/Android.mk | 4 ++ .../codecs/m4v_h263/dec/SoftMPEG4.cpp | 2 +- .../libstagefright/codecs/m4v_h263/enc/Android.mk | 4 ++ .../codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp | 2 +- media/libstagefright/codecs/mp3dec/Android.mk | 4 ++ media/libstagefright/codecs/mp3dec/SoftMP3.cpp | 2 +- .../mp3dec/src/pvmp3_mpeg2_get_scale_data.cpp | 2 +- media/libstagefright/codecs/on2/dec/Android.mk | 2 + media/libstagefright/codecs/on2/dec/SoftVPX.cpp | 2 +- media/libstagefright/codecs/on2/enc/Android.mk | 2 + .../libstagefright/codecs/on2/h264dec/SoftAVC.cpp | 2 +- .../codecs/on2/h264dec/source/H264SwDecApi.c | 3 + .../codecs/on2/h264dec/source/h264bsd_conceal.c | 2 +- .../on2/h264dec/source/h264bsd_reconstruct.c | 5 +- .../on2/h264dec/source/h264bsd_slice_header.c | 3 + .../codecs/on2/h264dec/source/h264bsd_util.c | 2 +- media/libstagefright/codecs/raw/Android.mk | 2 + media/libstagefright/codecs/raw/SoftRaw.cpp | 2 +- media/libstagefright/codecs/vorbis/dec/Android.mk | 2 + media/libstagefright/colorconversion/Android.mk | 2 + .../libstagefright/foundation/ANetworkSession.cpp | 2 +- media/libstagefright/foundation/Android.mk | 2 +- media/libstagefright/http/Android.mk | 2 + media/libstagefright/httplive/Android.mk | 2 + media/libstagefright/httplive/M3UParser.cpp | 6 +- media/libstagefright/httplive/PlaylistFetcher.cpp | 7 ++- media/libstagefright/id3/Android.mk | 4 ++ media/libstagefright/include/TimedEventQueue.h | 2 +- media/libstagefright/matroska/Android.mk | 2 +- .../libstagefright/matroska/MatroskaExtractor.cpp | 4 +- media/libstagefright/mp4/FragmentedMP4Parser.cpp | 30 ++++++---- media/libstagefright/mp4/TrackFragment.cpp | 25 ++++++-- media/libstagefright/mpeg2ts/ATSParser.cpp | 4 +- media/libstagefright/mpeg2ts/Android.mk | 2 + .../libstagefright/mpeg2ts/AnotherPacketSource.cpp | 2 +- media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp | 5 +- media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp | 2 +- media/libstagefright/omx/Android.mk | 2 + media/libstagefright/omx/GraphicBufferSource.cpp | 2 +- media/libstagefright/omx/OMX.cpp | 4 +- media/libstagefright/omx/OMXNodeInstance.cpp | 16 ++--- media/libstagefright/omx/SoftOMXComponent.cpp | 40 ++++++------- media/libstagefright/omx/SoftOMXPlugin.cpp | 2 +- media/libstagefright/omx/tests/Android.mk | 2 + media/libstagefright/rtsp/AMPEG2TSAssembler.cpp | 4 +- media/libstagefright/rtsp/ARTPWriter.cpp | 2 +- media/libstagefright/rtsp/ARawAudioAssembler.cpp | 4 +- media/libstagefright/rtsp/Android.mk | 2 + media/libstagefright/rtsp/MyHandler.h | 18 +++++- media/libstagefright/timedtext/Android.mk | 3 +- media/libstagefright/timedtext/TimedTextDriver.cpp | 1 + media/libstagefright/timedtext/TimedTextSource.h | 2 +- media/libstagefright/wifi-display/Android.mk | 2 + .../libstagefright/wifi-display/rtp/RTPSender.cpp | 5 +- .../wifi-display/source/WifiDisplaySource.cpp | 8 +-- media/libstagefright/yuv/Android.mk | 2 + 122 files changed, 446 insertions(+), 207 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp index b19e8bf..b37aee3 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.cpp +++ b/media/libmediaplayerservice/StagefrightPlayer.cpp @@ -189,7 +189,7 @@ status_t StagefrightPlayer::getParameter(int key, Parcel *reply) { } status_t StagefrightPlayer::getMetadata( - const media::Metadata::Filter& ids, Parcel *records) { + const media::Metadata::Filter& /* ids */, Parcel *records) { using media::Metadata; uint32_t flags = mPlayer->flags(); diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp index ac2aab8..cbedf5c 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp @@ -139,7 +139,7 @@ status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select) { // LiveSession::selectTrack returns BAD_VALUE when selecting the currently // selected track, or unselecting a non-selected track. In this case it's an // no-op so we return OK. - return (err == OK || err == BAD_VALUE) ? OK : err; + return (err == OK || err == BAD_VALUE) ? (status_t)OK : err; } status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 817395a..01e59c8 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1528,7 +1528,7 @@ void NuPlayer::Source::notifyPrepared(status_t err) { notify->post(); } -void NuPlayer::Source::onMessageReceived(const sp &msg) { +void NuPlayer::Source::onMessageReceived(const sp & /* msg */) { TRESPASS(); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 9ef8dbd..e4850f0 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -367,7 +367,7 @@ status_t NuPlayerDriver::reset() { return OK; } -status_t NuPlayerDriver::setLooping(int loop) { +status_t NuPlayerDriver::setLooping(int /* loop */) { return INVALID_OPERATION; } @@ -423,16 +423,17 @@ void NuPlayerDriver::setAudioSink(const sp &audioSink) { mPlayer->setAudioSink(audioSink); } -status_t NuPlayerDriver::setParameter(int key, const Parcel &request) { +status_t NuPlayerDriver::setParameter( + int /* key */, const Parcel & /* request */) { return INVALID_OPERATION; } -status_t NuPlayerDriver::getParameter(int key, Parcel *reply) { +status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) { return INVALID_OPERATION; } status_t NuPlayerDriver::getMetadata( - const media::Metadata::Filter& ids, Parcel *records) { + const media::Metadata::Filter& /* ids */, Parcel *records) { Mutex::Autolock autoLock(mLock); using media::Metadata; @@ -496,7 +497,8 @@ void NuPlayerDriver::notifyFrameStats( mNumFramesDropped = numFramesDropped; } -status_t NuPlayerDriver::dump(int fd, const Vector &args) const { +status_t NuPlayerDriver::dump( + int fd, const Vector & /* args */) const { Mutex::Autolock autoLock(mLock); FILE *out = fdopen(dup(fd), "w"); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index e50533a..11279fc 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -68,19 +68,19 @@ struct NuPlayer::Source : public AHandler { virtual status_t dequeueAccessUnit( bool audio, sp *accessUnit) = 0; - virtual status_t getDuration(int64_t *durationUs) { + virtual status_t getDuration(int64_t * /* durationUs */) { return INVALID_OPERATION; } - virtual status_t getTrackInfo(Parcel* reply) const { + virtual status_t getTrackInfo(Parcel* /* reply */) const { return INVALID_OPERATION; } - virtual status_t selectTrack(size_t trackIndex, bool select) { + virtual status_t selectTrack(size_t /* trackIndex */, bool /* select */) { return INVALID_OPERATION; } - virtual status_t seekTo(int64_t seekTimeUs) { + virtual status_t seekTo(int64_t /* seekTimeUs */) { return INVALID_OPERATION; } @@ -93,7 +93,7 @@ protected: virtual void onMessageReceived(const sp &msg); - virtual sp getFormatMeta(bool audio) { return NULL; } + virtual sp getFormatMeta(bool /* audio */) { return NULL; } sp dupNotify() const { return mNotify->dup(); } diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp index 4d1072f..196f6ee 100644 --- a/media/libstagefright/AACExtractor.cpp +++ b/media/libstagefright/AACExtractor.cpp @@ -219,7 +219,7 @@ sp AACExtractor::getTrack(size_t index) { return new AACSource(mDataSource, mMeta, mOffsetVector, mFrameDurationUs); } -sp AACExtractor::getTrackMetaData(size_t index, uint32_t flags) { +sp AACExtractor::getTrackMetaData(size_t index, uint32_t /* flags */) { if (mInitCheck != OK || index != 0) { return NULL; } @@ -252,7 +252,7 @@ AACSource::~AACSource() { } } -status_t AACSource::start(MetaData *params) { +status_t AACSource::start(MetaData * /* params */) { CHECK(!mStarted); if (mOffsetVector.empty()) { diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp index c9bcaba..deee8e7 100644 --- a/media/libstagefright/AACWriter.cpp +++ b/media/libstagefright/AACWriter.cpp @@ -111,7 +111,7 @@ status_t AACWriter::addSource(const sp &source) { return OK; } -status_t AACWriter::start(MetaData *params) { +status_t AACWriter::start(MetaData * /* params */) { if (mInitCheck != OK) { return mInitCheck; } diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index f2354b4..4a8c4c4 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -1171,7 +1171,7 @@ status_t ACodec::configureCodec( if (canDoAdaptivePlayback && msg->findInt32("max-width", &maxWidth) && msg->findInt32("max-height", &maxHeight)) { - ALOGV("[%s] prepareForAdaptivePlayback(%ldx%ld)", + ALOGV("[%s] prepareForAdaptivePlayback(%dx%d)", mComponentName.c_str(), maxWidth, maxHeight); err = mOMX->prepareForAdaptivePlayback( diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp index 03dcbf9..3f592ed 100644 --- a/media/libstagefright/AMRExtractor.cpp +++ b/media/libstagefright/AMRExtractor.cpp @@ -189,7 +189,7 @@ sp AMRExtractor::getTrack(size_t index) { mOffsetTable, mOffsetTableLength); } -sp AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) { +sp AMRExtractor::getTrackMetaData(size_t index, uint32_t /* flags */) { if (mInitCheck != OK || index != 0) { return NULL; } @@ -221,7 +221,7 @@ AMRSource::~AMRSource() { } } -status_t AMRSource::start(MetaData *params) { +status_t AMRSource::start(MetaData * /* params */) { CHECK(!mStarted); mOffset = mIsWide ? 9 : 6; @@ -258,7 +258,7 @@ status_t AMRSource::read( int64_t seekFrame = seekTimeUs / 20000ll; // 20ms per frame. mCurrentTimeUs = seekFrame * 20000ll; - int index = seekFrame / 50; + size_t index = seekFrame < 0 ? 0 : seekFrame / 50; if (index >= mOffsetTableLength) { index = mOffsetTableLength - 1; } diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp index 3fe247a..653ca36 100644 --- a/media/libstagefright/AMRWriter.cpp +++ b/media/libstagefright/AMRWriter.cpp @@ -105,7 +105,7 @@ status_t AMRWriter::addSource(const sp &source) { return OK; } -status_t AMRWriter::start(MetaData *params) { +status_t AMRWriter::start(MetaData * /* params */) { if (mInitCheck != OK) { return mInitCheck; } diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 63f9399..1ab3d82 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -111,7 +111,7 @@ LOCAL_SHARED_LIBRARIES += \ libstagefright_foundation \ libdl -LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Wno-multichar -Werror LOCAL_MODULE:= libstagefright diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index 05ee34e..8623100 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -410,7 +410,7 @@ status_t AudioPlayer::setPlaybackRatePermille(int32_t ratePermille) { // static size_t AudioPlayer::AudioSinkCallback( - MediaPlayerBase::AudioSink *audioSink, + MediaPlayerBase::AudioSink * /* audioSink */, void *buffer, size_t size, void *cookie, MediaPlayerBase::AudioSink::cb_event_t event) { AudioPlayer *me = (AudioPlayer *)cookie; diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index 6fdee6b..df7da0a 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -68,7 +68,7 @@ AudioSource::AudioSource( int frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount; // make sure that the AudioRecord total buffer size is large enough - int bufCount = 2; + size_t bufCount = 2; while ((bufCount * frameCount) < minFrameCount) { bufCount++; } @@ -208,7 +208,7 @@ void AudioSource::rampVolume( } status_t AudioSource::read( - MediaBuffer **out, const ReadOptions *options) { + MediaBuffer **out, const ReadOptions * /* options */) { Mutex::Autolock autoLock(mLock); *out = NULL; diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index f57ee25..e83ec62 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -86,7 +86,7 @@ struct AwesomeEvent : public TimedEventQueue::Event { protected: virtual ~AwesomeEvent() {} - virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) { + virtual void fire(TimedEventQueue * /* queue */, int64_t /* now_us */) { (mPlayer->*mMethod)(); } @@ -2813,7 +2813,8 @@ bool AwesomePlayer::isStreamingHTTP() const { return mCachedSource != NULL || mWVMExtractor != NULL; } -status_t AwesomePlayer::dump(int fd, const Vector &args) const { +status_t AwesomePlayer::dump( + int fd, const Vector & /* args */) const { Mutex::Autolock autoLock(mStatsLock); FILE *out = fdopen(dup(fd), "w"); diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index 3017fe7..f3ff792 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -31,6 +31,12 @@ #include #include +#if LOG_NDEBUG +#define UNUSED_UNLESS_VERBOSE(x) (void)(x) +#else +#define UNUSED_UNLESS_VERBOSE(x) +#endif + namespace android { static const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL; @@ -63,11 +69,14 @@ CameraSourceListener::~CameraSourceListener() { } void CameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) { + UNUSED_UNLESS_VERBOSE(msgType); + UNUSED_UNLESS_VERBOSE(ext1); + UNUSED_UNLESS_VERBOSE(ext2); ALOGV("notify(%d, %d, %d)", msgType, ext1, ext2); } void CameraSourceListener::postData(int32_t msgType, const sp &dataPtr, - camera_frame_metadata_t *metadata) { + camera_frame_metadata_t * /* metadata */) { ALOGV("postData(%d, ptr:%p, size:%d)", msgType, dataPtr->pointer(), dataPtr->size()); diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp index 86844b8..60cdf66 100644 --- a/media/libstagefright/CameraSourceTimeLapse.cpp +++ b/media/libstagefright/CameraSourceTimeLapse.cpp @@ -232,7 +232,7 @@ sp CameraSourceTimeLapse::createIMemoryCopy( return newMemory; } -bool CameraSourceTimeLapse::skipCurrentFrame(int64_t timestampUs) { +bool CameraSourceTimeLapse::skipCurrentFrame(int64_t /* timestampUs */) { ALOGV("skipCurrentFrame"); if (mSkipCurrentFrame) { mSkipCurrentFrame = false; diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp index 098fcf9..fa7251c 100644 --- a/media/libstagefright/FLACExtractor.cpp +++ b/media/libstagefright/FLACExtractor.cpp @@ -208,55 +208,55 @@ private: // with the same parameter list, but discard redundant information. FLAC__StreamDecoderReadStatus FLACParser::read_callback( - const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], + const FLAC__StreamDecoder * /* decoder */, FLAC__byte buffer[], size_t *bytes, void *client_data) { return ((FLACParser *) client_data)->readCallback(buffer, bytes); } FLAC__StreamDecoderSeekStatus FLACParser::seek_callback( - const FLAC__StreamDecoder *decoder, + const FLAC__StreamDecoder * /* decoder */, FLAC__uint64 absolute_byte_offset, void *client_data) { return ((FLACParser *) client_data)->seekCallback(absolute_byte_offset); } FLAC__StreamDecoderTellStatus FLACParser::tell_callback( - const FLAC__StreamDecoder *decoder, + const FLAC__StreamDecoder * /* decoder */, FLAC__uint64 *absolute_byte_offset, void *client_data) { return ((FLACParser *) client_data)->tellCallback(absolute_byte_offset); } FLAC__StreamDecoderLengthStatus FLACParser::length_callback( - const FLAC__StreamDecoder *decoder, + const FLAC__StreamDecoder * /* decoder */, FLAC__uint64 *stream_length, void *client_data) { return ((FLACParser *) client_data)->lengthCallback(stream_length); } FLAC__bool FLACParser::eof_callback( - const FLAC__StreamDecoder *decoder, void *client_data) + const FLAC__StreamDecoder * /* decoder */, void *client_data) { return ((FLACParser *) client_data)->eofCallback(); } FLAC__StreamDecoderWriteStatus FLACParser::write_callback( - const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, + const FLAC__StreamDecoder * /* decoder */, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) { return ((FLACParser *) client_data)->writeCallback(frame, buffer); } void FLACParser::metadata_callback( - const FLAC__StreamDecoder *decoder, + const FLAC__StreamDecoder * /* decoder */, const FLAC__StreamMetadata *metadata, void *client_data) { ((FLACParser *) client_data)->metadataCallback(metadata); } void FLACParser::error_callback( - const FLAC__StreamDecoder *decoder, + const FLAC__StreamDecoder * /* decoder */, FLAC__StreamDecoderErrorStatus status, void *client_data) { ((FLACParser *) client_data)->errorCallback(status); @@ -380,15 +380,21 @@ void FLACParser::errorCallback(FLAC__StreamDecoderErrorStatus status) // Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved. // These are candidates for optimization if needed. -static void copyMono8(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels) -{ +static void copyMono8( + short *dst, + const int *const *src, + unsigned nSamples, + unsigned /* nChannels */) { for (unsigned i = 0; i < nSamples; ++i) { *dst++ = src[0][i] << 8; } } -static void copyStereo8(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels) -{ +static void copyStereo8( + short *dst, + const int *const *src, + unsigned nSamples, + unsigned /* nChannels */) { for (unsigned i = 0; i < nSamples; ++i) { *dst++ = src[0][i] << 8; *dst++ = src[1][i] << 8; @@ -404,15 +410,21 @@ static void copyMultiCh8(short *dst, const int *const *src, unsigned nSamples, u } } -static void copyMono16(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels) -{ +static void copyMono16( + short *dst, + const int *const *src, + unsigned nSamples, + unsigned /* nChannels */) { for (unsigned i = 0; i < nSamples; ++i) { *dst++ = src[0][i]; } } -static void copyStereo16(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels) -{ +static void copyStereo16( + short *dst, + const int *const *src, + unsigned nSamples, + unsigned /* nChannels */) { for (unsigned i = 0; i < nSamples; ++i) { *dst++ = src[0][i]; *dst++ = src[1][i]; @@ -430,15 +442,21 @@ static void copyMultiCh16(short *dst, const int *const *src, unsigned nSamples, // 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger -static void copyMono24(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels) -{ +static void copyMono24( + short *dst, + const int *const *src, + unsigned nSamples, + unsigned /* nChannels */) { for (unsigned i = 0; i < nSamples; ++i) { *dst++ = src[0][i] >> 8; } } -static void copyStereo24(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels) -{ +static void copyStereo24( + short *dst, + const int *const *src, + unsigned nSamples, + unsigned /* nChannels */) { for (unsigned i = 0; i < nSamples; ++i) { *dst++ = src[0][i] >> 8; *dst++ = src[1][i] >> 8; @@ -454,8 +472,11 @@ static void copyMultiCh24(short *dst, const int *const *src, unsigned nSamples, } } -static void copyTrespass(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels) -{ +static void copyTrespass( + short * /* dst */, + const int *const * /* src */, + unsigned /* nSamples */, + unsigned /* nChannels */) { TRESPASS(); } @@ -700,7 +721,7 @@ FLACSource::~FLACSource() } } -status_t FLACSource::start(MetaData *params) +status_t FLACSource::start(MetaData * /* params */) { ALOGV("FLACSource::start"); @@ -792,8 +813,7 @@ sp FLACExtractor::getTrack(size_t index) } sp FLACExtractor::getTrackMetaData( - size_t index, uint32_t flags) -{ + size_t index, uint32_t /* flags */) { if (mInitCheck != OK || index > 0) { return NULL; } diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp index 380dab4..4a63152 100644 --- a/media/libstagefright/MP3Extractor.cpp +++ b/media/libstagefright/MP3Extractor.cpp @@ -398,7 +398,8 @@ sp MP3Extractor::getTrack(size_t index) { mSeeker); } -sp MP3Extractor::getTrackMetaData(size_t index, uint32_t flags) { +sp MP3Extractor::getTrackMetaData( + size_t index, uint32_t /* flags */) { if (mInitCheck != OK || index != 0) { return NULL; } diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp index c9ed5bb..78c12e1 100644 --- a/media/libstagefright/MPEG2TSWriter.cpp +++ b/media/libstagefright/MPEG2TSWriter.cpp @@ -555,7 +555,7 @@ status_t MPEG2TSWriter::addSource(const sp &source) { return OK; } -status_t MPEG2TSWriter::start(MetaData *param) { +status_t MPEG2TSWriter::start(MetaData * /* param */) { CHECK(!mStarted); mStarted = true; @@ -596,7 +596,8 @@ bool MPEG2TSWriter::reachedEOS() { return !mStarted || (mNumSourcesDone == mSources.size() ? true : false); } -status_t MPEG2TSWriter::dump(int fd, const Vector &args) { +status_t MPEG2TSWriter::dump( + int /* fd */, const Vector & /* args */) { return OK; } diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index e6312c1..570d417 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -571,7 +571,8 @@ static int32_t readSize(off64_t offset, return size; } -status_t MPEG4Extractor::parseDrmSINF(off64_t *offset, off64_t data_offset) { +status_t MPEG4Extractor::parseDrmSINF( + off64_t * /* offset */, off64_t data_offset) { uint8_t updateIdTag; if (mDataSource->readAt(data_offset, &updateIdTag, 1) < 1) { return ERROR_IO; @@ -2959,7 +2960,8 @@ status_t MPEG4Source::parseChunk(off64_t *offset) { return OK; } -status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(off64_t offset, off64_t size) { +status_t MPEG4Source::parseSampleAuxiliaryInformationSizes( + off64_t offset, off64_t /* size */) { ALOGV("parseSampleAuxiliaryInformationSizes"); // 14496-12 8.7.12 uint8_t version; @@ -3021,7 +3023,8 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(off64_t offset, off64 return OK; } -status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size) { +status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets( + off64_t offset, off64_t /* size */) { ALOGV("parseSampleAuxiliaryInformationOffsets"); // 14496-12 8.7.13 uint8_t version; diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index ff6feb9..2e8d6b3 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -407,7 +407,7 @@ status_t MPEG4Writer::dump( } status_t MPEG4Writer::Track::dump( - int fd, const Vector& args) const { + int fd, const Vector& /* args */) const { const size_t SIZE = 256; char buffer[SIZE]; String8 result; diff --git a/media/libstagefright/MediaAdapter.cpp b/media/libstagefright/MediaAdapter.cpp index 2484212..d680e0c 100644 --- a/media/libstagefright/MediaAdapter.cpp +++ b/media/libstagefright/MediaAdapter.cpp @@ -36,7 +36,7 @@ MediaAdapter::~MediaAdapter() { CHECK(mCurrentMediaBuffer == NULL); } -status_t MediaAdapter::start(MetaData *params) { +status_t MediaAdapter::start(MetaData * /* params */) { Mutex::Autolock autoLock(mAdapterLock); if (!mStarted) { mStarted = true; @@ -75,7 +75,7 @@ void MediaAdapter::signalBufferReturned(MediaBuffer *buffer) { } status_t MediaAdapter::read( - MediaBuffer **buffer, const ReadOptions *options) { + MediaBuffer **buffer, const ReadOptions * /* options */) { Mutex::Autolock autoLock(mAdapterLock); if (!mStarted) { ALOGV("Read before even started!"); diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index c4c47b3..fe21296 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -115,7 +115,7 @@ status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) { if (codecIdx >= 0) { Vector types; if (mcl->getSupportedTypes(codecIdx, &types) == OK) { - for (int i = 0; i < types.size(); i++) { + for (size_t i = 0; i < types.size(); i++) { if (types[i].startsWith("video/")) { needDedicatedLooper = true; break; diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index 2c20d62..924173c 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -293,8 +293,8 @@ sp MediaCodecSource::getGraphicBufferProducer() { return mGraphicBufferProducer; } -status_t MediaCodecSource::read(MediaBuffer** buffer, - const ReadOptions* options) { +status_t MediaCodecSource::read( + MediaBuffer** buffer, const ReadOptions* /* options */) { Mutex::Autolock autolock(mOutputBufferLock); *buffer = NULL; diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index 1287fb1..72ea32d 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -333,7 +333,7 @@ void NuCachedSource2::fetchInternal() { mNumRetriesLeft = 0; } - ALOGE("source returned error %ld, %d retries left", n, mNumRetriesLeft); + ALOGE("source returned error %d, %d retries left", n, mNumRetriesLeft); mCache->releasePage(page); } else if (n == 0) { ALOGI("ERROR_END_OF_STREAM"); @@ -648,7 +648,7 @@ void NuCachedSource2::updateCacheParamsFromString(const char *s) { ssize_t lowwaterMarkKb, highwaterMarkKb; int keepAliveSecs; - if (sscanf(s, "%ld/%ld/%d", + if (sscanf(s, "%d/%d/%d", &lowwaterMarkKb, &highwaterMarkKb, &keepAliveSecs) != 3) { ALOGE("Failed to parse cache parameters from '%s'.", s); return; diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp index 5e79e78..f3eeb03 100644 --- a/media/libstagefright/OggExtractor.cpp +++ b/media/libstagefright/OggExtractor.cpp @@ -151,7 +151,7 @@ sp OggSource::getFormat() { return mExtractor->mImpl->getFormat(); } -status_t OggSource::start(MetaData *params) { +status_t OggSource::start(MetaData * /* params */) { if (mStarted) { return INVALID_OPERATION; } @@ -381,7 +381,7 @@ ssize_t MyVorbisExtractor::readPage(off64_t offset, Page *page) { ssize_t n; if ((n = mSource->readAt(offset, header, sizeof(header))) < (ssize_t)sizeof(header)) { - ALOGV("failed to read %d bytes at offset 0x%016llx, got %ld bytes", + ALOGV("failed to read %zu bytes at offset 0x%016llx, got %d bytes", sizeof(header), offset, n); if (n < 0) { @@ -505,7 +505,7 @@ status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) { packetSize); if (n < (ssize_t)packetSize) { - ALOGV("failed to read %d bytes at 0x%016llx, got %ld bytes", + ALOGV("failed to read %zu bytes at 0x%016llx, got %d bytes", packetSize, dataOffset, n); return ERROR_IO; } @@ -546,7 +546,7 @@ status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) { buffer = NULL; } - ALOGV("readPage returned %ld", n); + ALOGV("readPage returned %d", n); return n < 0 ? n : (status_t)ERROR_END_OF_STREAM; } @@ -998,7 +998,7 @@ sp OggExtractor::getTrack(size_t index) { } sp OggExtractor::getTrackMetaData( - size_t index, uint32_t flags) { + size_t index, uint32_t /* flags */) { if (index >= 1) { return NULL; } diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp index edd12fc..fe20835 100644 --- a/media/libstagefright/StagefrightMediaScanner.cpp +++ b/media/libstagefright/StagefrightMediaScanner.cpp @@ -118,7 +118,7 @@ MediaScanResult StagefrightMediaScanner::processFile( } MediaScanResult StagefrightMediaScanner::processFileInternal( - const char *path, const char *mimeType, + const char *path, const char * /* mimeType */, MediaScannerClient &client) { const char *extension = strrchr(path, '.'); diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index 6b934d4..686d03a 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -99,8 +99,11 @@ void SurfaceMediaSource::dump(String8& result) const dump(result, "", buffer, 1024); } -void SurfaceMediaSource::dump(String8& result, const char* prefix, - char* buffer, size_t SIZE) const +void SurfaceMediaSource::dump( + String8& result, + const char* /* prefix */, + char* buffer, + size_t /* SIZE */) const { Mutex::Autolock lock(mMutex); @@ -269,9 +272,8 @@ static void passMetadataBuffer(MediaBuffer **buffer, bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset()); } -status_t SurfaceMediaSource::read( MediaBuffer **buffer, - const ReadOptions *options) -{ +status_t SurfaceMediaSource::read( + MediaBuffer **buffer, const ReadOptions * /* options */) { ALOGV("read"); Mutex::Autolock lock(mMutex); diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp index 0afac69..3d2eb1f 100644 --- a/media/libstagefright/TimedEventQueue.cpp +++ b/media/libstagefright/TimedEventQueue.cpp @@ -376,8 +376,8 @@ void TimedEventQueue::clearPowerManager() mPowerManager.clear(); } -void TimedEventQueue::PMDeathRecipient::binderDied(const wp& who) -{ +void TimedEventQueue::PMDeathRecipient::binderDied( + const wp& /* who */) { mQueue->clearPowerManager(); } diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp index a245f2c..af858b9 100644 --- a/media/libstagefright/VBRISeeker.cpp +++ b/media/libstagefright/VBRISeeker.cpp @@ -119,7 +119,7 @@ sp VBRISeeker::CreateFromSource( seeker->mSegments.push(numBytes); - ALOGV("entry #%d: %d offset 0x%08lx", i, numBytes, offset); + ALOGV("entry #%d: %u offset 0x%016llx", i, numBytes, offset); offset += numBytes; } @@ -160,7 +160,7 @@ bool VBRISeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) { *pos += mSegments.itemAt(segmentIndex++); } - ALOGV("getOffsetForTime %lld us => 0x%08lx", *timeUs, *pos); + ALOGV("getOffsetForTime %lld us => 0x%016llx", *timeUs, *pos); *timeUs = nowUs; diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp index 22af6fb..fe9058b 100644 --- a/media/libstagefright/WAVExtractor.cpp +++ b/media/libstagefright/WAVExtractor.cpp @@ -127,7 +127,7 @@ sp WAVExtractor::getTrack(size_t index) { } sp WAVExtractor::getTrackMetaData( - size_t index, uint32_t flags) { + size_t index, uint32_t /* flags */) { if (mInitCheck != OK || index > 0) { return NULL; } @@ -358,7 +358,7 @@ WAVSource::~WAVSource() { } } -status_t WAVSource::start(MetaData *params) { +status_t WAVSource::start(MetaData * /* params */) { ALOGV("WAVSource::start"); CHECK(!mStarted); diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp index b822868..c6ac0da 100644 --- a/media/libstagefright/avc_utils.cpp +++ b/media/libstagefright/avc_utils.cpp @@ -251,9 +251,7 @@ status_t getNextNALUnit( return OK; } -static sp FindNAL( - const uint8_t *data, size_t size, unsigned nalType, - size_t *stopOffset) { +static sp FindNAL(const uint8_t *data, size_t size, unsigned nalType) { const uint8_t *nalStart; size_t nalSize; while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) { @@ -293,7 +291,7 @@ sp MakeAVCCodecSpecificData(const sp &accessUnit) { const uint8_t *data = accessUnit->data(); size_t size = accessUnit->size(); - sp seqParamSet = FindNAL(data, size, 7, NULL); + sp seqParamSet = FindNAL(data, size, 7); if (seqParamSet == NULL) { return NULL; } @@ -303,8 +301,7 @@ sp MakeAVCCodecSpecificData(const sp &accessUnit) { FindAVCDimensions( seqParamSet, &width, &height, &sarWidth, &sarHeight); - size_t stopOffset; - sp picParamSet = FindNAL(data, size, 8, &stopOffset); + sp picParamSet = FindNAL(data, size, 8); CHECK(picParamSet != NULL); size_t csdSize = diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk index ffa64f9..49ff238 100644 --- a/media/libstagefright/codecs/aacdec/Android.mk +++ b/media/libstagefright/codecs/aacdec/Android.mk @@ -17,6 +17,8 @@ LOCAL_C_INCLUDES := \ LOCAL_CFLAGS := +LOCAL_CFLAGS += -Werror + LOCAL_STATIC_LIBRARIES := libFraunhoferAAC LOCAL_SHARED_LIBRARIES := \ diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk index 057c69b..58ec3ba 100644 --- a/media/libstagefright/codecs/aacenc/Android.mk +++ b/media/libstagefright/codecs/aacenc/Android.mk @@ -82,6 +82,8 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV7 endif +LOCAL_CFLAGS += -Werror + include $(BUILD_STATIC_LIBRARY) ################################################################################ @@ -106,6 +108,8 @@ ifeq ($(AAC_LIBRARY), fraunhofer) LOCAL_CFLAGS := + LOCAL_CFLAGS += -Werror + LOCAL_STATIC_LIBRARIES := libFraunhoferAAC LOCAL_SHARED_LIBRARIES := \ @@ -128,6 +132,8 @@ else # visualon LOCAL_CFLAGS := -DOSCL_IMPORT_REF= + LOCAL_CFLAGS += -Werror + LOCAL_STATIC_LIBRARIES := \ libstagefright_aacenc diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp index ff2b503..9a91579 100644 --- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp +++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp @@ -338,7 +338,7 @@ status_t SoftAACEncoder2::setAudioParams() { return OK; } -void SoftAACEncoder2::onQueueFilled(OMX_U32 portIndex) { +void SoftAACEncoder2::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError) { return; } diff --git a/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c b/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c index cc01927..1d029fc 100644 --- a/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c +++ b/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c @@ -24,6 +24,8 @@ #include "basic_op.h" #include "oper_32b.h" +#define UNUSED(x) (void)(x) + /***************************************************************************** * * * Function L_Extract() * @@ -243,6 +245,8 @@ Word16 iLog4(Word32 value) Word32 rsqrt(Word32 value, /*!< Operand to square root (0.0 ... 1) */ Word32 accuracy) /*!< Number of valid bits that will be calculated */ { + UNUSED(accuracy); + Word32 root = 0; Word32 scale; diff --git a/media/libstagefright/codecs/aacenc/src/aacenc.c b/media/libstagefright/codecs/aacenc/src/aacenc.c index d1c8621..40db92c 100644 --- a/media/libstagefright/codecs/aacenc/src/aacenc.c +++ b/media/libstagefright/codecs/aacenc/src/aacenc.c @@ -27,6 +27,8 @@ #include "cmnMemory.h" #include "memalign.h" +#define UNUSED(x) (void)(x) + /** * Init the audio codec module and return codec handle * \param phCodec [OUT] Return the video codec handle @@ -46,6 +48,8 @@ VO_U32 VO_API voAACEncInit(VO_HANDLE * phCodec,VO_AUDIO_CODINGTYPE vType, VO_COD VO_MEM_OPERATOR *pMemOP; int interMem; + UNUSED(vType); + interMem = 0; error = 0; @@ -471,6 +475,10 @@ VO_U32 VO_API voAACEncSetParam(VO_HANDLE hCodec, VO_S32 uParamID, VO_PTR pData) */ VO_U32 VO_API voAACEncGetParam(VO_HANDLE hCodec, VO_S32 uParamID, VO_PTR pData) { + UNUSED(hCodec); + UNUSED(uParamID); + UNUSED(pData); + return VO_ERR_NONE; } diff --git a/media/libstagefright/codecs/aacenc/src/adj_thr.c b/media/libstagefright/codecs/aacenc/src/adj_thr.c index ccfe883..471631c 100644 --- a/media/libstagefright/codecs/aacenc/src/adj_thr.c +++ b/media/libstagefright/codecs/aacenc/src/adj_thr.c @@ -72,7 +72,7 @@ static void calcThreshExp(Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB], const Word16 nChannels) { Word16 ch, sfb, sfbGrp; - Word32 *pthrExp, *psfbThre; + Word32 *pthrExp = NULL, *psfbThre; for (ch=0; chsfbCnt; sfbGrp+= psyOutChan->sfbPerGroup) diff --git a/media/libstagefright/codecs/aacenc/src/bitenc.c b/media/libstagefright/codecs/aacenc/src/bitenc.c index fcc12dd..d1fd647 100644 --- a/media/libstagefright/codecs/aacenc/src/bitenc.c +++ b/media/libstagefright/codecs/aacenc/src/bitenc.c @@ -26,6 +26,7 @@ #include "qc_data.h" #include "interface.h" +#define UNUSED(x) (void)(x) static const Word16 globalGainOffset = 100; static const Word16 icsReservedBit = 0; @@ -585,6 +586,8 @@ Word16 WriteBitstream (HANDLE_BIT_BUF hBitStream, Word16 elementUsedBits; Word16 frameBits=0; + UNUSED(ancBytes); + /* struct bitbuffer bsWriteCopy; */ bitMarkUp = GetBitsAvail(hBitStream); if(qcOut->qcElement.adtsUsed) /* write adts header*/ diff --git a/media/libstagefright/codecs/aacenc/src/dyn_bits.c b/media/libstagefright/codecs/aacenc/src/dyn_bits.c index 7769188..4d763d0 100644 --- a/media/libstagefright/codecs/aacenc/src/dyn_bits.c +++ b/media/libstagefright/codecs/aacenc/src/dyn_bits.c @@ -25,7 +25,6 @@ #include "bit_cnt.h" #include "psy_const.h" - /***************************************************************************** * * function name: buildBitLookUp @@ -226,7 +225,7 @@ gmStage2(SECTION_INFO *sectionInfo, } while (TRUE) { - Word16 maxMergeGain, maxNdx, maxNdxNext, maxNdxLast; + Word16 maxMergeGain, maxNdx = 0, maxNdxNext, maxNdxLast; maxMergeGain = findMaxMerge(mergeGainLookUp, sectionInfo, maxSfb, &maxNdx); diff --git a/media/libstagefright/codecs/aacenc/src/psy_main.c b/media/libstagefright/codecs/aacenc/src/psy_main.c index 4e9218c..6f0679c 100644 --- a/media/libstagefright/codecs/aacenc/src/psy_main.c +++ b/media/libstagefright/codecs/aacenc/src/psy_main.c @@ -38,6 +38,8 @@ #include "tns_func.h" #include "memalign.h" +#define UNUSED(x) (void)(x) + /* long start short stop */ static Word16 blockType2windowShape[] = {KBD_WINDOW,SINE_WINDOW,SINE_WINDOW,KBD_WINDOW}; @@ -170,7 +172,9 @@ Word16 PsyOutNew(PSY_OUT *hPsyOut, VO_MEM_OPERATOR *pMemOP) *****************************************************************************/ Word16 PsyOutDelete(PSY_OUT *hPsyOut, VO_MEM_OPERATOR *pMemOP) { - hPsyOut=NULL; + UNUSED(hPsyOut); + UNUSED(pMemOP); + return 0; } diff --git a/media/libstagefright/codecs/aacenc/src/qc_main.c b/media/libstagefright/codecs/aacenc/src/qc_main.c index 48ff300..e5d78aa 100644 --- a/media/libstagefright/codecs/aacenc/src/qc_main.c +++ b/media/libstagefright/codecs/aacenc/src/qc_main.c @@ -33,6 +33,7 @@ #include "channel_map.h" #include "memalign.h" +#define UNUSED(x) (void)(x) typedef enum{ FRAME_LEN_BYTES_MODULO = 1, @@ -204,11 +205,8 @@ Word16 QCNew(QC_STATE *hQC, VO_MEM_OPERATOR *pMemOP) **********************************************************************************/ void QCDelete(QC_STATE *hQC, VO_MEM_OPERATOR *pMemOP) { - - /* - nothing to do - */ - hQC=NULL; + UNUSED(hQC); + UNUSED(pMemOP); } /********************************************************************************* diff --git a/media/libstagefright/codecs/aacenc/src/tns.c b/media/libstagefright/codecs/aacenc/src/tns.c index 455a864..5172612 100644 --- a/media/libstagefright/codecs/aacenc/src/tns.c +++ b/media/libstagefright/codecs/aacenc/src/tns.c @@ -30,6 +30,8 @@ #include "psy_configuration.h" #include "tns_func.h" +#define UNUSED(x) (void)(x) + #define TNS_MODIFY_BEGIN 2600 /* Hz */ #define RATIO_PATCH_LOWER_BORDER 380 /* Hz */ #define TNS_GAIN_THRESH 141 /* 1.41*100 */ @@ -643,6 +645,8 @@ static Word16 CalcTnsFilter(const Word16 *signal, Word32 i; Word32 tnsOrderPlus1 = tnsOrder + 1; + UNUSED(window); + assert(tnsOrder <= TNS_MAX_ORDER); /* remove asserts later? (btg) */ for(i=0;i &inQueue = getPortQueue(0); List &outQueue = getPortQueue(1); @@ -428,7 +428,7 @@ void SoftAMR::onQueueFilled(OMX_U32 portIndex) { } } -void SoftAMR::onPortFlushCompleted(OMX_U32 portIndex) { +void SoftAMR::onPortFlushCompleted(OMX_U32 /* portIndex */) { } void SoftAMR::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk index f4e467a..afc0b89 100644 --- a/media/libstagefright/codecs/amrnb/enc/Android.mk +++ b/media/libstagefright/codecs/amrnb/enc/Android.mk @@ -69,6 +69,8 @@ LOCAL_C_INCLUDES := \ LOCAL_CFLAGS := \ -DOSCL_UNUSED_ARG= +LOCAL_CFLAGS += -Werror + LOCAL_MODULE := libstagefright_amrnbenc include $(BUILD_STATIC_LIBRARY) @@ -88,6 +90,8 @@ LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/../common/include \ $(LOCAL_PATH)/../common +LOCAL_CFLAGS += -Werror + LOCAL_STATIC_LIBRARIES := \ libstagefright_amrnbenc diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp index 50b739c..9489457 100644 --- a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp +++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp @@ -270,7 +270,7 @@ OMX_ERRORTYPE SoftAMRNBEncoder::internalSetParameter( } } -void SoftAMRNBEncoder::onQueueFilled(OMX_U32 portIndex) { +void SoftAMRNBEncoder::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError) { return; } diff --git a/media/libstagefright/codecs/amrwb/Android.mk b/media/libstagefright/codecs/amrwb/Android.mk index 677107f..efdf988 100644 --- a/media/libstagefright/codecs/amrwb/Android.mk +++ b/media/libstagefright/codecs/amrwb/Android.mk @@ -50,6 +50,8 @@ LOCAL_C_INCLUDES := \ LOCAL_CFLAGS := \ -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF= +LOCAL_CFLAGS += -Werror + LOCAL_MODULE := libstagefright_amrwbdec include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk index c5b8e0c..64fe8d1 100644 --- a/media/libstagefright/codecs/amrwbenc/Android.mk +++ b/media/libstagefright/codecs/amrwbenc/Android.mk @@ -112,6 +112,8 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV7 endif +LOCAL_CFLAGS += -Werror + include $(BUILD_STATIC_LIBRARY) ################################################################################ @@ -126,6 +128,8 @@ LOCAL_C_INCLUDES := \ frameworks/av/media/libstagefright/codecs/common/include \ frameworks/native/include/media/openmax +LOCAL_CFLAGS += -Werror + LOCAL_STATIC_LIBRARIES := \ libstagefright_amrwbenc diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp index 9ccb49c..91a512d 100644 --- a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp +++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp @@ -317,7 +317,7 @@ OMX_ERRORTYPE SoftAMRWBEncoder::internalSetParameter( } } -void SoftAMRWBEncoder::onQueueFilled(OMX_U32 portIndex) { +void SoftAMRWBEncoder::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError) { return; } diff --git a/media/libstagefright/codecs/amrwbenc/src/autocorr.c b/media/libstagefright/codecs/amrwbenc/src/autocorr.c index 8c477ca..0b2ea89 100644 --- a/media/libstagefright/codecs/amrwbenc/src/autocorr.c +++ b/media/libstagefright/codecs/amrwbenc/src/autocorr.c @@ -28,6 +28,8 @@ #include "acelp.h" #include "ham_wind.tab" +#define UNUSED(x) (void)(x) + void Autocorr( Word16 x[], /* (i) : Input signal */ Word16 m, /* (i) : LPC order */ @@ -40,6 +42,8 @@ void Autocorr( Word32 L_sum, L_sum1, L_tmp, F_LEN; Word16 *p1,*p2,*p3; const Word16 *p4; + UNUSED(m); + /* Windowing of signal */ p1 = x; p4 = vo_window; diff --git a/media/libstagefright/codecs/amrwbenc/src/convolve.c b/media/libstagefright/codecs/amrwbenc/src/convolve.c index acba532..4c1f7d4 100644 --- a/media/libstagefright/codecs/amrwbenc/src/convolve.c +++ b/media/libstagefright/codecs/amrwbenc/src/convolve.c @@ -25,6 +25,8 @@ #include "typedef.h" #include "basic_op.h" +#define UNUSED(x) (void)(x) + void Convolve ( Word16 x[], /* (i) : input vector */ Word16 h[], /* (i) : impulse response */ @@ -35,6 +37,8 @@ void Convolve ( Word32 i, n; Word16 *tmpH,*tmpX; Word32 s; + UNUSED(L); + for (n = 0; n < 64;) { tmpH = h+n; diff --git a/media/libstagefright/codecs/amrwbenc/src/syn_filt.c b/media/libstagefright/codecs/amrwbenc/src/syn_filt.c index 1bda05a..961aadc 100644 --- a/media/libstagefright/codecs/amrwbenc/src/syn_filt.c +++ b/media/libstagefright/codecs/amrwbenc/src/syn_filt.c @@ -26,6 +26,8 @@ #include "math_op.h" #include "cnst.h" +#define UNUSED(x) (void)(x) + void Syn_filt( Word16 a[], /* (i) Q12 : a[m+1] prediction coefficients */ Word16 x[], /* (i) : input signal */ @@ -95,6 +97,8 @@ void Syn_filt_32( Word32 i,a0; Word32 L_tmp, L_tmp1; Word16 *p1, *p2, *p3; + UNUSED(m); + a0 = a[0] >> (4 + Qnew); /* input / 16 and >>Qnew */ /* Do the filtering. */ for (i = 0; i < lg; i++) diff --git a/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c b/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c index ea9da52..df7b9b3 100644 --- a/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c +++ b/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c @@ -39,6 +39,8 @@ #include "mem_align.h" #include "cmnMemory.h" +#define UNUSED(x) (void)(x) + #ifdef __cplusplus extern "C" { #endif @@ -1602,6 +1604,8 @@ VO_U32 VO_API voAMRWB_Init(VO_HANDLE * phCodec, /* o: the audi VO_MEM_OPERATOR voMemoprator; #endif VO_MEM_OPERATOR *pMemOP; + UNUSED(vType); + int interMem = 0; if(pUserData == NULL || pUserData->memflag != VO_IMF_USERMEMOPERATOR || pUserData->memData == NULL ) diff --git a/media/libstagefright/codecs/avc/common/Android.mk b/media/libstagefright/codecs/avc/common/Android.mk index 22dee15..844ef0a 100644 --- a/media/libstagefright/codecs/avc/common/Android.mk +++ b/media/libstagefright/codecs/avc/common/Android.mk @@ -16,4 +16,6 @@ LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/src \ $(LOCAL_PATH)/include +LOCAL_CFLAGS += -Werror + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk index 7d17c2a..537ba42 100644 --- a/media/libstagefright/codecs/avc/enc/Android.mk +++ b/media/libstagefright/codecs/avc/enc/Android.mk @@ -30,6 +30,8 @@ LOCAL_C_INCLUDES := \ LOCAL_CFLAGS := \ -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF= +LOCAL_CFLAGS += -Werror + include $(BUILD_STATIC_LIBRARY) ################################################################################ @@ -69,4 +71,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE := libstagefright_soft_h264enc LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS += -Werror + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp index 1d398fb..1104e54 100644 --- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp +++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp @@ -34,6 +34,12 @@ #include "SoftAVCEncoder.h" +#if LOG_NDEBUG +#define UNUSED_UNLESS_VERBOSE(x) (void)(x) +#else +#define UNUSED_UNLESS_VERBOSE(x) +#endif + namespace android { template @@ -136,14 +142,14 @@ inline static void ConvertYUV420SemiPlanarToYUV420Planar( } static void* MallocWrapper( - void *userData, int32_t size, int32_t attrs) { + void * /* userData */, int32_t size, int32_t /* attrs */) { void *ptr = malloc(size); if (ptr) memset(ptr, 0, size); return ptr; } -static void FreeWrapper(void *userData, void* ptr) { +static void FreeWrapper(void * /* userData */, void* ptr) { free(ptr); } @@ -217,7 +223,7 @@ OMX_ERRORTYPE SoftAVCEncoder::initEncParams() { mHandle->CBAVC_Free = FreeWrapper; CHECK(mEncParams != NULL); - memset(mEncParams, 0, sizeof(mEncParams)); + memset(mEncParams, 0, sizeof(*mEncParams)); mEncParams->rate_control = AVC_ON; mEncParams->initQP = 0; mEncParams->init_CBP_removal_delay = 1600; @@ -722,7 +728,7 @@ OMX_ERRORTYPE SoftAVCEncoder::internalSetParameter( } } -void SoftAVCEncoder::onQueueFilled(OMX_U32 portIndex) { +void SoftAVCEncoder::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError || mSawInputEOS) { return; } @@ -964,6 +970,7 @@ int32_t SoftAVCEncoder::bindOutputBuffer(int32_t index, uint8_t **yuv) { } void SoftAVCEncoder::signalBufferReturned(MediaBuffer *buffer) { + UNUSED_UNLESS_VERBOSE(buffer); ALOGV("signalBufferReturned: %p", buffer); } diff --git a/media/libstagefright/codecs/common/Android.mk b/media/libstagefright/codecs/common/Android.mk index a33cb92..b0010ff 100644 --- a/media/libstagefright/codecs/common/Android.mk +++ b/media/libstagefright/codecs/common/Android.mk @@ -14,6 +14,8 @@ LOCAL_STATIC_LIBRARIES := LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include +LOCAL_CFLAGS += -Werror + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/common/cmnMemory.c b/media/libstagefright/codecs/common/cmnMemory.c index aa52bd9..5bb6cc4 100644 --- a/media/libstagefright/codecs/common/cmnMemory.c +++ b/media/libstagefright/codecs/common/cmnMemory.c @@ -26,8 +26,12 @@ //VO_MEM_OPERATOR g_memOP; +#define UNUSED(x) (void)(x) + VO_U32 cmnMemAlloc (VO_S32 uID, VO_MEM_INFO * pMemInfo) { + UNUSED(uID); + if (!pMemInfo) return VO_ERR_INVALID_ARG; @@ -37,34 +41,48 @@ VO_U32 cmnMemAlloc (VO_S32 uID, VO_MEM_INFO * pMemInfo) VO_U32 cmnMemFree (VO_S32 uID, VO_PTR pMem) { + UNUSED(uID); + free (pMem); return 0; } VO_U32 cmnMemSet (VO_S32 uID, VO_PTR pBuff, VO_U8 uValue, VO_U32 uSize) { + UNUSED(uID); + memset (pBuff, uValue, uSize); return 0; } VO_U32 cmnMemCopy (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize) { + UNUSED(uID); + memcpy (pDest, pSource, uSize); return 0; } VO_U32 cmnMemCheck (VO_S32 uID, VO_PTR pBuffer, VO_U32 uSize) { + UNUSED(uID); + UNUSED(pBuffer); + UNUSED(uSize); + return 0; } VO_S32 cmnMemCompare (VO_S32 uID, VO_PTR pBuffer1, VO_PTR pBuffer2, VO_U32 uSize) { + UNUSED(uID); + return memcmp(pBuffer1, pBuffer2, uSize); } VO_U32 cmnMemMove (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize) { + UNUSED(uID); + memmove (pDest, pSource, uSize); return 0; } diff --git a/media/libstagefright/codecs/flac/enc/Android.mk b/media/libstagefright/codecs/flac/enc/Android.mk index f01d605..59a11de 100644 --- a/media/libstagefright/codecs/flac/enc/Android.mk +++ b/media/libstagefright/codecs/flac/enc/Android.mk @@ -9,6 +9,8 @@ LOCAL_C_INCLUDES := \ frameworks/native/include/media/openmax \ external/flac/include +LOCAL_CFLAGS += -Werror + LOCAL_SHARED_LIBRARIES := \ libstagefright libstagefright_omx libstagefright_foundation libutils liblog diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp index e64fe72..40661e7 100644 --- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp +++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp @@ -27,6 +27,12 @@ #define FLAC_COMPRESSION_LEVEL_DEFAULT 5 #define FLAC_COMPRESSION_LEVEL_MAX 8 +#if LOG_NDEBUG +#define UNUSED_UNLESS_VERBOSE(x) (void)(x) +#else +#define UNUSED_UNLESS_VERBOSE(x) +#endif + namespace android { template @@ -257,7 +263,7 @@ OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter( } void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) { - + UNUSED_UNLESS_VERBOSE(portIndex); ALOGV("SoftFlacEncoder::onQueueFilled(portIndex=%ld)", portIndex); if (mSignalledError) { @@ -343,10 +349,11 @@ void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) { } } - FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable( const FLAC__byte buffer[], - size_t bytes, unsigned samples, unsigned current_frame) { + size_t bytes, unsigned samples, + unsigned current_frame) { + UNUSED_UNLESS_VERBOSE(current_frame); ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%d, samples=%d, curr_frame=%d)", bytes, samples, current_frame); @@ -444,8 +451,12 @@ return_result: // static FLAC__StreamEncoderWriteStatus SoftFlacEncoder::flacEncoderWriteCallback( - const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], - size_t bytes, unsigned samples, unsigned current_frame, void *client_data) { + const FLAC__StreamEncoder * /* encoder */, + const FLAC__byte buffer[], + size_t bytes, + unsigned samples, + unsigned current_frame, + void *client_data) { return ((SoftFlacEncoder*) client_data)->onEncodedFlacAvailable( buffer, bytes, samples, current_frame); } diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk index 4c80da6..a0112e1 100644 --- a/media/libstagefright/codecs/g711/dec/Android.mk +++ b/media/libstagefright/codecs/g711/dec/Android.mk @@ -14,4 +14,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE := libstagefright_soft_g711dec LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS += -Werror + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp index bcdd3c7..160ada0 100644 --- a/media/libstagefright/codecs/g711/dec/SoftG711.cpp +++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp @@ -182,7 +182,7 @@ OMX_ERRORTYPE SoftG711::internalSetParameter( } } -void SoftG711::onQueueFilled(OMX_U32 portIndex) { +void SoftG711::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError) { return; } diff --git a/media/libstagefright/codecs/gsm/dec/Android.mk b/media/libstagefright/codecs/gsm/dec/Android.mk index 71613d2..30868d5 100644 --- a/media/libstagefright/codecs/gsm/dec/Android.mk +++ b/media/libstagefright/codecs/gsm/dec/Android.mk @@ -9,6 +9,8 @@ LOCAL_C_INCLUDES := \ frameworks/native/include/media/openmax \ external/libgsm/inc +LOCAL_CFLAGS += -Werror + LOCAL_SHARED_LIBRARIES := \ libstagefright libstagefright_omx libstagefright_foundation libutils liblog diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp index 00e0c85..18f7d29 100644 --- a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp +++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp @@ -172,7 +172,7 @@ OMX_ERRORTYPE SoftGSM::internalSetParameter( } } -void SoftGSM::onQueueFilled(OMX_U32 portIndex) { +void SoftGSM::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError) { return; } diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk index a3d5779..1d232c6 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk +++ b/media/libstagefright/codecs/m4v_h263/dec/Android.mk @@ -46,6 +46,8 @@ LOCAL_C_INCLUDES := \ LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF= +LOCAL_CFLAGS += -Werror + include $(BUILD_STATIC_LIBRARY) ################################################################################ @@ -72,4 +74,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE := libstagefright_soft_mpeg4dec LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS += -Werror + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp index fb2a430..0d1ab71 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp @@ -91,7 +91,7 @@ status_t SoftMPEG4::initDecoder() { return OK; } -void SoftMPEG4::onQueueFilled(OMX_U32 portIndex) { +void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError || mOutputPortSettingsChange != NONE) { return; } diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.mk b/media/libstagefright/codecs/m4v_h263/enc/Android.mk index 83a2dd2..c9006d9 100644 --- a/media/libstagefright/codecs/m4v_h263/enc/Android.mk +++ b/media/libstagefright/codecs/m4v_h263/enc/Android.mk @@ -33,6 +33,8 @@ LOCAL_C_INCLUDES := \ $(TOP)/frameworks/av/media/libstagefright/include \ $(TOP)/frameworks/native/include/media/openmax +LOCAL_CFLAGS += -Werror + include $(BUILD_STATIC_LIBRARY) ################################################################################ @@ -72,4 +74,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE := libstagefright_soft_mpeg4enc LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS += -Werror + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp index e02af90..c084277 100644 --- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp +++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp @@ -620,7 +620,7 @@ OMX_ERRORTYPE SoftMPEG4Encoder::internalSetParameter( } } -void SoftMPEG4Encoder::onQueueFilled(OMX_U32 portIndex) { +void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError || mSawInputEOS) { return; } diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk index 135c715..8284490 100644 --- a/media/libstagefright/codecs/mp3dec/Android.mk +++ b/media/libstagefright/codecs/mp3dec/Android.mk @@ -50,6 +50,8 @@ LOCAL_C_INCLUDES := \ LOCAL_CFLAGS := \ -DOSCL_UNUSED_ARG= +LOCAL_CFLAGS += -Werror + LOCAL_MODULE := libstagefright_mp3dec LOCAL_ARM_MODE := arm @@ -69,6 +71,8 @@ LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/src \ $(LOCAL_PATH)/include +LOCAL_CFLAGS += -Werror + LOCAL_SHARED_LIBRARIES := \ libstagefright libstagefright_omx libstagefright_foundation libutils liblog diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp index 61df65e..a09ab7c 100644 --- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp +++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp @@ -188,7 +188,7 @@ OMX_ERRORTYPE SoftMP3::internalSetParameter( } } -void SoftMP3::onQueueFilled(OMX_U32 portIndex) { +void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError || mOutputPortSettingsChange != NONE) { return; } diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_mpeg2_get_scale_data.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_mpeg2_get_scale_data.cpp index ee42dc5..499672b 100644 --- a/media/libstagefright/codecs/mp3dec/src/pvmp3_mpeg2_get_scale_data.cpp +++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_mpeg2_get_scale_data.cpp @@ -139,7 +139,7 @@ void pvmp3_mpeg2_get_scale_data(mp3SideInfo *si, int16 blocknumber = 0; granuleInfo *gr_info = &(si->ch[ch].gran[gr]); - uint32 scalefac_comp, int_scalefac_comp, new_slen[4]; + uint32 scalefac_comp, int_scalefac_comp, new_slen[4] = { 0,0,0,0 }; scalefac_comp = gr_info->scalefac_compress; diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk index 7f2c46d..93ff64c 100644 --- a/media/libstagefright/codecs/on2/dec/Android.mk +++ b/media/libstagefright/codecs/on2/dec/Android.mk @@ -20,4 +20,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE := libstagefright_soft_vpxdec LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS += -Werror + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp index 476e986..423a057 100644 --- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp +++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp @@ -85,7 +85,7 @@ status_t SoftVPX::initDecoder() { return OK; } -void SoftVPX::onQueueFilled(OMX_U32 portIndex) { +void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) { if (mOutputPortSettingsChange != NONE) { return; } diff --git a/media/libstagefright/codecs/on2/enc/Android.mk b/media/libstagefright/codecs/on2/enc/Android.mk index 4060a0a..cbb1a89 100644 --- a/media/libstagefright/codecs/on2/enc/Android.mk +++ b/media/libstagefright/codecs/on2/enc/Android.mk @@ -26,4 +26,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE := libstagefright_soft_vpxenc LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS += -Werror + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp index 7ddb13c..a7bde97 100644 --- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp +++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp @@ -98,7 +98,7 @@ status_t SoftAVC::initDecoder() { return UNKNOWN_ERROR; } -void SoftAVC::onQueueFilled(OMX_U32 portIndex) { +void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError || mOutputPortSettingsChange != NONE) { return; } diff --git a/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c b/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c index 2bb4c4d..524a3f0 100644 --- a/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c +++ b/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c @@ -42,6 +42,8 @@ #include "h264bsd_decoder.h" #include "h264bsd_util.h" +#define UNUSED(x) (void)(x) + /*------------------------------------------------------------------------------ Version Information ------------------------------------------------------------------------------*/ @@ -73,6 +75,7 @@ H264DEC_EVALUATION Compile evaluation version, restricts number of frames #endif void H264SwDecTrace(char *string) { + UNUSED(string); } void* H264SwDecMalloc(u32 size) { diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c index 493fb9e..7a262ed 100755 --- a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c +++ b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c @@ -267,7 +267,7 @@ u32 ConcealMb(mbStorage_t *pMb, image_t *currImage, u32 row, u32 col, i32 firstPhase[16]; i32 *pTmp; /* neighbours above, below, left and right */ - i32 a[4], b[4], l[4], r[4]; + i32 a[4] = { 0,0,0,0 }, b[4], l[4] = { 0,0,0,0 }, r[4]; u32 A, B, L, R; #ifdef H264DEC_OMXDL u8 fillBuff[32*21 + 15 + 32]; diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c index c948776..b409a06 100755 --- a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c +++ b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c @@ -42,6 +42,8 @@ #include "armVC.h" #endif /* H264DEC_OMXDL */ +#define UNUSED(x) (void)(x) + /*------------------------------------------------------------------------------ 2. External compiler flags -------------------------------------------------------------------------------- @@ -2136,7 +2138,8 @@ static void FillRow1( i32 center, i32 right) { - + UNUSED(left); + UNUSED(right); ASSERT(ref); ASSERT(fill); diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c index a7c6f64..23401c6 100755 --- a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c +++ b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c @@ -47,6 +47,8 @@ #include "h264bsd_nal_unit.h" #include "h264bsd_dpb.h" +#define UNUSED(x) (void)(x) + /*------------------------------------------------------------------------------ 2. External compiler flags -------------------------------------------------------------------------------- @@ -1407,6 +1409,7 @@ u32 h264bsdCheckPriorPicsFlag(u32 * noOutputOfPriorPicsFlag, u32 tmp, value, i; i32 ivalue; strmData_t tmpStrmData[1]; + UNUSED(nalUnitType); /* Code */ diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c index cc838fd..fb97a28 100755 --- a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c +++ b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c @@ -186,7 +186,7 @@ u32 h264bsdMoreRbspData(strmData_t *pStrmData) return(HANTRO_FALSE); if ( (bits > 8) || - ((h264bsdShowBits32(pStrmData)>>(32-bits)) != (1 << (bits-1))) ) + ((h264bsdShowBits32(pStrmData)>>(32-bits)) != (1ul << (bits-1))) ) return(HANTRO_TRUE); else return(HANTRO_FALSE); diff --git a/media/libstagefright/codecs/raw/Android.mk b/media/libstagefright/codecs/raw/Android.mk index fe90a03..87080e7 100644 --- a/media/libstagefright/codecs/raw/Android.mk +++ b/media/libstagefright/codecs/raw/Android.mk @@ -8,6 +8,8 @@ LOCAL_C_INCLUDES := \ frameworks/av/media/libstagefright/include \ frameworks/native/include/media/openmax +LOCAL_CFLAGS += -Werror + LOCAL_SHARED_LIBRARIES := \ libstagefright_omx libstagefright_foundation libutils liblog diff --git a/media/libstagefright/codecs/raw/SoftRaw.cpp b/media/libstagefright/codecs/raw/SoftRaw.cpp index 19d6f13..9d514a6 100644 --- a/media/libstagefright/codecs/raw/SoftRaw.cpp +++ b/media/libstagefright/codecs/raw/SoftRaw.cpp @@ -163,7 +163,7 @@ OMX_ERRORTYPE SoftRaw::internalSetParameter( } } -void SoftRaw::onQueueFilled(OMX_U32 portIndex) { +void SoftRaw::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError) { return; } diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk index 2232353..217a6d2 100644 --- a/media/libstagefright/codecs/vorbis/dec/Android.mk +++ b/media/libstagefright/codecs/vorbis/dec/Android.mk @@ -16,4 +16,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE := libstagefright_soft_vorbisdec LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS += -Werror + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk index 59a64ba..1c90957 100644 --- a/media/libstagefright/colorconversion/Android.mk +++ b/media/libstagefright/colorconversion/Android.mk @@ -11,4 +11,6 @@ LOCAL_C_INCLUDES := \ LOCAL_MODULE:= libstagefright_color_conversion +LOCAL_CFLAGS += -Werror + include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/foundation/ANetworkSession.cpp b/media/libstagefright/foundation/ANetworkSession.cpp index e629588..08c4a87 100644 --- a/media/libstagefright/foundation/ANetworkSession.cpp +++ b/media/libstagefright/foundation/ANetworkSession.cpp @@ -521,7 +521,7 @@ status_t ANetworkSession::Session::readMore() { return err; } -void ANetworkSession::Session::dumpFragmentStats(const Fragment &frag) { +void ANetworkSession::Session::dumpFragmentStats(const Fragment & /* frag */) { #if 0 int64_t nowUs = ALooper::GetNowUs(); int64_t delayMs = (nowUs - frag.mTimeUs) / 1000ll; diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk index ad2dab5..90a6a23 100644 --- a/media/libstagefright/foundation/Android.mk +++ b/media/libstagefright/foundation/Android.mk @@ -24,7 +24,7 @@ LOCAL_SHARED_LIBRARIES := \ libutils \ liblog -LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Wno-multichar -Werror LOCAL_MODULE:= libstagefright_foundation diff --git a/media/libstagefright/http/Android.mk b/media/libstagefright/http/Android.mk index a6b481f..7f3307d 100644 --- a/media/libstagefright/http/Android.mk +++ b/media/libstagefright/http/Android.mk @@ -21,6 +21,8 @@ LOCAL_MODULE:= libstagefright_http_support LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Werror + include $(BUILD_SHARED_LIBRARY) endif diff --git a/media/libstagefright/httplive/Android.mk b/media/libstagefright/httplive/Android.mk index f3529f9..e8d558c 100644 --- a/media/libstagefright/httplive/Android.mk +++ b/media/libstagefright/httplive/Android.mk @@ -13,6 +13,8 @@ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/native/include/media/openmax \ $(TOP)/external/openssl/include +LOCAL_CFLAGS += -Werror + LOCAL_SHARED_LIBRARIES := \ libbinder \ libcrypto \ diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 5ef7c0f..39d80fc 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -125,7 +125,7 @@ void M3UParser::MediaGroup::pickRandomMediaItems() { mSelectedIndex = strtoul(value, &end, 10); CHECK(end > value && *end == '\0'); - if (mSelectedIndex >= mMediaItems.size()) { + if (mSelectedIndex >= (ssize_t)mMediaItems.size()) { mSelectedIndex = mMediaItems.size() - 1; } } else { @@ -165,14 +165,14 @@ status_t M3UParser::MediaGroup::selectTrack(size_t index, bool select) { ALOGE("track %d does not exist", index); return INVALID_OPERATION; } - if (mSelectedIndex == index) { + if (mSelectedIndex == (ssize_t)index) { ALOGE("track %d already selected", index); return BAD_VALUE; } ALOGV("selected track %d", index); mSelectedIndex = index; } else { - if (mSelectedIndex != index) { + if (mSelectedIndex != (ssize_t)index) { ALOGE("track %d is not selected", index); return BAD_VALUE; } diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index f095987..4d29366 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -602,7 +602,7 @@ void PlaylistFetcher::onDownloadNext() { if (mPlaylist->isComplete() || mPlaylist->isEvent()) { mSeqNumber = getSeqNumberForTime(mStartTimeUs); - ALOGV("Initial sequence number for time %lld is %ld from (%ld .. %ld)", + ALOGV("Initial sequence number for time %lld is %d from (%d .. %d)", mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist); } else { @@ -611,7 +611,7 @@ void PlaylistFetcher::onDownloadNext() { if (mSeqNumber < firstSeqNumberInPlaylist) { mSeqNumber = firstSeqNumberInPlaylist; } - ALOGV("Initial sequence number for live event %ld from (%ld .. %ld)", + ALOGV("Initial sequence number for live event %d from (%d .. %d)", mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist); } @@ -635,7 +635,8 @@ void PlaylistFetcher::onDownloadNext() { if (delayUs > kMaxMonitorDelayUs) { delayUs = kMaxMonitorDelayUs; } - ALOGV("sequence number high: %ld from (%ld .. %ld), monitor in %lld (retry=%d)", + ALOGV("sequence number high: %d from (%d .. %d), " + "monitor in %lld (retry=%d)", mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist, delayUs, mNumRetries); postMonitorQueue(delayUs); diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk index bf6f7bb..2194c38 100644 --- a/media/libstagefright/id3/Android.mk +++ b/media/libstagefright/id3/Android.mk @@ -4,6 +4,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ ID3.cpp +LOCAL_CFLAGS += -Werror + LOCAL_MODULE := libstagefright_id3 include $(BUILD_STATIC_LIBRARY) @@ -15,6 +17,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ testid3.cpp +LOCAL_CFLAGS += -Werror + LOCAL_SHARED_LIBRARIES := \ libstagefright libutils liblog libbinder libstagefright_foundation diff --git a/media/libstagefright/include/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h index 3e84256..2963150 100644 --- a/media/libstagefright/include/TimedEventQueue.h +++ b/media/libstagefright/include/TimedEventQueue.h @@ -122,7 +122,7 @@ private: }; struct StopEvent : public TimedEventQueue::Event { - virtual void fire(TimedEventQueue *queue, int64_t now_us) { + virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) { queue->mStopped = true; } }; diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk index 2d8c1e1..446ff8c 100644 --- a/media/libstagefright/matroska/Android.mk +++ b/media/libstagefright/matroska/Android.mk @@ -8,7 +8,7 @@ LOCAL_C_INCLUDES:= \ $(TOP)/external/libvpx/libwebm \ $(TOP)/frameworks/native/include/media/openmax \ -LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Wno-multichar -Werror LOCAL_MODULE:= libstagefright_matroska diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index dcb1cda..6f69d0b 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -193,7 +193,7 @@ MatroskaSource::~MatroskaSource() { clearPendingFrames(); } -status_t MatroskaSource::start(MetaData *params) { +status_t MatroskaSource::start(MetaData * /* params */) { mBlockIter.reset(); return OK; @@ -410,7 +410,7 @@ void BlockIterator::seek( // Accept the first key frame *actualFrameTimeUs = (block()->GetTime(mCluster) + 500LL) / 1000LL; ALOGV("Requested seek point: %lld actual: %lld", - seekTimeUs, actualFrameTimeUs); + seekTimeUs, *actualFrameTimeUs); break; } } diff --git a/media/libstagefright/mp4/FragmentedMP4Parser.cpp b/media/libstagefright/mp4/FragmentedMP4Parser.cpp index 0102656..0639bec 100644 --- a/media/libstagefright/mp4/FragmentedMP4Parser.cpp +++ b/media/libstagefright/mp4/FragmentedMP4Parser.cpp @@ -32,6 +32,11 @@ #include #include +#if LOG_NDEBUG +#define UNUSED_UNLESS_VERBOSE(x) (void)(x) +#else +#define UNUSED_UNLESS_VERBOSE(x) +#endif namespace android { @@ -463,7 +468,9 @@ void FragmentedMP4Parser::onMessageReceived(const sp &msg) { mBuffer->data() + mBuffer->size(), needed); if (n < (ssize_t)needed) { - ALOGV("Reached EOF when reading %d @ %d + %d", needed, mBufferPos, mBuffer->size()); + ALOGV("Reached EOF when reading %d @ %ld + %zu", + needed, mBufferPos, mBuffer->size()); + if (n < 0) { mFinalResult = n; } else if (n == 0) { @@ -636,7 +643,7 @@ status_t FragmentedMP4Parser::onProceed() { // This is a container box. if (type == FOURCC('m', 'o', 'o', 'f')) { if (mFirstMoofOffset == 0) { - ALOGV("first moof @ %08x", mBufferPos + offset); + ALOGV("first moof @ %08lx", mBufferPos + offset); mFirstMoofOffset = mBufferPos + offset - 8; // point at the size } } @@ -1137,7 +1144,7 @@ void FragmentedMP4Parser::skip(off_t distance) { } status_t FragmentedMP4Parser::parseTrackHeader( - uint32_t type, size_t offset, uint64_t size) { + uint32_t /* type */, size_t offset, uint64_t size) { if (offset + 4 > size) { return -EINVAL; } @@ -1188,7 +1195,7 @@ status_t FragmentedMP4Parser::parseTrackHeader( } status_t FragmentedMP4Parser::parseMediaHeader( - uint32_t type, size_t offset, uint64_t size) { + uint32_t /* type */, size_t offset, uint64_t size) { if (offset + 4 > size) { return -EINVAL; } @@ -1221,7 +1228,7 @@ status_t FragmentedMP4Parser::parseMediaHeader( } status_t FragmentedMP4Parser::parseMediaHandler( - uint32_t type, size_t offset, uint64_t size) { + uint32_t /* type */, size_t offset, uint64_t size) { if (offset + 12 > size) { return -EINVAL; } @@ -1388,7 +1395,7 @@ status_t FragmentedMP4Parser::parseChunkOffsets64( } status_t FragmentedMP4Parser::parseAVCCodecSpecificData( - uint32_t type, size_t offset, uint64_t size) { + uint32_t /* type */, size_t offset, uint64_t size) { TrackInfo *trackInfo = editTrack(mCurrentTrackID); SampleDescription *sampleDesc = @@ -1471,7 +1478,7 @@ status_t FragmentedMP4Parser::parseAVCCodecSpecificData( } status_t FragmentedMP4Parser::parseESDSCodecSpecificData( - uint32_t type, size_t offset, uint64_t size) { + uint32_t /* type */, size_t offset, uint64_t size) { TrackInfo *trackInfo = editTrack(mCurrentTrackID); SampleDescription *sampleDesc = @@ -1576,7 +1583,7 @@ status_t FragmentedMP4Parser::parseESDSCodecSpecificData( } status_t FragmentedMP4Parser::parseMediaData( - uint32_t type, size_t offset, uint64_t size) { + uint32_t /* type */, size_t offset, uint64_t size) { ALOGV("skipping 'mdat' chunk at offsets 0x%08lx-0x%08llx.", mBufferPos + offset, mBufferPos + size); @@ -1598,6 +1605,7 @@ status_t FragmentedMP4Parser::parseMediaData( status_t FragmentedMP4Parser::parseSegmentIndex( uint32_t type, size_t offset, uint64_t size) { + UNUSED_UNLESS_VERBOSE(type); ALOGV("sidx box type %d, offset %d, size %d", type, int(offset), int(size)); // AString sidxstr; // hexdump(mBuffer->data() + offset, size, 0 /* indent */, &sidxstr); @@ -1684,7 +1692,7 @@ status_t FragmentedMP4Parser::parseSegmentIndex( } status_t FragmentedMP4Parser::parseTrackExtends( - uint32_t type, size_t offset, uint64_t size) { + uint32_t /* type */, size_t offset, uint64_t size) { if (offset + 24 > size) { return -EINVAL; } @@ -1735,7 +1743,7 @@ FragmentedMP4Parser::TrackInfo *FragmentedMP4Parser::editTrack( } status_t FragmentedMP4Parser::parseTrackFragmentHeader( - uint32_t type, size_t offset, uint64_t size) { + uint32_t /* type */, size_t offset, uint64_t size) { if (offset + 8 > size) { return -EINVAL; } @@ -1825,7 +1833,7 @@ status_t FragmentedMP4Parser::parseTrackFragmentHeader( } status_t FragmentedMP4Parser::parseTrackFragmentRun( - uint32_t type, size_t offset, uint64_t size) { + uint32_t /* type */, size_t offset, uint64_t size) { if (offset + 8 > size) { return -EINVAL; } diff --git a/media/libstagefright/mp4/TrackFragment.cpp b/media/libstagefright/mp4/TrackFragment.cpp index 3699038..3e0056d 100644 --- a/media/libstagefright/mp4/TrackFragment.cpp +++ b/media/libstagefright/mp4/TrackFragment.cpp @@ -241,7 +241,10 @@ bool FragmentedMP4Parser::StaticTrackFragment::complete() const { } status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleSizes( - FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) { + FragmentedMP4Parser *parser, + uint32_t /* type */, + size_t offset, + uint64_t size) { if (offset + 12 > size) { return ERROR_MALFORMED; } @@ -265,7 +268,10 @@ status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleSizes( } status_t FragmentedMP4Parser::StaticTrackFragment::parseCompactSampleSizes( - FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) { + FragmentedMP4Parser *parser, + uint32_t /* type */, + size_t offset, + uint64_t size) { if (offset + 12 > size) { return ERROR_MALFORMED; } @@ -294,7 +300,10 @@ status_t FragmentedMP4Parser::StaticTrackFragment::parseCompactSampleSizes( } status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleToChunk( - FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) { + FragmentedMP4Parser *parser, + uint32_t /* type */, + size_t offset, + uint64_t size) { if (offset + 8 > size) { return ERROR_MALFORMED; } @@ -319,7 +328,10 @@ status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleToChunk( } status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets( - FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) { + FragmentedMP4Parser *parser, + uint32_t /* type */, + size_t offset, + uint64_t size) { if (offset + 8 > size) { return ERROR_MALFORMED; } @@ -340,7 +352,10 @@ status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets( } status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets64( - FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) { + FragmentedMP4Parser *parser, + uint32_t /* type */, + size_t offset, + uint64_t size) { if (offset + 8 > size) { return ERROR_MALFORMED; } diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index cb57a2f..d039f7d 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -862,7 +862,7 @@ status_t ATSParser::Stream::flush() { } void ATSParser::Stream::onPayloadData( - unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS, + unsigned PTS_DTS_flags, uint64_t PTS, uint64_t /* DTS */, const uint8_t *data, size_t size) { #if 0 ALOGI("payload streamType 0x%02x, PTS = 0x%016llx, dPTS = %lld", @@ -1267,7 +1267,7 @@ bool ATSParser::PTSTimeDeltaEstablished() { } void ATSParser::updatePCR( - unsigned PID, uint64_t PCR, size_t byteOffsetFromStart) { + unsigned /* PID */, uint64_t PCR, size_t byteOffsetFromStart) { ALOGV("PCR 0x%016llx @ %d", PCR, byteOffsetFromStart); if (mNumPCRs == 2) { diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk index c1a7a9d..c17a0b7 100644 --- a/media/libstagefright/mpeg2ts/Android.mk +++ b/media/libstagefright/mpeg2ts/Android.mk @@ -13,6 +13,8 @@ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/av/media/libstagefright \ $(TOP)/frameworks/native/include/media/openmax +LOCAL_CFLAGS += -Werror + LOCAL_MODULE:= libstagefright_mpeg2ts ifeq ($(TARGET_ARCH),arm) diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index 52fb2a5..9fb13c1 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -61,7 +61,7 @@ void AnotherPacketSource::setFormat(const sp &meta) { AnotherPacketSource::~AnotherPacketSource() { } -status_t AnotherPacketSource::start(MetaData *params) { +status_t AnotherPacketSource::start(MetaData * /* params */) { return OK; } diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp index dd714c9..bc2a16d 100644 --- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp +++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp @@ -130,7 +130,8 @@ sp MPEG2PSExtractor::getTrack(size_t index) { return new WrappedTrack(this, mTracks.valueAt(index)); } -sp MPEG2PSExtractor::getTrackMetaData(size_t index, uint32_t flags) { +sp MPEG2PSExtractor::getTrackMetaData( + size_t index, uint32_t /* flags */) { if (index >= mTracks.size()) { return NULL; } @@ -625,7 +626,7 @@ status_t MPEG2PSExtractor::Track::read( status_t MPEG2PSExtractor::Track::appendPESData( unsigned PTS_DTS_flags, - uint64_t PTS, uint64_t DTS, + uint64_t PTS, uint64_t /* DTS */, const uint8_t *data, size_t size) { if (mQueue == NULL) { return OK; diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp index d449c34..35ca118 100644 --- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp +++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp @@ -141,7 +141,7 @@ sp MPEG2TSExtractor::getTrack(size_t index) { } sp MPEG2TSExtractor::getTrackMetaData( - size_t index, uint32_t flags) { + size_t index, uint32_t /* flags */) { return index < mSourceImpls.size() ? mSourceImpls.editItemAt(index)->getFormat() : NULL; } diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk index cd912e7..37b289f 100644 --- a/media/libstagefright/omx/Android.mk +++ b/media/libstagefright/omx/Android.mk @@ -16,6 +16,8 @@ LOCAL_C_INCLUDES += \ $(TOP)/frameworks/native/include/media/hardware \ $(TOP)/frameworks/native/include/media/openmax +LOCAL_CFLAGS += -Werror + LOCAL_SHARED_LIBRARIES := \ libbinder \ libmedia \ diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 1e6de55..7672204 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -41,11 +41,11 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, mNumFramesAvailable(0), mEndOfStream(false), mEndOfStreamSent(false), - mRepeatAfterUs(-1ll), mMaxTimestampGapUs(-1ll), mPrevOriginalTimeUs(-1ll), mPrevModifiedTimeUs(-1ll), mSkipFramesBeforeNs(-1ll), + mRepeatAfterUs(-1ll), mRepeatLastFrameGeneration(0), mRepeatLastFrameTimestamp(-1ll), mLatestSubmittedBufferId(-1), diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index 274f2eb..a608479 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -185,7 +185,7 @@ void OMX::binderDied(const wp &the_late_who) { instance->onObserverDied(mMaster); } -bool OMX::livesLocally(node_id node, pid_t pid) { +bool OMX::livesLocally(node_id /* node */, pid_t pid) { return pid == getpid(); } @@ -424,7 +424,7 @@ OMX_ERRORTYPE OMX::OnEvent( OMX_IN OMX_EVENTTYPE eEvent, OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, - OMX_IN OMX_PTR pEventData) { + OMX_IN OMX_PTR /* pEventData */) { ALOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2); // Forward to OMXNodeInstance. diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index dba522f..aa96389 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -266,7 +266,7 @@ status_t OMXNodeInstance::sendCommand( } status_t OMXNodeInstance::getParameter( - OMX_INDEXTYPE index, void *params, size_t size) { + OMX_INDEXTYPE index, void *params, size_t /* size */) { Mutex::Autolock autoLock(mLock); OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params); @@ -275,7 +275,7 @@ status_t OMXNodeInstance::getParameter( } status_t OMXNodeInstance::setParameter( - OMX_INDEXTYPE index, const void *params, size_t size) { + OMX_INDEXTYPE index, const void *params, size_t /* size */) { Mutex::Autolock autoLock(mLock); OMX_ERRORTYPE err = OMX_SetParameter( @@ -285,7 +285,7 @@ status_t OMXNodeInstance::setParameter( } status_t OMXNodeInstance::getConfig( - OMX_INDEXTYPE index, void *params, size_t size) { + OMX_INDEXTYPE index, void *params, size_t /* size */) { Mutex::Autolock autoLock(mLock); OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params); @@ -293,7 +293,7 @@ status_t OMXNodeInstance::getConfig( } status_t OMXNodeInstance::setConfig( - OMX_INDEXTYPE index, const void *params, size_t size) { + OMX_INDEXTYPE index, const void *params, size_t /* size */) { Mutex::Autolock autoLock(mLock); OMX_ERRORTYPE err = OMX_SetConfig( @@ -610,7 +610,7 @@ status_t OMXNodeInstance::useGraphicBuffer( } status_t OMXNodeInstance::updateGraphicBufferInMeta( - OMX_U32 portIndex, const sp& graphicBuffer, + OMX_U32 /* portIndex */, const sp& graphicBuffer, OMX::buffer_id buffer) { Mutex::Autolock autoLock(mLock); @@ -971,7 +971,7 @@ void OMXNodeInstance::onEvent( // static OMX_ERRORTYPE OMXNodeInstance::OnEvent( - OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_HANDLETYPE /* hComponent */, OMX_IN OMX_PTR pAppData, OMX_IN OMX_EVENTTYPE eEvent, OMX_IN OMX_U32 nData1, @@ -987,7 +987,7 @@ OMX_ERRORTYPE OMXNodeInstance::OnEvent( // static OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone( - OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_HANDLETYPE /* hComponent */, OMX_IN OMX_PTR pAppData, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { OMXNodeInstance *instance = static_cast(pAppData); @@ -999,7 +999,7 @@ OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone( // static OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone( - OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_HANDLETYPE /* hComponent */, OMX_IN OMX_PTR pAppData, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { OMXNodeInstance *instance = static_cast(pAppData); diff --git a/media/libstagefright/omx/SoftOMXComponent.cpp b/media/libstagefright/omx/SoftOMXComponent.cpp index b1c34dc..646cd32 100644 --- a/media/libstagefright/omx/SoftOMXComponent.cpp +++ b/media/libstagefright/omx/SoftOMXComponent.cpp @@ -257,69 +257,69 @@ OMX_ERRORTYPE SoftOMXComponent::GetStateWrapper( //////////////////////////////////////////////////////////////////////////////// OMX_ERRORTYPE SoftOMXComponent::sendCommand( - OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data) { + OMX_COMMANDTYPE /* cmd */, OMX_U32 /* param */, OMX_PTR /* data */) { return OMX_ErrorUndefined; } OMX_ERRORTYPE SoftOMXComponent::getParameter( - OMX_INDEXTYPE index, OMX_PTR params) { + OMX_INDEXTYPE /* index */, OMX_PTR /* params */) { return OMX_ErrorUndefined; } OMX_ERRORTYPE SoftOMXComponent::setParameter( - OMX_INDEXTYPE index, const OMX_PTR params) { + OMX_INDEXTYPE /* index */, const OMX_PTR /* params */) { return OMX_ErrorUndefined; } OMX_ERRORTYPE SoftOMXComponent::getConfig( - OMX_INDEXTYPE index, OMX_PTR params) { + OMX_INDEXTYPE /* index */, OMX_PTR /* params */) { return OMX_ErrorUndefined; } OMX_ERRORTYPE SoftOMXComponent::setConfig( - OMX_INDEXTYPE index, const OMX_PTR params) { + OMX_INDEXTYPE /* index */, const OMX_PTR /* params */) { return OMX_ErrorUndefined; } OMX_ERRORTYPE SoftOMXComponent::getExtensionIndex( - const char *name, OMX_INDEXTYPE *index) { + const char * /* name */, OMX_INDEXTYPE * /* index */) { return OMX_ErrorUndefined; } OMX_ERRORTYPE SoftOMXComponent::useBuffer( - OMX_BUFFERHEADERTYPE **buffer, - OMX_U32 portIndex, - OMX_PTR appPrivate, - OMX_U32 size, - OMX_U8 *ptr) { + OMX_BUFFERHEADERTYPE ** /* buffer */, + OMX_U32 /* portIndex */, + OMX_PTR /* appPrivate */, + OMX_U32 /* size */, + OMX_U8 * /* ptr */) { return OMX_ErrorUndefined; } OMX_ERRORTYPE SoftOMXComponent::allocateBuffer( - OMX_BUFFERHEADERTYPE **buffer, - OMX_U32 portIndex, - OMX_PTR appPrivate, - OMX_U32 size) { + OMX_BUFFERHEADERTYPE ** /* buffer */, + OMX_U32 /* portIndex */, + OMX_PTR /* appPrivate */, + OMX_U32 /* size */) { return OMX_ErrorUndefined; } OMX_ERRORTYPE SoftOMXComponent::freeBuffer( - OMX_U32 portIndex, - OMX_BUFFERHEADERTYPE *buffer) { + OMX_U32 /* portIndex */, + OMX_BUFFERHEADERTYPE * /* buffer */) { return OMX_ErrorUndefined; } OMX_ERRORTYPE SoftOMXComponent::emptyThisBuffer( - OMX_BUFFERHEADERTYPE *buffer) { + OMX_BUFFERHEADERTYPE * /* buffer */) { return OMX_ErrorUndefined; } OMX_ERRORTYPE SoftOMXComponent::fillThisBuffer( - OMX_BUFFERHEADERTYPE *buffer) { + OMX_BUFFERHEADERTYPE * /* buffer */) { return OMX_ErrorUndefined; } -OMX_ERRORTYPE SoftOMXComponent::getState(OMX_STATETYPE *state) { +OMX_ERRORTYPE SoftOMXComponent::getState(OMX_STATETYPE * /* state */) { return OMX_ErrorUndefined; } diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp index d6cde73..d49e50b 100644 --- a/media/libstagefright/omx/SoftOMXPlugin.cpp +++ b/media/libstagefright/omx/SoftOMXPlugin.cpp @@ -154,7 +154,7 @@ OMX_ERRORTYPE SoftOMXPlugin::destroyComponentInstance( OMX_ERRORTYPE SoftOMXPlugin::enumerateComponents( OMX_STRING name, - size_t size, + size_t /* size */, OMX_U32 index) { if (index >= kNumComponents) { return OMX_ErrorNoMore; diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk index 1061c39..8b79af4 100644 --- a/media/libstagefright/omx/tests/Android.mk +++ b/media/libstagefright/omx/tests/Android.mk @@ -11,6 +11,8 @@ LOCAL_C_INCLUDES := \ $(TOP)/frameworks/av/media/libstagefright \ $(TOP)/frameworks/native/include/media/openmax +LOCAL_CFLAGS += -Werror + LOCAL_MODULE := omx_tests LOCAL_MODULE_TAGS := tests diff --git a/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp index 4c9bf5b..dca5c89 100644 --- a/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp +++ b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp @@ -34,7 +34,9 @@ namespace android { AMPEG2TSAssembler::AMPEG2TSAssembler( - const sp ¬ify, const char *desc, const AString ¶ms) + const sp ¬ify, + const char * /* desc */, + const AString & /* params */) : mNotifyMsg(notify), mNextExpectedSeqNoValid(false), mNextExpectedSeqNo(0) { diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp index 0d07043..c46d16f 100644 --- a/media/libstagefright/rtsp/ARTPWriter.cpp +++ b/media/libstagefright/rtsp/ARTPWriter.cpp @@ -114,7 +114,7 @@ bool ARTPWriter::reachedEOS() { return (mFlags & kFlagEOS) != 0; } -status_t ARTPWriter::start(MetaData *params) { +status_t ARTPWriter::start(MetaData * /* params */) { Mutex::Autolock autoLock(mLock); if (mFlags & kFlagStarted) { return INVALID_OPERATION; diff --git a/media/libstagefright/rtsp/ARawAudioAssembler.cpp b/media/libstagefright/rtsp/ARawAudioAssembler.cpp index 0da5dd2..167f7a4 100644 --- a/media/libstagefright/rtsp/ARawAudioAssembler.cpp +++ b/media/libstagefright/rtsp/ARawAudioAssembler.cpp @@ -34,7 +34,9 @@ namespace android { ARawAudioAssembler::ARawAudioAssembler( - const sp ¬ify, const char *desc, const AString ¶ms) + const sp ¬ify, + const char * /* desc */, + const AString & /* params */) : mNotifyMsg(notify), mNextExpectedSeqNoValid(false), mNextExpectedSeqNo(0) { diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk index 02e44f4..39eedc0 100644 --- a/media/libstagefright/rtsp/Android.mk +++ b/media/libstagefright/rtsp/Android.mk @@ -30,6 +30,8 @@ ifeq ($(TARGET_ARCH),arm) LOCAL_CFLAGS += -Wno-psabi endif +LOCAL_CFLAGS += -Werror + include $(BUILD_STATIC_LIBRARY) ################################################################################ diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index cd77aa0..45470a3 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -19,7 +19,11 @@ #define MY_HANDLER_H_ //#define LOG_NDEBUG 0 + +#ifndef LOG_TAG #define LOG_TAG "MyHandler" +#endif + #include #include "APacketSource.h" @@ -42,6 +46,12 @@ #include "HTTPBase.h" +#if LOG_NDEBUG +#define UNUSED_UNLESS_VERBOSE(x) (void)(x) +#else +#define UNUSED_UNLESS_VERBOSE(x) +#endif + // If no access units are received within 5 secs, assume that the rtp // stream has ended and signal end of stream. static int64_t kAccessUnitTimeoutUs = 10000000ll; @@ -178,7 +188,7 @@ struct MyHandler : public AHandler { mConn->connect(mOriginalSessionURL.c_str(), reply); } - AString getControlURL(sp desc) { + AString getControlURL() { AString sessionLevelControlURL; if (mSessionDesc->findAttribute( 0, @@ -545,7 +555,7 @@ struct MyHandler : public AHandler { mBaseURL = tmp; } - mControlURL = getControlURL(mSessionDesc); + mControlURL = getControlURL(); if (mSessionDesc->countTracks() < 2) { // There's no actual tracks in this session. @@ -591,7 +601,7 @@ struct MyHandler : public AHandler { mSeekable = !isLiveStream(mSessionDesc); - mControlURL = getControlURL(mSessionDesc); + mControlURL = getControlURL(); if (mSessionDesc->countTracks() < 2) { // There's no actual tracks in this session. @@ -1805,6 +1815,8 @@ private: bool addMediaTimestamp( int32_t trackIndex, const TrackInfo *track, const sp &accessUnit) { + UNUSED_UNLESS_VERBOSE(trackIndex); + uint32_t rtpTime; CHECK(accessUnit->meta()->findInt32( "rtp-time", (int32_t *)&rtpTime)); diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk index f099bbd..6a8b9fc 100644 --- a/media/libstagefright/timedtext/Android.mk +++ b/media/libstagefright/timedtext/Android.mk @@ -9,7 +9,8 @@ LOCAL_SRC_FILES:= \ TimedTextSRTSource.cpp \ TimedTextPlayer.cpp -LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Wno-multichar -Werror + LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/av/include/media/stagefright/timedtext \ $(TOP)/frameworks/av/media/libstagefright diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp index 05d6d02..71aa21e 100644 --- a/media/libstagefright/timedtext/TimedTextDriver.cpp +++ b/media/libstagefright/timedtext/TimedTextDriver.cpp @@ -45,6 +45,7 @@ TimedTextDriver::TimedTextDriver( const sp &httpService) : mLooper(new ALooper), mListener(listener), + mHTTPService(httpService), mState(UNINITIALIZED), mCurrentTrackIndex(UINT_MAX) { mLooper->setName("TimedTextDriver"); diff --git a/media/libstagefright/timedtext/TimedTextSource.h b/media/libstagefright/timedtext/TimedTextSource.h index 756cc31..8c1c1cd 100644 --- a/media/libstagefright/timedtext/TimedTextSource.h +++ b/media/libstagefright/timedtext/TimedTextSource.h @@ -47,7 +47,7 @@ class TimedTextSource : public RefBase { int64_t *endTimeUs, Parcel *parcel, const MediaSource::ReadOptions *options = NULL) = 0; - virtual status_t extractGlobalDescriptions(Parcel *parcel) { + virtual status_t extractGlobalDescriptions(Parcel * /* parcel */) { return INVALID_OPERATION; } virtual sp getFormat(); diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk index f70454a..3f47bfb 100644 --- a/media/libstagefright/wifi-display/Android.mk +++ b/media/libstagefright/wifi-display/Android.mk @@ -19,6 +19,8 @@ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/native/include/media/openmax \ $(TOP)/frameworks/av/media/libstagefright/mpeg2ts \ +LOCAL_CFLAGS += -Werror + LOCAL_SHARED_LIBRARIES:= \ libbinder \ libcutils \ diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp index 1887b8b..e88a3bd 100644 --- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp +++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp @@ -685,9 +685,8 @@ status_t RTPSender::onRTCPData(const sp &buffer) { return OK; } -status_t RTPSender::parseReceiverReport(const uint8_t *data, size_t size) { - // hexdump(data, size); - +status_t RTPSender::parseReceiverReport( + const uint8_t *data, size_t /* size */) { float fractionLost = data[12] / 256.0f; ALOGI("lost %.2f %% of packets during report interval.", diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp index 05e4018..da405e2 100644 --- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp +++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp @@ -746,7 +746,7 @@ status_t WifiDisplaySource::sendM16(int32_t sessionID) { } status_t WifiDisplaySource::onReceiveM1Response( - int32_t sessionID, const sp &msg) { + int32_t /* sessionID */, const sp &msg) { int32_t statusCode; if (!msg->getStatusCode(&statusCode)) { return ERROR_MALFORMED; @@ -991,7 +991,7 @@ status_t WifiDisplaySource::onReceiveM4Response( } status_t WifiDisplaySource::onReceiveM5Response( - int32_t sessionID, const sp &msg) { + int32_t /* sessionID */, const sp &msg) { int32_t statusCode; if (!msg->getStatusCode(&statusCode)) { return ERROR_MALFORMED; @@ -1005,7 +1005,7 @@ status_t WifiDisplaySource::onReceiveM5Response( } status_t WifiDisplaySource::onReceiveM16Response( - int32_t sessionID, const sp &msg) { + int32_t sessionID, const sp & /* msg */) { // If only the response was required to include a "Session:" header... CHECK_EQ(sessionID, mClientSessionID); @@ -1680,7 +1680,7 @@ WifiDisplaySource::HDCPObserver::HDCPObserver( } void WifiDisplaySource::HDCPObserver::notify( - int msg, int ext1, int ext2, const Parcel *obj) { + int msg, int ext1, int ext2, const Parcel * /* obj */) { sp notify = mNotify->dup(); notify->setInt32("msg", msg); notify->setInt32("ext1", ext1); diff --git a/media/libstagefright/yuv/Android.mk b/media/libstagefright/yuv/Android.mk index b3f7b1b..bb86dfc 100644 --- a/media/libstagefright/yuv/Android.mk +++ b/media/libstagefright/yuv/Android.mk @@ -12,5 +12,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE:= libstagefright_yuv +LOCAL_CFLAGS += -Werror + include $(BUILD_SHARED_LIBRARY) -- cgit v1.1 From 4bbfff2dbf3968c267c3b2ea9f8912a38372a9da Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Mon, 10 Feb 2014 14:40:45 -0800 Subject: Support "data:" URIs again in mediaplayer... Change-Id: I6dac35c7e606f738a60f985f6dca977dc92c82a4 related-to-bug: 12957757 --- media/libstagefright/Android.mk | 1 + media/libstagefright/DataSource.cpp | 3 + media/libstagefright/DataURISource.cpp | 109 +++++++++++++++++++++++++++++ media/libstagefright/foundation/base64.cpp | 6 +- 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 media/libstagefright/DataURISource.cpp (limited to 'media') diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 63f9399..f94f136 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -15,6 +15,7 @@ LOCAL_SRC_FILES:= \ CameraSource.cpp \ CameraSourceTimeLapse.cpp \ DataSource.cpp \ + DataURISource.cpp \ DRMExtractor.cpp \ ESDS.cpp \ FileSource.cpp \ diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 2704b74..6e0f37a 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -221,6 +222,8 @@ sp DataSource::CreateFromURI( // in the widevine:// case. source = httpSource; } + } else if (!strncasecmp("data:", uri, 5)) { + source = DataURISource::Create(uri); } else { // Assume it's a filename. source = new FileSource(uri); diff --git a/media/libstagefright/DataURISource.cpp b/media/libstagefright/DataURISource.cpp new file mode 100644 index 0000000..377bc85 --- /dev/null +++ b/media/libstagefright/DataURISource.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 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 + +#include +#include +#include + +namespace android { + +// static +sp DataURISource::Create(const char *uri) { + if (strncasecmp("data:", uri, 5)) { + return NULL; + } + + char *commaPos = strrchr(uri, ','); + + if (commaPos == NULL) { + return NULL; + } + + sp buffer; + + AString tmp(&uri[5], commaPos - &uri[5]); + + if (tmp.endsWith(";base64")) { + AString encoded(commaPos + 1); + + // Strip CR and LF... + for (size_t i = encoded.size(); i-- > 0;) { + if (encoded.c_str()[i] == '\r' || encoded.c_str()[i] == '\n') { + encoded.erase(i, 1); + } + } + + buffer = decodeBase64(encoded); + + if (buffer == NULL) { + ALOGE("Malformed base64 encoded content found."); + return NULL; + } + } else { +#if 0 + size_t dataLen = strlen(uri) - tmp.size() - 6; + buffer = new ABuffer(dataLen); + memcpy(buffer->data(), commaPos + 1, dataLen); + + // unescape +#else + // MediaPlayer doesn't care for this right now as we don't + // play any text-based media. + return NULL; +#endif + } + + // We don't really care about charset or mime type. + + return new DataURISource(buffer); +} + +DataURISource::DataURISource(const sp &buffer) + : mBuffer(buffer) { +} + +DataURISource::~DataURISource() { +} + +status_t DataURISource::initCheck() const { + return OK; +} + +ssize_t DataURISource::readAt(off64_t offset, void *data, size_t size) { + if (offset >= mBuffer->size()) { + return 0; + } + + size_t copy = mBuffer->size() - offset; + if (copy > size) { + copy = size; + } + + memcpy(data, mBuffer->data() + offset, copy); + + return copy; +} + +status_t DataURISource::getSize(off64_t *size) { + *size = mBuffer->size(); + + return OK; +} + +} // namespace android + diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp index d5fb4e0..dcf5bef 100644 --- a/media/libstagefright/foundation/base64.cpp +++ b/media/libstagefright/foundation/base64.cpp @@ -33,6 +33,10 @@ sp decodeBase64(const AString &s) { if (n >= 2 && s.c_str()[n - 2] == '=') { padding = 2; + + if (n >= 3 && s.c_str()[n - 3] == '=') { + padding = 3; + } } } @@ -71,7 +75,7 @@ sp decodeBase64(const AString &s) { if (((i + 1) % 4) == 0) { out[j++] = (accum >> 16); - if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } + if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } if (j < outLen) { out[j++] = accum & 0xff; } accum = 0; -- cgit v1.1 From d457c970c8d08519cd77280a90b61ae1e342cfe3 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 11 Feb 2014 08:47:07 -0800 Subject: Track pid for each session so they can be properly freed. Change-Id: I6f389035bc29e74e7c367c1c6d0252b180f666b3 --- media/libmedia/AudioRecord.cpp | 4 +-- media/libmedia/AudioSystem.cpp | 8 +++--- media/libmedia/AudioTrack.cpp | 29 ++++++++++++++++------ media/libmedia/IAudioFlinger.cpp | 12 ++++++--- media/libmedia/mediaplayer.cpp | 8 +++--- media/libmediaplayerservice/MediaPlayerService.cpp | 12 ++++++--- media/libmediaplayerservice/MediaPlayerService.h | 3 ++- 7 files changed, 49 insertions(+), 27 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 541cb51..6ca499b 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -115,7 +115,7 @@ AudioRecord::~AudioRecord() mAudioRecord.clear(); } IPCThreadState::self()->flushCommands(); - AudioSystem::releaseAudioSessionId(mSessionId); + AudioSystem::releaseAudioSessionId(mSessionId, -1); } } @@ -266,7 +266,7 @@ status_t AudioRecord::set( mMarkerReached = false; mNewPosition = 0; mUpdatePeriod = 0; - AudioSystem::acquireAudioSessionId(mSessionId); + AudioSystem::acquireAudioSessionId(mSessionId, -1); mSequence = 1; mObservedSequence = mSequence; mInOverrun = false; diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 87f4b4c..140fb66 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -435,19 +435,19 @@ int AudioSystem::newAudioSessionId() return af->newAudioSessionId(); } -void AudioSystem::acquireAudioSessionId(int audioSession) +void AudioSystem::acquireAudioSessionId(int audioSession, pid_t pid) { const sp& af = AudioSystem::get_audio_flinger(); if (af != 0) { - af->acquireAudioSessionId(audioSession); + af->acquireAudioSessionId(audioSession, pid); } } -void AudioSystem::releaseAudioSessionId(int audioSession) +void AudioSystem::releaseAudioSessionId(int audioSession, pid_t pid) { const sp& af = AudioSystem::get_audio_flinger(); if (af != 0) { - af->releaseAudioSessionId(audioSession); + af->releaseAudioSessionId(audioSession, pid); } } diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 63eaf1a..5c62260 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -116,7 +116,8 @@ AudioTrack::AudioTrack( int sessionId, transfer_type transferType, const audio_offload_info_t *offloadInfo, - int uid) + int uid, + pid_t pid) : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), @@ -125,7 +126,7 @@ AudioTrack::AudioTrack( mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, - offloadInfo, uid); + offloadInfo, uid, pid); } AudioTrack::AudioTrack( @@ -141,7 +142,8 @@ AudioTrack::AudioTrack( int sessionId, transfer_type transferType, const audio_offload_info_t *offloadInfo, - int uid) + int uid, + pid_t pid) : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), @@ -149,7 +151,8 @@ AudioTrack::AudioTrack( { mStatus = set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags, cbf, user, notificationFrames, - sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, uid); + sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, + uid, pid); } AudioTrack::~AudioTrack() @@ -168,7 +171,9 @@ AudioTrack::~AudioTrack() mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this); mAudioTrack.clear(); IPCThreadState::self()->flushCommands(); - AudioSystem::releaseAudioSessionId(mSessionId); + ALOGV("~AudioTrack, releasing session id from %d on behalf of %d", + IPCThreadState::self()->getCallingPid(), mClientPid); + AudioSystem::releaseAudioSessionId(mSessionId, mClientPid); } } @@ -187,7 +192,8 @@ status_t AudioTrack::set( int sessionId, transfer_type transferType, const audio_offload_info_t *offloadInfo, - int uid) + int uid, + pid_t pid) { switch (transferType) { case TRANSFER_DEFAULT: @@ -335,11 +341,18 @@ status_t AudioTrack::set( mNotificationFramesReq = notificationFrames; mNotificationFramesAct = 0; mSessionId = sessionId; - if (uid == -1 || (IPCThreadState::self()->getCallingPid() != getpid())) { + int callingpid = IPCThreadState::self()->getCallingPid(); + int mypid = getpid(); + if (uid == -1 || (callingpid != mypid)) { mClientUid = IPCThreadState::self()->getCallingUid(); } else { mClientUid = uid; } + if (pid == -1 || (callingpid != mypid)) { + mClientPid = callingpid; + } else { + mClientPid = pid; + } mAuxEffectId = 0; mFlags = flags; mCbf = cbf; @@ -379,7 +392,7 @@ status_t AudioTrack::set( mMarkerReached = false; mNewPosition = 0; mUpdatePeriod = 0; - AudioSystem::acquireAudioSessionId(mSessionId); + AudioSystem::acquireAudioSessionId(mSessionId, mClientPid); mSequence = 1; mObservedSequence = mSequence; mInUnderrun = false; diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index eef6a3d..7b15e68 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -609,19 +609,21 @@ public: return id; } - virtual void acquireAudioSessionId(int audioSession) + virtual void acquireAudioSessionId(int audioSession, int pid) { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInt32(audioSession); + data.writeInt32(pid); remote()->transact(ACQUIRE_AUDIO_SESSION_ID, data, &reply); } - virtual void releaseAudioSessionId(int audioSession) + virtual void releaseAudioSessionId(int audioSession, int pid) { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInt32(audioSession); + data.writeInt32(pid); remote()->transact(RELEASE_AUDIO_SESSION_ID, data, &reply); } @@ -1082,13 +1084,15 @@ status_t BnAudioFlinger::onTransact( case ACQUIRE_AUDIO_SESSION_ID: { CHECK_INTERFACE(IAudioFlinger, data, reply); int audioSession = data.readInt32(); - acquireAudioSessionId(audioSession); + int pid = data.readInt32(); + acquireAudioSessionId(audioSession, pid); return NO_ERROR; } break; case RELEASE_AUDIO_SESSION_ID: { CHECK_INTERFACE(IAudioFlinger, data, reply); int audioSession = data.readInt32(); - releaseAudioSessionId(audioSession); + int pid = data.readInt32(); + releaseAudioSessionId(audioSession, pid); return NO_ERROR; } break; case QUERY_NUM_EFFECTS: { diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 24663ad..d94c7c5 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -58,7 +58,7 @@ MediaPlayer::MediaPlayer() mVideoWidth = mVideoHeight = 0; mLockThreadId = 0; mAudioSessionId = AudioSystem::newAudioSessionId(); - AudioSystem::acquireAudioSessionId(mAudioSessionId); + AudioSystem::acquireAudioSessionId(mAudioSessionId, -1); mSendLevel = 0; mRetransmitEndpointValid = false; } @@ -66,7 +66,7 @@ MediaPlayer::MediaPlayer() MediaPlayer::~MediaPlayer() { ALOGV("destructor"); - AudioSystem::releaseAudioSessionId(mAudioSessionId); + AudioSystem::releaseAudioSessionId(mAudioSessionId, -1); disconnect(); IPCThreadState::self()->flushCommands(); } @@ -576,8 +576,8 @@ status_t MediaPlayer::setAudioSessionId(int sessionId) return BAD_VALUE; } if (sessionId != mAudioSessionId) { - AudioSystem::acquireAudioSessionId(sessionId); - AudioSystem::releaseAudioSessionId(mAudioSessionId); + AudioSystem::acquireAudioSessionId(sessionId, -1); + AudioSystem::releaseAudioSessionId(mAudioSessionId, -1); mAudioSessionId = sessionId; } return NO_ERROR; diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 1f70620..142788d 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -586,7 +586,8 @@ sp MediaPlayerService::Client::setDataSource_pre( } if (!p->hardwareOutput()) { - mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid()); + mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(), + mPid); static_cast(p.get())->setAudioSink(mAudioOutput); } @@ -1299,13 +1300,14 @@ Exit: #undef LOG_TAG #define LOG_TAG "AudioSink" -MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid) +MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid) : mCallback(NULL), mCallbackCookie(NULL), mCallbackData(NULL), mBytesWritten(0), mSessionId(sessionId), mUid(uid), + mPid(pid), mFlags(AUDIO_OUTPUT_FLAG_NONE) { ALOGV("AudioOutput(%d)", sessionId); mStreamType = AUDIO_STREAM_MUSIC; @@ -1554,7 +1556,8 @@ status_t MediaPlayerService::AudioOutput::open( mSessionId, AudioTrack::TRANSFER_CALLBACK, offloadInfo, - mUid); + mUid, + mPid); } else { t = new AudioTrack( mStreamType, @@ -1569,7 +1572,8 @@ status_t MediaPlayerService::AudioOutput::open( mSessionId, AudioTrack::TRANSFER_DEFAULT, NULL, // offload info - mUid); + mUid, + mPid); } if ((t == 0) || (t->initCheck() != NO_ERROR)) { diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index fc355b0..448f27a 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -72,7 +72,7 @@ class MediaPlayerService : public BnMediaPlayerService class CallbackData; public: - AudioOutput(int sessionId, int uid); + AudioOutput(int sessionId, int uid, int pid); virtual ~AudioOutput(); virtual bool ready() const { return mTrack != 0; } @@ -140,6 +140,7 @@ class MediaPlayerService : public BnMediaPlayerService float mMsecsPerFrame; int mSessionId; int mUid; + int mPid; float mSendLevel; int mAuxEffectId; static bool mIsOnEmulator; -- cgit v1.1 From ccb067b1d8424ba610cbd3de83368bd55b532b5b Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Tue, 11 Feb 2014 14:45:59 -0800 Subject: fix the build by fixing more warnings. Change-Id: Ied0ec39eb83b101582702d1e30c21643ccf6353e --- media/libmediaplayerservice/StagefrightRecorder.cpp | 2 +- media/libstagefright/ACodec.cpp | 11 ++++++----- media/libstagefright/tests/SurfaceMediaSource_test.cpp | 3 ++- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index e0eae37..d377acd 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -243,7 +243,7 @@ status_t StagefrightRecorder::setPreviewSurface(const sp return OK; } -status_t StagefrightRecorder::setOutputFile(const char *path) { +status_t StagefrightRecorder::setOutputFile(const char * /* path */) { ALOGE("setOutputFile(const char*) must not be called"); // We don't actually support this at all, as the media_server process // no longer has permissions to create files. diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 4a8c4c4..ac78d6c 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -2967,7 +2967,8 @@ ACodec::BaseState::BaseState(ACodec *codec, const sp &parentState) mCodec(codec) { } -ACodec::BaseState::PortMode ACodec::BaseState::getPortMode(OMX_U32 portIndex) { +ACodec::BaseState::PortMode ACodec::BaseState::getPortMode( + OMX_U32 /* portIndex */) { return KEEP_BUFFERS; } @@ -3376,8 +3377,8 @@ bool ACodec::BaseState::onOMXFillBufferDone( size_t rangeOffset, size_t rangeLength, OMX_U32 flags, int64_t timeUs, - void *platformPrivate, - void *dataPtr) { + void * /* platformPrivate */, + void * /* dataPtr */) { ALOGV("[%s] onOMXFillBufferDone %p time %lld us, flags = 0x%08lx", mCodec->mComponentName.c_str(), bufferID, timeUs, flags); @@ -3910,7 +3911,7 @@ bool ACodec::LoadedState::onConfigureComponent( } void ACodec::LoadedState::onCreateInputSurface( - const sp &msg) { + const sp & /* msg */) { ALOGV("onCreateInputSurface"); sp notify = mCodec->mNotify->dup(); @@ -4154,7 +4155,7 @@ ACodec::ExecutingState::ExecutingState(ACodec *codec) } ACodec::BaseState::PortMode ACodec::ExecutingState::getPortMode( - OMX_U32 portIndex) { + OMX_U32 /* portIndex */) { return RESUBMIT_BUFFERS; } diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp index ddedad7..aeecdbc 100644 --- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp +++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp @@ -527,7 +527,8 @@ void SurfaceMediaSourceTest::oneBufferPass(int width, int height ) { } // Dequeuing and queuing the buffer without really filling it in. -void SurfaceMediaSourceTest::oneBufferPassNoFill(int width, int height ) { +void SurfaceMediaSourceTest::oneBufferPassNoFill( + int /* width */, int /* height */) { ANativeWindowBuffer* anb; ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); ASSERT_TRUE(anb != NULL); -- cgit v1.1 From def582e93022fa5eb7a64d4a11c15598afc0db86 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Tue, 11 Feb 2014 15:59:30 -0800 Subject: fix the OS X builds until we can fix compiler warnings that apparently trigger only on that platform... Change-Id: I9555d7e2efbe3e349e8af60528b7b9d131a257e3 --- media/libstagefright/Android.mk | 2 +- media/libstagefright/codecs/on2/enc/Android.mk | 2 -- media/libstagefright/colorconversion/Android.mk | 2 -- media/libstagefright/omx/Android.mk | 2 -- media/libstagefright/wifi-display/Android.mk | 2 -- 5 files changed, 1 insertion(+), 9 deletions(-) (limited to 'media') diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 1495df0..f94f136 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -112,7 +112,7 @@ LOCAL_SHARED_LIBRARIES += \ libstagefright_foundation \ libdl -LOCAL_CFLAGS += -Wno-multichar -Werror +LOCAL_CFLAGS += -Wno-multichar LOCAL_MODULE:= libstagefright diff --git a/media/libstagefright/codecs/on2/enc/Android.mk b/media/libstagefright/codecs/on2/enc/Android.mk index cbb1a89..4060a0a 100644 --- a/media/libstagefright/codecs/on2/enc/Android.mk +++ b/media/libstagefright/codecs/on2/enc/Android.mk @@ -26,6 +26,4 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE := libstagefright_soft_vpxenc LOCAL_MODULE_TAGS := optional -LOCAL_CFLAGS += -Werror - include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk index 1c90957..59a64ba 100644 --- a/media/libstagefright/colorconversion/Android.mk +++ b/media/libstagefright/colorconversion/Android.mk @@ -11,6 +11,4 @@ LOCAL_C_INCLUDES := \ LOCAL_MODULE:= libstagefright_color_conversion -LOCAL_CFLAGS += -Werror - include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk index 37b289f..cd912e7 100644 --- a/media/libstagefright/omx/Android.mk +++ b/media/libstagefright/omx/Android.mk @@ -16,8 +16,6 @@ LOCAL_C_INCLUDES += \ $(TOP)/frameworks/native/include/media/hardware \ $(TOP)/frameworks/native/include/media/openmax -LOCAL_CFLAGS += -Werror - LOCAL_SHARED_LIBRARIES := \ libbinder \ libmedia \ diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk index 3f47bfb..f70454a 100644 --- a/media/libstagefright/wifi-display/Android.mk +++ b/media/libstagefright/wifi-display/Android.mk @@ -19,8 +19,6 @@ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/native/include/media/openmax \ $(TOP)/frameworks/av/media/libstagefright/mpeg2ts \ -LOCAL_CFLAGS += -Werror - LOCAL_SHARED_LIBRARIES:= \ libbinder \ libcutils \ -- cgit v1.1 From e59b77ab4c6b4ee8b7338d7eccd4a6c5fac834e7 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Wed, 12 Feb 2014 08:51:09 -0800 Subject: Fix warnings (now errors) in YUVImage.cpp related-to-build Change-Id: Ib29d78c4ca176fe66bfe5881f24127843b95c3f8 --- media/libstagefright/yuv/YUVImage.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libstagefright/yuv/YUVImage.cpp b/media/libstagefright/yuv/YUVImage.cpp index 7b9000b..bb3e2fd 100644 --- a/media/libstagefright/yuv/YUVImage.cpp +++ b/media/libstagefright/yuv/YUVImage.cpp @@ -226,8 +226,8 @@ void YUVImage::fastCopyRectangle420Planar( &ySrcOffsetIncrement, &uSrcOffsetIncrement, &vSrcOffsetIncrement); int32_t yDestOffsetIncrement; - int32_t uDestOffsetIncrement; - int32_t vDestOffsetIncrement; + int32_t uDestOffsetIncrement = 0; + int32_t vDestOffsetIncrement = 0; destImage.getOffsetIncrementsPerDataRow( &yDestOffsetIncrement, &uDestOffsetIncrement, &vDestOffsetIncrement); @@ -309,7 +309,7 @@ void YUVImage::fastCopyRectangle420SemiPlanar( int32_t yDestOffsetIncrement; int32_t uDestOffsetIncrement; - int32_t vDestOffsetIncrement; + int32_t vDestOffsetIncrement = 0; destImage.getOffsetIncrementsPerDataRow( &yDestOffsetIncrement, &uDestOffsetIncrement, &vDestOffsetIncrement); @@ -393,9 +393,9 @@ bool YUVImage::writeToPPM(const char *filename) const { fprintf(fp, "255\n"); for (int32_t y = 0; y < mHeight; ++y) { for (int32_t x = 0; x < mWidth; ++x) { - uint8_t yValue; - uint8_t uValue; - uint8_t vValue; + uint8_t yValue = 0u; + uint8_t uValue = 0u; + uint8_t vValue = 0u; getPixelValue(x, y, &yValue, &uValue, & vValue); uint8_t rValue; -- cgit v1.1 From 442cc6dc48f8188e097617f7f804c314a9dacd0e Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Wed, 12 Feb 2014 09:48:48 -0800 Subject: Even more warnings (now errors) fixed to unbreak the sdk-x86 build(s). Change-Id: Ib4a5ab1a9e50fe9e7747a907f8b4a8c207099fdb --- media/libstagefright/MPEG4Extractor.cpp | 2 +- media/libstagefright/codecs/amrwbenc/src/pitch_f4.c | 3 +++ media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp | 2 +- media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 570d417..4756b3e 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -3735,7 +3735,7 @@ status_t MPEG4Source::fragmentedRead( } off64_t offset = 0; - size_t size; + size_t size = 0; uint32_t cts = 0; bool isSyncSample = false; bool newBuffer = false; diff --git a/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c b/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c index 0d66c31..b66b55e 100644 --- a/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c +++ b/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c @@ -31,6 +31,8 @@ #define UP_SAMP 4 #define L_INTERPOL1 4 +#define UNUSED(x) (void)(x) + /* Local functions */ #ifdef ASM_OPT @@ -171,6 +173,7 @@ static void Norm_Corr( Word32 corr, exp_corr, norm, exp, scale; Word16 exp_norm, excf[L_SUBFR], tmp; Word32 L_tmp, L_tmp1, L_tmp2; + UNUSED(L_subfr); /* compute the filtered excitation for the first delay t_min */ k = -t_min; diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp index 1104e54..a15b040 100644 --- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp +++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp @@ -801,7 +801,7 @@ void SoftAVCEncoder::onQueueFilled(OMX_U32 /* portIndex */) { } } - buffer_handle_t srcBuffer; // for MetaDataMode only + buffer_handle_t srcBuffer = NULL; // for MetaDataMode only // Get next input video frame if (mReadyForNextFrame) { diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp index c084277..2c73e57 100644 --- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp +++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp @@ -677,7 +677,7 @@ void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { mSawInputEOS = true; } - buffer_handle_t srcBuffer; // for MetaDataMode only + buffer_handle_t srcBuffer = NULL; // for MetaDataMode only if (inHeader->nFilledLen > 0) { uint8_t *inputData = NULL; if (mStoreMetaDataInBuffers) { -- cgit v1.1 From 85fcbd6aec4eab3368e9266be0a1151a081f204d Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 13 Feb 2014 13:17:54 -0800 Subject: Try not to have sample durations vary too much Change-Id: Ibbd0f0a253cc74e241236b7a30d1c931e18af753 --- media/libstagefright/MPEG4Writer.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'media') diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index ff6feb9..f689d7e 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -2278,6 +2278,22 @@ status_t MPEG4Writer::Track::threadEntry() { return UNKNOWN_ERROR; } + // if the duration is different for this sample, see if it is close enough to the previous + // duration that we can fudge it and use the same value, to avoid filling the stts table + // with lots of near-identical entries. + // "close enough" here means that the current duration needs to be adjusted by less + // than 0.1 milliseconds + if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) { + int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL + + (mTimeScale / 2)) / mTimeScale; + if (deltaUs > -100 && deltaUs < 100) { + // use previous ticks, and adjust timestamp as if it was actually that number + // of ticks + currDurationTicks = lastDurationTicks; + timestampUs += deltaUs; + } + } + mStszTableEntries->add(htonl(sampleSize)); if (mStszTableEntries->count() > 2) { -- cgit v1.1 From 240abcc4bf661a10ffca24859945796acc76ac6e Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Thu, 13 Feb 2014 13:32:37 -0800 Subject: Remove unused FragmentedMP4Parser and friends. The functionality has been subsumed into MP4Extractor. Change-Id: Ic1b6445660adfb985c604f1ca6f0c86585f8de04 --- media/libmediaplayerservice/nuplayer/Android.mk | 1 - media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 11 +- .../nuplayer/mp4/MP4Source.cpp | 144 -- .../libmediaplayerservice/nuplayer/mp4/MP4Source.h | 53 - media/libstagefright/Android.mk | 2 - media/libstagefright/include/FragmentedMP4Parser.h | 274 --- media/libstagefright/mp4/FragmentedMP4Parser.cpp | 2001 -------------------- media/libstagefright/mp4/TrackFragment.cpp | 379 ---- media/libstagefright/mp4/TrackFragment.h | 122 -- 9 files changed, 1 insertion(+), 2986 deletions(-) delete mode 100644 media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp delete mode 100644 media/libmediaplayerservice/nuplayer/mp4/MP4Source.h delete mode 100644 media/libstagefright/include/FragmentedMP4Parser.h delete mode 100644 media/libstagefright/mp4/FragmentedMP4Parser.cpp delete mode 100644 media/libstagefright/mp4/TrackFragment.cpp delete mode 100644 media/libstagefright/mp4/TrackFragment.h (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk index f946c1c..f97ba57 100644 --- a/media/libmediaplayerservice/nuplayer/Android.mk +++ b/media/libmediaplayerservice/nuplayer/Android.mk @@ -11,7 +11,6 @@ LOCAL_SRC_FILES:= \ NuPlayerStreamListener.cpp \ RTSPSource.cpp \ StreamingSource.cpp \ - mp4/MP4Source.cpp \ LOCAL_C_INCLUDES := \ $(TOP)/frameworks/av/media/libstagefright/httplive \ diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 01e59c8..d47ac98 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -28,13 +28,11 @@ #include "RTSPSource.h" #include "StreamingSource.h" #include "GenericSource.h" -#include "mp4/MP4Source.h" #include "ATSParser.h" #include "SoftwareRenderer.h" -#include // for property_get #include #include #include @@ -183,14 +181,7 @@ void NuPlayer::setDataSourceAsync(const sp &source) { sp notify = new AMessage(kWhatSourceNotify, id()); - char prop[PROPERTY_VALUE_MAX]; - if (property_get("media.stagefright.use-mp4source", prop, NULL) - && (!strcmp(prop, "1") || !strcasecmp(prop, "true"))) { - msg->setObject("source", new MP4Source(notify, source)); - } else { - msg->setObject("source", new StreamingSource(notify, source)); - } - + msg->setObject("source", new StreamingSource(notify, source)); msg->post(); } diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp deleted file mode 100644 index 2aae4dd..0000000 --- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2012 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 "MP4Source.h" - -#include "FragmentedMP4Parser.h" -#include "../NuPlayerStreamListener.h" - -#include -#include -#include -#include - -namespace android { - -struct StreamSource : public FragmentedMP4Parser::Source { - StreamSource(const sp &source) - : mListener(new NuPlayer::NuPlayerStreamListener(source, 0)), - mPosition(0) { - mListener->start(); - } - - virtual ssize_t readAt(off64_t offset, void *data, size_t size) { - if (offset < mPosition) { - return -EPIPE; - } - - while (offset > mPosition) { - char buffer[1024]; - off64_t skipBytes = offset - mPosition; - if (skipBytes > sizeof(buffer)) { - skipBytes = sizeof(buffer); - } - - sp extra; - ssize_t n; - for (;;) { - n = mListener->read(buffer, skipBytes, &extra); - - if (n == -EWOULDBLOCK) { - usleep(10000); - continue; - } - - break; - } - - ALOGV("skipped %ld bytes at offset %lld", n, mPosition); - - if (n < 0) { - return n; - } - - mPosition += n; - } - - sp extra; - size_t total = 0; - while (total < size) { - ssize_t n = mListener->read( - (uint8_t *)data + total, size - total, &extra); - - if (n == -EWOULDBLOCK) { - usleep(10000); - continue; - } else if (n == 0) { - break; - } else if (n < 0) { - mPosition += total; - return n; - } - - total += n; - } - - ALOGV("read %ld bytes at offset %lld", total, mPosition); - - mPosition += total; - - return total; - } - - bool isSeekable() { - return false; - } - -private: - sp mListener; - off64_t mPosition; - - DISALLOW_EVIL_CONSTRUCTORS(StreamSource); -}; - -MP4Source::MP4Source( - const sp ¬ify, const sp &source) - : Source(notify), - mSource(source), - mLooper(new ALooper), - mParser(new FragmentedMP4Parser), - mEOS(false) { - mLooper->registerHandler(mParser); -} - -MP4Source::~MP4Source() { -} - -void MP4Source::prepareAsync() { - notifyVideoSizeChanged(0, 0); - notifyFlagsChanged(0); - notifyPrepared(); -} - -void MP4Source::start() { - mLooper->start(false /* runOnCallingThread */); - mParser->start(new StreamSource(mSource)); -} - -status_t MP4Source::feedMoreTSData() { - return mEOS ? ERROR_END_OF_STREAM : (status_t)OK; -} - -sp MP4Source::getFormat(bool audio) { - return mParser->getFormat(audio); -} - -status_t MP4Source::dequeueAccessUnit( - bool audio, sp *accessUnit) { - return mParser->dequeueAccessUnit(audio, accessUnit); -} - -} // namespace android diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h deleted file mode 100644 index a6ef622..0000000 --- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2012 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 MP4_SOURCE_H -#define MP4_SOURCE_H - -#include "NuPlayerSource.h" - -namespace android { - -struct FragmentedMP4Parser; - -struct MP4Source : public NuPlayer::Source { - MP4Source(const sp ¬ify, const sp &source); - - virtual void prepareAsync(); - virtual void start(); - - virtual status_t feedMoreTSData(); - - virtual sp getFormat(bool audio); - - virtual status_t dequeueAccessUnit( - bool audio, sp *accessUnit); - -protected: - virtual ~MP4Source(); - -private: - sp mSource; - sp mLooper; - sp mParser; - bool mEOS; - - DISALLOW_EVIL_CONSTRUCTORS(MP4Source); -}; - -} // namespace android - -#endif // MP4_SOURCE_H diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index f94f136..0636dcc 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -58,8 +58,6 @@ LOCAL_SRC_FILES:= \ WVMExtractor.cpp \ XINGSeeker.cpp \ avc_utils.cpp \ - mp4/FragmentedMP4Parser.cpp \ - mp4/TrackFragment.cpp \ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/av/include/media/stagefright/timedtext \ diff --git a/media/libstagefright/include/FragmentedMP4Parser.h b/media/libstagefright/include/FragmentedMP4Parser.h deleted file mode 100644 index dbe02b8..0000000 --- a/media/libstagefright/include/FragmentedMP4Parser.h +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (C) 2012 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 PARSER_H_ - -#define PARSER_H_ - -#include -#include -#include - -namespace android { - -struct ABuffer; - -struct FragmentedMP4Parser : public AHandler { - struct Source : public RefBase { - Source() {} - - virtual ssize_t readAt(off64_t offset, void *data, size_t size) = 0; - virtual bool isSeekable() = 0; - - protected: - virtual ~Source() {} - - private: - DISALLOW_EVIL_CONSTRUCTORS(Source); - }; - - FragmentedMP4Parser(); - - void start(const char *filename); - void start(const sp &source); - void start(sp &source); - - sp getFormat(bool audio, bool synchronous = false); - status_t dequeueAccessUnit(bool audio, sp *accessUnit, bool synchronous = false); - status_t seekTo(bool audio, int64_t timeUs); - bool isSeekable() const; - - virtual void onMessageReceived(const sp &msg); - -protected: - virtual ~FragmentedMP4Parser(); - -private: - enum { - kWhatStart, - kWhatProceed, - kWhatReadMore, - kWhatGetFormat, - kWhatDequeueAccessUnit, - kWhatSeekTo, - }; - - struct TrackFragment; - struct DynamicTrackFragment; - struct StaticTrackFragment; - - struct DispatchEntry { - uint32_t mType; - uint32_t mParentType; - status_t (FragmentedMP4Parser::*mHandler)(uint32_t, size_t, uint64_t); - }; - - struct Container { - uint64_t mOffset; - uint64_t mBytesRemaining; - uint32_t mType; - bool mExtendsToEOF; - }; - - struct SampleDescription { - uint32_t mType; - uint16_t mDataRefIndex; - - sp mFormat; - }; - - struct SampleInfo { - off64_t mOffset; - size_t mSize; - uint32_t mPresentationTime; - size_t mSampleDescIndex; - uint32_t mFlags; - }; - - struct MediaDataInfo { - sp mBuffer; - off64_t mOffset; - }; - - struct SidxEntry { - size_t mSize; - uint32_t mDurationUs; - }; - - struct TrackInfo { - enum Flags { - kTrackEnabled = 0x01, - kTrackInMovie = 0x02, - kTrackInPreview = 0x04, - }; - - uint32_t mTrackID; - uint32_t mFlags; - uint32_t mDuration; // This is the duration in terms of movie timescale! - uint64_t mSidxDuration; // usec, from sidx box, which can use a different timescale - - uint32_t mMediaTimeScale; - - uint32_t mMediaHandlerType; - Vector mSampleDescs; - - // from track extends: - uint32_t mDefaultSampleDescriptionIndex; - uint32_t mDefaultSampleDuration; - uint32_t mDefaultSampleSize; - uint32_t mDefaultSampleFlags; - - uint32_t mDecodingTime; - - Vector mSidx; - sp mStaticFragment; - List > mFragments; - }; - - struct TrackFragmentHeaderInfo { - enum Flags { - kBaseDataOffsetPresent = 0x01, - kSampleDescriptionIndexPresent = 0x02, - kDefaultSampleDurationPresent = 0x08, - kDefaultSampleSizePresent = 0x10, - kDefaultSampleFlagsPresent = 0x20, - kDurationIsEmpty = 0x10000, - }; - - uint32_t mTrackID; - uint32_t mFlags; - uint64_t mBaseDataOffset; - uint32_t mSampleDescriptionIndex; - uint32_t mDefaultSampleDuration; - uint32_t mDefaultSampleSize; - uint32_t mDefaultSampleFlags; - - uint64_t mDataOffset; - }; - - static const DispatchEntry kDispatchTable[]; - - sp mSource; - off_t mBufferPos; - bool mSuspended; - bool mDoneWithMoov; - off_t mFirstMoofOffset; // used as the starting point for offsets calculated from the sidx box - sp mBuffer; - Vector mStack; - KeyedVector mTracks; // TrackInfo by trackID - Vector mMediaData; - - uint32_t mCurrentTrackID; - - status_t mFinalResult; - - TrackFragmentHeaderInfo mTrackFragmentHeaderInfo; - - status_t onProceed(); - status_t onDequeueAccessUnit(size_t trackIndex, sp *accessUnit); - status_t onSeekTo(bool wantAudio, int64_t position); - - void enter(off64_t offset, uint32_t type, uint64_t size); - - uint16_t readU16(size_t offset); - uint32_t readU32(size_t offset); - uint64_t readU64(size_t offset); - void skip(off_t distance); - status_t need(size_t size); - bool fitsContainer(uint64_t size) const; - - status_t parseTrackHeader( - uint32_t type, size_t offset, uint64_t size); - - status_t parseMediaHeader( - uint32_t type, size_t offset, uint64_t size); - - status_t parseMediaHandler( - uint32_t type, size_t offset, uint64_t size); - - status_t parseTrackExtends( - uint32_t type, size_t offset, uint64_t size); - - status_t parseTrackFragmentHeader( - uint32_t type, size_t offset, uint64_t size); - - status_t parseTrackFragmentRun( - uint32_t type, size_t offset, uint64_t size); - - status_t parseVisualSampleEntry( - uint32_t type, size_t offset, uint64_t size); - - status_t parseAudioSampleEntry( - uint32_t type, size_t offset, uint64_t size); - - status_t parseSampleSizes( - uint32_t type, size_t offset, uint64_t size); - - status_t parseCompactSampleSizes( - uint32_t type, size_t offset, uint64_t size); - - status_t parseSampleToChunk( - uint32_t type, size_t offset, uint64_t size); - - status_t parseChunkOffsets( - uint32_t type, size_t offset, uint64_t size); - - status_t parseChunkOffsets64( - uint32_t type, size_t offset, uint64_t size); - - status_t parseAVCCodecSpecificData( - uint32_t type, size_t offset, uint64_t size); - - status_t parseESDSCodecSpecificData( - uint32_t type, size_t offset, uint64_t size); - - status_t parseMediaData( - uint32_t type, size_t offset, uint64_t size); - - status_t parseSegmentIndex( - uint32_t type, size_t offset, uint64_t size); - - TrackInfo *editTrack(uint32_t trackID, bool createIfNecessary = false); - - ssize_t findTrack(bool wantAudio) const; - - status_t makeAccessUnit( - TrackInfo *info, - const SampleInfo &sample, - const MediaDataInfo &mdatInfo, - sp *accessUnit); - - status_t getSample( - TrackInfo *info, - sp *fragment, - SampleInfo *sampleInfo); - - static int CompareSampleLocation( - const SampleInfo &sample, const MediaDataInfo &mdatInfo); - - void resumeIfNecessary(); - - void copyBuffer( - sp *dst, - size_t offset, uint64_t size) const; - - DISALLOW_EVIL_CONSTRUCTORS(FragmentedMP4Parser); -}; - -} // namespace android - -#endif // PARSER_H_ - diff --git a/media/libstagefright/mp4/FragmentedMP4Parser.cpp b/media/libstagefright/mp4/FragmentedMP4Parser.cpp deleted file mode 100644 index 0639bec..0000000 --- a/media/libstagefright/mp4/FragmentedMP4Parser.cpp +++ /dev/null @@ -1,2001 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "FragmentedMP4Parser" -#include - -#include "include/avc_utils.h" -#include "include/ESDS.h" -#include "include/FragmentedMP4Parser.h" -#include "TrackFragment.h" - - -#include -#include -#include -#include -#include -#include -#include - -#if LOG_NDEBUG -#define UNUSED_UNLESS_VERBOSE(x) (void)(x) -#else -#define UNUSED_UNLESS_VERBOSE(x) -#endif - -namespace android { - -static const char *Fourcc2String(uint32_t fourcc) { - static char buffer[5]; - buffer[4] = '\0'; - buffer[0] = fourcc >> 24; - buffer[1] = (fourcc >> 16) & 0xff; - buffer[2] = (fourcc >> 8) & 0xff; - buffer[3] = fourcc & 0xff; - - return buffer; -} - -static const char *IndentString(size_t n) { - static const char kSpace[] = " "; - return kSpace + sizeof(kSpace) - 2 * n - 1; -} - -// static -const FragmentedMP4Parser::DispatchEntry FragmentedMP4Parser::kDispatchTable[] = { - { FOURCC('m', 'o', 'o', 'v'), 0, NULL }, - { FOURCC('t', 'r', 'a', 'k'), FOURCC('m', 'o', 'o', 'v'), NULL }, - { FOURCC('u', 'd', 't', 'a'), FOURCC('t', 'r', 'a', 'k'), NULL }, - { FOURCC('u', 'd', 't', 'a'), FOURCC('m', 'o', 'o', 'v'), NULL }, - { FOURCC('m', 'e', 't', 'a'), FOURCC('u', 'd', 't', 'a'), NULL }, - { FOURCC('i', 'l', 's', 't'), FOURCC('m', 'e', 't', 'a'), NULL }, - - { FOURCC('t', 'k', 'h', 'd'), FOURCC('t', 'r', 'a', 'k'), - &FragmentedMP4Parser::parseTrackHeader - }, - - { FOURCC('m', 'v', 'e', 'x'), FOURCC('m', 'o', 'o', 'v'), NULL }, - - { FOURCC('t', 'r', 'e', 'x'), FOURCC('m', 'v', 'e', 'x'), - &FragmentedMP4Parser::parseTrackExtends - }, - - { FOURCC('e', 'd', 't', 's'), FOURCC('t', 'r', 'a', 'k'), NULL }, - { FOURCC('m', 'd', 'i', 'a'), FOURCC('t', 'r', 'a', 'k'), NULL }, - - { FOURCC('m', 'd', 'h', 'd'), FOURCC('m', 'd', 'i', 'a'), - &FragmentedMP4Parser::parseMediaHeader - }, - - { FOURCC('h', 'd', 'l', 'r'), FOURCC('m', 'd', 'i', 'a'), - &FragmentedMP4Parser::parseMediaHandler - }, - - { FOURCC('m', 'i', 'n', 'f'), FOURCC('m', 'd', 'i', 'a'), NULL }, - { FOURCC('d', 'i', 'n', 'f'), FOURCC('m', 'i', 'n', 'f'), NULL }, - { FOURCC('s', 't', 'b', 'l'), FOURCC('m', 'i', 'n', 'f'), NULL }, - { FOURCC('s', 't', 's', 'd'), FOURCC('s', 't', 'b', 'l'), NULL }, - - { FOURCC('s', 't', 's', 'z'), FOURCC('s', 't', 'b', 'l'), - &FragmentedMP4Parser::parseSampleSizes }, - - { FOURCC('s', 't', 'z', '2'), FOURCC('s', 't', 'b', 'l'), - &FragmentedMP4Parser::parseCompactSampleSizes }, - - { FOURCC('s', 't', 's', 'c'), FOURCC('s', 't', 'b', 'l'), - &FragmentedMP4Parser::parseSampleToChunk }, - - { FOURCC('s', 't', 'c', 'o'), FOURCC('s', 't', 'b', 'l'), - &FragmentedMP4Parser::parseChunkOffsets }, - - { FOURCC('c', 'o', '6', '4'), FOURCC('s', 't', 'b', 'l'), - &FragmentedMP4Parser::parseChunkOffsets64 }, - - { FOURCC('a', 'v', 'c', 'C'), FOURCC('a', 'v', 'c', '1'), - &FragmentedMP4Parser::parseAVCCodecSpecificData }, - - { FOURCC('e', 's', 'd', 's'), FOURCC('m', 'p', '4', 'a'), - &FragmentedMP4Parser::parseESDSCodecSpecificData }, - - { FOURCC('e', 's', 'd', 's'), FOURCC('m', 'p', '4', 'v'), - &FragmentedMP4Parser::parseESDSCodecSpecificData }, - - { FOURCC('m', 'd', 'a', 't'), 0, &FragmentedMP4Parser::parseMediaData }, - - { FOURCC('m', 'o', 'o', 'f'), 0, NULL }, - { FOURCC('t', 'r', 'a', 'f'), FOURCC('m', 'o', 'o', 'f'), NULL }, - - { FOURCC('t', 'f', 'h', 'd'), FOURCC('t', 'r', 'a', 'f'), - &FragmentedMP4Parser::parseTrackFragmentHeader - }, - { FOURCC('t', 'r', 'u', 'n'), FOURCC('t', 'r', 'a', 'f'), - &FragmentedMP4Parser::parseTrackFragmentRun - }, - - { FOURCC('m', 'f', 'r', 'a'), 0, NULL }, - - { FOURCC('s', 'i', 'd', 'x'), 0, &FragmentedMP4Parser::parseSegmentIndex }, -}; - -struct FileSource : public FragmentedMP4Parser::Source { - FileSource(const char *filename) - : mFile(fopen(filename, "rb")) { - CHECK(mFile != NULL); - } - - virtual ~FileSource() { - fclose(mFile); - } - - virtual ssize_t readAt(off64_t offset, void *data, size_t size) { - fseek(mFile, offset, SEEK_SET); - return fread(data, 1, size, mFile); - } - - virtual bool isSeekable() { - return true; - } - - private: - FILE *mFile; - - DISALLOW_EVIL_CONSTRUCTORS(FileSource); -}; - -struct ReadTracker : public RefBase { - ReadTracker(off64_t size) { - allocSize = 1 + size / 8192; // 1 bit per kilobyte - bitmap = (char*) calloc(1, allocSize); - } - virtual ~ReadTracker() { - dumpToLog(); - free(bitmap); - } - void mark(off64_t offset, size_t size) { - int firstbit = offset / 1024; - int lastbit = (offset + size - 1) / 1024; - for (int i = firstbit; i <= lastbit; i++) { - bitmap[i/8] |= (0x80 >> (i & 7)); - } - } - - private: - void dumpToLog() { - // 96 chars per line, each char represents one kilobyte, 1 kb per bit - int numlines = allocSize / 12; - char buf[97]; - char *cur = bitmap; - for (int i = 0; i < numlines; i++ && cur) { - for (int j = 0; j < 12; j++) { - for (int k = 0; k < 8; k++) { - buf[(j * 8) + k] = (*cur & (0x80 >> k)) ? 'X' : '.'; - } - cur++; - } - buf[96] = '\0'; - ALOGI("%5dk: %s", i * 96, buf); - } - } - - size_t allocSize; - char *bitmap; -}; - -struct DataSourceSource : public FragmentedMP4Parser::Source { - DataSourceSource(sp &source) - : mDataSource(source) { - CHECK(mDataSource != NULL); -#if 0 - off64_t size; - if (source->getSize(&size) == OK) { - mReadTracker = new ReadTracker(size); - } else { - ALOGE("couldn't get data source size"); - } -#endif - } - - virtual ssize_t readAt(off64_t offset, void *data, size_t size) { - if (mReadTracker != NULL) { - mReadTracker->mark(offset, size); - } - return mDataSource->readAt(offset, data, size); - } - - virtual bool isSeekable() { - return true; - } - - private: - sp mDataSource; - sp mReadTracker; - - DISALLOW_EVIL_CONSTRUCTORS(DataSourceSource); -}; - -FragmentedMP4Parser::FragmentedMP4Parser() - : mBufferPos(0), - mSuspended(false), - mDoneWithMoov(false), - mFirstMoofOffset(0), - mFinalResult(OK) { -} - -FragmentedMP4Parser::~FragmentedMP4Parser() { -} - -void FragmentedMP4Parser::start(const char *filename) { - sp msg = new AMessage(kWhatStart, id()); - msg->setObject("source", new FileSource(filename)); - msg->post(); - ALOGV("Parser::start(%s)", filename); -} - -void FragmentedMP4Parser::start(const sp &source) { - sp msg = new AMessage(kWhatStart, id()); - msg->setObject("source", source); - msg->post(); - ALOGV("Parser::start(Source)"); -} - -void FragmentedMP4Parser::start(sp &source) { - sp msg = new AMessage(kWhatStart, id()); - msg->setObject("source", new DataSourceSource(source)); - msg->post(); - ALOGV("Parser::start(DataSource)"); -} - -sp FragmentedMP4Parser::getFormat(bool audio, bool synchronous) { - - while (true) { - bool moovDone = mDoneWithMoov; - sp msg = new AMessage(kWhatGetFormat, id()); - msg->setInt32("audio", audio); - - sp response; - status_t err = msg->postAndAwaitResponse(&response); - - if (err != OK) { - ALOGV("getFormat post failed: %d", err); - return NULL; - } - - if (response->findInt32("err", &err) && err != OK) { - if (synchronous && err == -EWOULDBLOCK && !moovDone) { - resumeIfNecessary(); - ALOGV("@getFormat parser not ready yet, retrying"); - usleep(10000); - continue; - } - ALOGV("getFormat failed: %d", err); - return NULL; - } - - sp format; - CHECK(response->findMessage("format", &format)); - - ALOGV("returning format %s", format->debugString().c_str()); - return format; - } -} - -status_t FragmentedMP4Parser::seekTo(bool wantAudio, int64_t timeUs) { - sp msg = new AMessage(kWhatSeekTo, id()); - msg->setInt32("audio", wantAudio); - msg->setInt64("position", timeUs); - - sp response; - status_t err = msg->postAndAwaitResponse(&response); - return err; -} - -bool FragmentedMP4Parser::isSeekable() const { - while (mFirstMoofOffset == 0 && mFinalResult == OK) { - usleep(10000); - } - bool seekable = mSource->isSeekable(); - for (size_t i = 0; seekable && i < mTracks.size(); i++) { - const TrackInfo *info = &mTracks.valueAt(i); - seekable &= !info->mSidx.empty(); - } - return seekable; -} - -status_t FragmentedMP4Parser::onSeekTo(bool wantAudio, int64_t position) { - status_t err = -EINVAL; - ssize_t trackIndex = findTrack(wantAudio); - if (trackIndex < 0) { - err = trackIndex; - } else { - TrackInfo *info = &mTracks.editValueAt(trackIndex); - - int numSidxEntries = info->mSidx.size(); - int64_t totalTime = 0; - off_t totalOffset = mFirstMoofOffset; - for (int i = 0; i < numSidxEntries; i++) { - const SidxEntry *se = &info->mSidx[i]; - if (totalTime + se->mDurationUs > position) { - mBuffer->setRange(0,0); - mBufferPos = totalOffset; - if (mFinalResult == ERROR_END_OF_STREAM) { - mFinalResult = OK; - mSuspended = true; // force resume - resumeIfNecessary(); - } - info->mFragments.clear(); - info->mDecodingTime = totalTime * info->mMediaTimeScale / 1000000ll; - return OK; - } - totalTime += se->mDurationUs; - totalOffset += se->mSize; - } - } - ALOGV("seekTo out of range"); - return err; -} - -status_t FragmentedMP4Parser::dequeueAccessUnit(bool audio, sp *accessUnit, - bool synchronous) { - - while (true) { - sp msg = new AMessage(kWhatDequeueAccessUnit, id()); - msg->setInt32("audio", audio); - - sp response; - status_t err = msg->postAndAwaitResponse(&response); - - if (err != OK) { - ALOGV("dequeue fail 1: %d", err); - return err; - } - - if (response->findInt32("err", &err) && err != OK) { - if (synchronous && err == -EWOULDBLOCK) { - resumeIfNecessary(); - ALOGV("Parser not ready yet, retrying"); - usleep(10000); - continue; - } - ALOGV("dequeue fail 2: %d, %d", err, synchronous); - return err; - } - - CHECK(response->findBuffer("accessUnit", accessUnit)); - - return OK; - } -} - -ssize_t FragmentedMP4Parser::findTrack(bool wantAudio) const { - for (size_t i = 0; i < mTracks.size(); ++i) { - const TrackInfo *info = &mTracks.valueAt(i); - - bool isAudio = - info->mMediaHandlerType == FOURCC('s', 'o', 'u', 'n'); - - bool isVideo = - info->mMediaHandlerType == FOURCC('v', 'i', 'd', 'e'); - - if ((wantAudio && isAudio) || (!wantAudio && !isAudio)) { - if (info->mSampleDescs.empty()) { - break; - } - - return i; - } - } - - return -EWOULDBLOCK; -} - -void FragmentedMP4Parser::onMessageReceived(const sp &msg) { - switch (msg->what()) { - case kWhatStart: - { - sp obj; - CHECK(msg->findObject("source", &obj)); - - mSource = static_cast(obj.get()); - - mBuffer = new ABuffer(512 * 1024); - mBuffer->setRange(0, 0); - - enter(0ll, 0, 0); - - (new AMessage(kWhatProceed, id()))->post(); - break; - } - - case kWhatProceed: - { - CHECK(!mSuspended); - - status_t err = onProceed(); - - if (err == OK) { - if (!mSuspended) { - msg->post(); - } - } else if (err != -EAGAIN) { - ALOGE("onProceed returned error %d", err); - } - - break; - } - - case kWhatReadMore: - { - size_t needed; - CHECK(msg->findSize("needed", &needed)); - - memmove(mBuffer->base(), mBuffer->data(), mBuffer->size()); - mBufferPos += mBuffer->offset(); - mBuffer->setRange(0, mBuffer->size()); - - size_t maxBytesToRead = mBuffer->capacity() - mBuffer->size(); - - if (maxBytesToRead < needed) { - ALOGV("resizing buffer."); - - sp newBuffer = - new ABuffer((mBuffer->size() + needed + 1023) & ~1023); - memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size()); - newBuffer->setRange(0, mBuffer->size()); - - mBuffer = newBuffer; - maxBytesToRead = mBuffer->capacity() - mBuffer->size(); - } - - CHECK_GE(maxBytesToRead, needed); - - ssize_t n = mSource->readAt( - mBufferPos + mBuffer->size(), - mBuffer->data() + mBuffer->size(), needed); - - if (n < (ssize_t)needed) { - ALOGV("Reached EOF when reading %d @ %ld + %zu", - needed, mBufferPos, mBuffer->size()); - - if (n < 0) { - mFinalResult = n; - } else if (n == 0) { - mFinalResult = ERROR_END_OF_STREAM; - } else { - mFinalResult = ERROR_IO; - } - } else { - mBuffer->setRange(0, mBuffer->size() + n); - (new AMessage(kWhatProceed, id()))->post(); - } - - break; - } - - case kWhatGetFormat: - { - int32_t wantAudio; - CHECK(msg->findInt32("audio", &wantAudio)); - - status_t err = -EWOULDBLOCK; - sp response = new AMessage; - - ssize_t trackIndex = findTrack(wantAudio); - - if (trackIndex < 0) { - err = trackIndex; - } else { - TrackInfo *info = &mTracks.editValueAt(trackIndex); - - sp format = info->mSampleDescs.itemAt(0).mFormat; - if (info->mSidxDuration) { - format->setInt64("durationUs", info->mSidxDuration); - } else { - // this is probably going to be zero. Oh well... - format->setInt64("durationUs", - 1000000ll * info->mDuration / info->mMediaTimeScale); - } - response->setMessage( - "format", format); - - err = OK; - } - - response->setInt32("err", err); - - uint32_t replyID; - CHECK(msg->senderAwaitsResponse(&replyID)); - - response->postReply(replyID); - break; - } - - case kWhatDequeueAccessUnit: - { - int32_t wantAudio; - CHECK(msg->findInt32("audio", &wantAudio)); - - status_t err = -EWOULDBLOCK; - sp response = new AMessage; - - ssize_t trackIndex = findTrack(wantAudio); - - if (trackIndex < 0) { - err = trackIndex; - } else { - sp accessUnit; - err = onDequeueAccessUnit(trackIndex, &accessUnit); - - if (err == OK) { - response->setBuffer("accessUnit", accessUnit); - } - } - - response->setInt32("err", err); - - uint32_t replyID; - CHECK(msg->senderAwaitsResponse(&replyID)); - - response->postReply(replyID); - break; - } - - case kWhatSeekTo: - { - ALOGV("kWhatSeekTo"); - int32_t wantAudio; - CHECK(msg->findInt32("audio", &wantAudio)); - int64_t position; - CHECK(msg->findInt64("position", &position)); - - status_t err = -EWOULDBLOCK; - sp response = new AMessage; - - ssize_t trackIndex = findTrack(wantAudio); - - if (trackIndex < 0) { - err = trackIndex; - } else { - err = onSeekTo(wantAudio, position); - } - response->setInt32("err", err); - uint32_t replyID; - CHECK(msg->senderAwaitsResponse(&replyID)); - response->postReply(replyID); - break; - } - default: - TRESPASS(); - } -} - -status_t FragmentedMP4Parser::onProceed() { - status_t err; - - if ((err = need(8)) != OK) { - return err; - } - - uint64_t size = readU32(0); - uint32_t type = readU32(4); - - size_t offset = 8; - - if (size == 1) { - if ((err = need(16)) != OK) { - return err; - } - - size = readU64(offset); - offset += 8; - } - - uint8_t userType[16]; - - if (type == FOURCC('u', 'u', 'i', 'd')) { - if ((err = need(offset + 16)) != OK) { - return err; - } - - memcpy(userType, mBuffer->data() + offset, 16); - offset += 16; - } - - CHECK(!mStack.isEmpty()); - uint32_t ptype = mStack.itemAt(mStack.size() - 1).mType; - - static const size_t kNumDispatchers = - sizeof(kDispatchTable) / sizeof(kDispatchTable[0]); - - size_t i; - for (i = 0; i < kNumDispatchers; ++i) { - if (kDispatchTable[i].mType == type - && kDispatchTable[i].mParentType == ptype) { - break; - } - } - - // SampleEntry boxes are container boxes that start with a variable - // amount of data depending on the media handler type. - // We don't look inside 'hint' type SampleEntry boxes. - - bool isSampleEntryBox = - (ptype == FOURCC('s', 't', 's', 'd')) - && editTrack(mCurrentTrackID)->mMediaHandlerType - != FOURCC('h', 'i', 'n', 't'); - - if ((i < kNumDispatchers && kDispatchTable[i].mHandler == 0) - || isSampleEntryBox || ptype == FOURCC('i', 'l', 's', 't')) { - // This is a container box. - if (type == FOURCC('m', 'o', 'o', 'f')) { - if (mFirstMoofOffset == 0) { - ALOGV("first moof @ %08lx", mBufferPos + offset); - mFirstMoofOffset = mBufferPos + offset - 8; // point at the size - } - } - if (type == FOURCC('m', 'e', 't', 'a')) { - if ((err = need(offset + 4)) < OK) { - return err; - } - - if (readU32(offset) != 0) { - return -EINVAL; - } - - offset += 4; - } else if (type == FOURCC('s', 't', 's', 'd')) { - if ((err = need(offset + 8)) < OK) { - return err; - } - - if (readU32(offset) != 0) { - return -EINVAL; - } - - if (readU32(offset + 4) == 0) { - // We need at least some entries. - return -EINVAL; - } - - offset += 8; - } else if (isSampleEntryBox) { - size_t headerSize; - - switch (editTrack(mCurrentTrackID)->mMediaHandlerType) { - case FOURCC('v', 'i', 'd', 'e'): - { - // 8 bytes SampleEntry + 70 bytes VisualSampleEntry - headerSize = 78; - break; - } - - case FOURCC('s', 'o', 'u', 'n'): - { - // 8 bytes SampleEntry + 20 bytes AudioSampleEntry - headerSize = 28; - break; - } - - case FOURCC('m', 'e', 't', 'a'): - { - headerSize = 8; // 8 bytes SampleEntry - break; - } - - default: - TRESPASS(); - } - - if (offset + headerSize > size) { - return -EINVAL; - } - - if ((err = need(offset + headerSize)) != OK) { - return err; - } - - switch (editTrack(mCurrentTrackID)->mMediaHandlerType) { - case FOURCC('v', 'i', 'd', 'e'): - { - err = parseVisualSampleEntry( - type, offset, offset + headerSize); - break; - } - - case FOURCC('s', 'o', 'u', 'n'): - { - err = parseAudioSampleEntry( - type, offset, offset + headerSize); - break; - } - - case FOURCC('m', 'e', 't', 'a'): - { - err = OK; - break; - } - - default: - TRESPASS(); - } - - if (err != OK) { - return err; - } - - offset += headerSize; - } - - skip(offset); - - ALOGV("%sentering box of type '%s'", - IndentString(mStack.size()), Fourcc2String(type)); - - enter(mBufferPos - offset, type, size - offset); - } else { - if (!fitsContainer(size)) { - return -EINVAL; - } - - if (i < kNumDispatchers && kDispatchTable[i].mHandler != 0) { - // We have a handler for this box type. - - if ((err = need(size)) != OK) { - return err; - } - - ALOGV("%sparsing box of type '%s'", - IndentString(mStack.size()), Fourcc2String(type)); - - if ((err = (this->*kDispatchTable[i].mHandler)( - type, offset, size)) != OK) { - return err; - } - } else { - // Unknown box type - - ALOGV("%sskipping box of type '%s', size %llu", - IndentString(mStack.size()), - Fourcc2String(type), size); - - } - - skip(size); - } - - return OK; -} - -// static -int FragmentedMP4Parser::CompareSampleLocation( - const SampleInfo &sample, const MediaDataInfo &mdatInfo) { - if (sample.mOffset + sample.mSize < mdatInfo.mOffset) { - return -1; - } - - if (sample.mOffset >= mdatInfo.mOffset + mdatInfo.mBuffer->size()) { - return 1; - } - - // Otherwise make sure the sample is completely contained within this - // media data block. - - CHECK_GE(sample.mOffset, mdatInfo.mOffset); - - CHECK_LE(sample.mOffset + sample.mSize, - mdatInfo.mOffset + mdatInfo.mBuffer->size()); - - return 0; -} - -void FragmentedMP4Parser::resumeIfNecessary() { - if (!mSuspended) { - return; - } - - ALOGV("resuming."); - - mSuspended = false; - (new AMessage(kWhatProceed, id()))->post(); -} - -status_t FragmentedMP4Parser::getSample( - TrackInfo *info, sp *fragment, SampleInfo *sampleInfo) { - for (;;) { - if (info->mFragments.empty()) { - if (mFinalResult != OK) { - return mFinalResult; - } - - resumeIfNecessary(); - return -EWOULDBLOCK; - } - - *fragment = *info->mFragments.begin(); - - status_t err = (*fragment)->getSample(sampleInfo); - - if (err == OK) { - return OK; - } else if (err != ERROR_END_OF_STREAM) { - return err; - } - - // Really, end of this fragment... - - info->mFragments.erase(info->mFragments.begin()); - } -} - -status_t FragmentedMP4Parser::onDequeueAccessUnit( - size_t trackIndex, sp *accessUnit) { - TrackInfo *info = &mTracks.editValueAt(trackIndex); - - sp fragment; - SampleInfo sampleInfo; - status_t err = getSample(info, &fragment, &sampleInfo); - - if (err == -EWOULDBLOCK) { - resumeIfNecessary(); - return err; - } else if (err != OK) { - return err; - } - - err = -EWOULDBLOCK; - - bool checkDroppable = false; - - for (size_t i = 0; i < mMediaData.size(); ++i) { - const MediaDataInfo &mdatInfo = mMediaData.itemAt(i); - - int cmp = CompareSampleLocation(sampleInfo, mdatInfo); - - if (cmp < 0 && !mSource->isSeekable()) { - return -EPIPE; - } else if (cmp == 0) { - if (i > 0) { - checkDroppable = true; - } - - err = makeAccessUnit(info, sampleInfo, mdatInfo, accessUnit); - break; - } - } - - if (err != OK) { - return err; - } - - fragment->advance(); - - if (!mMediaData.empty() && checkDroppable) { - size_t numDroppable = 0; - bool done = false; - - // XXX FIXME: if one of the tracks is not advanced (e.g. if you play an audio+video - // file with sf2), then mMediaData will not be pruned and keeps growing - for (size_t i = 0; !done && i < mMediaData.size(); ++i) { - const MediaDataInfo &mdatInfo = mMediaData.itemAt(i); - - for (size_t j = 0; j < mTracks.size(); ++j) { - TrackInfo *info = &mTracks.editValueAt(j); - - sp fragment; - SampleInfo sampleInfo; - err = getSample(info, &fragment, &sampleInfo); - - if (err != OK) { - done = true; - break; - } - - int cmp = CompareSampleLocation(sampleInfo, mdatInfo); - - if (cmp <= 0) { - done = true; - break; - } - } - - if (!done) { - ++numDroppable; - } - } - - if (numDroppable > 0) { - mMediaData.removeItemsAt(0, numDroppable); - - if (mMediaData.size() < 5) { - resumeIfNecessary(); - } - } - } - - return err; -} - -static size_t parseNALSize(size_t nalLengthSize, const uint8_t *data) { - switch (nalLengthSize) { - case 1: - return *data; - case 2: - return U16_AT(data); - case 3: - return ((size_t)data[0] << 16) | U16_AT(&data[1]); - case 4: - return U32_AT(data); - } - - // This cannot happen, mNALLengthSize springs to life by adding 1 to - // a 2-bit integer. - TRESPASS(); - - return 0; -} - -status_t FragmentedMP4Parser::makeAccessUnit( - TrackInfo *info, - const SampleInfo &sample, - const MediaDataInfo &mdatInfo, - sp *accessUnit) { - if (sample.mSampleDescIndex < 1 - || sample.mSampleDescIndex > info->mSampleDescs.size()) { - return ERROR_MALFORMED; - } - - int64_t presentationTimeUs = - 1000000ll * sample.mPresentationTime / info->mMediaTimeScale; - - const SampleDescription &sampleDesc = - info->mSampleDescs.itemAt(sample.mSampleDescIndex - 1); - - size_t nalLengthSize; - if (!sampleDesc.mFormat->findSize("nal-length-size", &nalLengthSize)) { - *accessUnit = new ABuffer(sample.mSize); - - memcpy((*accessUnit)->data(), - mdatInfo.mBuffer->data() + (sample.mOffset - mdatInfo.mOffset), - sample.mSize); - - (*accessUnit)->meta()->setInt64("timeUs", presentationTimeUs); - if (IsIDR(*accessUnit)) { - (*accessUnit)->meta()->setInt32("is-sync-frame", 1); - } - - return OK; - } - - const uint8_t *srcPtr = - mdatInfo.mBuffer->data() + (sample.mOffset - mdatInfo.mOffset); - - for (int i = 0; i < 2 ; ++i) { - size_t srcOffset = 0; - size_t dstOffset = 0; - - while (srcOffset < sample.mSize) { - if (srcOffset + nalLengthSize > sample.mSize) { - return ERROR_MALFORMED; - } - - size_t nalSize = parseNALSize(nalLengthSize, &srcPtr[srcOffset]); - srcOffset += nalLengthSize; - - if (srcOffset + nalSize > sample.mSize) { - return ERROR_MALFORMED; - } - - if (i == 1) { - memcpy((*accessUnit)->data() + dstOffset, - "\x00\x00\x00\x01", - 4); - - memcpy((*accessUnit)->data() + dstOffset + 4, - srcPtr + srcOffset, - nalSize); - } - - srcOffset += nalSize; - dstOffset += nalSize + 4; - } - - if (i == 0) { - (*accessUnit) = new ABuffer(dstOffset); - (*accessUnit)->meta()->setInt64( - "timeUs", presentationTimeUs); - } - } - if (IsIDR(*accessUnit)) { - (*accessUnit)->meta()->setInt32("is-sync-frame", 1); - } - - return OK; -} - -status_t FragmentedMP4Parser::need(size_t size) { - if (!fitsContainer(size)) { - return -EINVAL; - } - - if (size <= mBuffer->size()) { - return OK; - } - - sp msg = new AMessage(kWhatReadMore, id()); - msg->setSize("needed", size - mBuffer->size()); - msg->post(); - - // ALOGV("need(%d) returning -EAGAIN, only have %d", size, mBuffer->size()); - - return -EAGAIN; -} - -void FragmentedMP4Parser::enter(off64_t offset, uint32_t type, uint64_t size) { - Container container; - container.mOffset = offset; - container.mType = type; - container.mExtendsToEOF = (size == 0); - container.mBytesRemaining = size; - - mStack.push(container); -} - -bool FragmentedMP4Parser::fitsContainer(uint64_t size) const { - CHECK(!mStack.isEmpty()); - const Container &container = mStack.itemAt(mStack.size() - 1); - - return container.mExtendsToEOF || size <= container.mBytesRemaining; -} - -uint16_t FragmentedMP4Parser::readU16(size_t offset) { - CHECK_LE(offset + 2, mBuffer->size()); - - const uint8_t *ptr = mBuffer->data() + offset; - return (ptr[0] << 8) | ptr[1]; -} - -uint32_t FragmentedMP4Parser::readU32(size_t offset) { - CHECK_LE(offset + 4, mBuffer->size()); - - const uint8_t *ptr = mBuffer->data() + offset; - return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]; -} - -uint64_t FragmentedMP4Parser::readU64(size_t offset) { - return (((uint64_t)readU32(offset)) << 32) | readU32(offset + 4); -} - -void FragmentedMP4Parser::skip(off_t distance) { - CHECK(!mStack.isEmpty()); - for (size_t i = mStack.size(); i-- > 0;) { - Container *container = &mStack.editItemAt(i); - if (!container->mExtendsToEOF) { - CHECK_LE(distance, (off_t)container->mBytesRemaining); - - container->mBytesRemaining -= distance; - - if (container->mBytesRemaining == 0) { - ALOGV("%sleaving box of type '%s'", - IndentString(mStack.size() - 1), - Fourcc2String(container->mType)); - -#if 0 - if (container->mType == FOURCC('s', 't', 's', 'd')) { - TrackInfo *trackInfo = editTrack(mCurrentTrackID); - for (size_t i = 0; - i < trackInfo->mSampleDescs.size(); ++i) { - ALOGI("format #%d: %s", - i, - trackInfo->mSampleDescs.itemAt(i) - .mFormat->debugString().c_str()); - } - } -#endif - - if (container->mType == FOURCC('s', 't', 'b', 'l')) { - TrackInfo *trackInfo = editTrack(mCurrentTrackID); - - trackInfo->mStaticFragment->signalCompletion(); - - CHECK(trackInfo->mFragments.empty()); - trackInfo->mFragments.push_back(trackInfo->mStaticFragment); - trackInfo->mStaticFragment.clear(); - } else if (container->mType == FOURCC('t', 'r', 'a', 'f')) { - TrackInfo *trackInfo = - editTrack(mTrackFragmentHeaderInfo.mTrackID); - - const sp &fragment = - *--trackInfo->mFragments.end(); - - static_cast( - fragment.get())->signalCompletion(); - } else if (container->mType == FOURCC('m', 'o', 'o', 'v')) { - mDoneWithMoov = true; - } - - container = NULL; - mStack.removeItemsAt(i); - } - } - } - - if (distance < (off_t)mBuffer->size()) { - mBuffer->setRange(mBuffer->offset() + distance, mBuffer->size() - distance); - mBufferPos += distance; - return; - } - - mBuffer->setRange(0, 0); - mBufferPos += distance; -} - -status_t FragmentedMP4Parser::parseTrackHeader( - uint32_t /* type */, size_t offset, uint64_t size) { - if (offset + 4 > size) { - return -EINVAL; - } - - uint32_t flags = readU32(offset); - - uint32_t version = flags >> 24; - flags &= 0xffffff; - - uint32_t trackID; - uint64_t duration; - - if (version == 1) { - if (offset + 36 > size) { - return -EINVAL; - } - - trackID = readU32(offset + 20); - duration = readU64(offset + 28); - - offset += 36; - } else if (version == 0) { - if (offset + 24 > size) { - return -EINVAL; - } - - trackID = readU32(offset + 12); - duration = readU32(offset + 20); - - offset += 24; - } else { - return -EINVAL; - } - - TrackInfo *info = editTrack(trackID, true /* createIfNecessary */); - info->mFlags = flags; - info->mDuration = duration; - if (info->mDuration == 0xffffffff) { - // ffmpeg sets this to -1, which is incorrect. - info->mDuration = 0; - } - - info->mStaticFragment = new StaticTrackFragment; - - mCurrentTrackID = trackID; - - return OK; -} - -status_t FragmentedMP4Parser::parseMediaHeader( - uint32_t /* type */, size_t offset, uint64_t size) { - if (offset + 4 > size) { - return -EINVAL; - } - - uint32_t versionAndFlags = readU32(offset); - - if (versionAndFlags & 0xffffff) { - return ERROR_MALFORMED; - } - - uint32_t version = versionAndFlags >> 24; - - TrackInfo *info = editTrack(mCurrentTrackID); - - if (version == 1) { - if (offset + 4 + 32 > size) { - return -EINVAL; - } - info->mMediaTimeScale = U32_AT(mBuffer->data() + offset + 20); - } else if (version == 0) { - if (offset + 4 + 20 > size) { - return -EINVAL; - } - info->mMediaTimeScale = U32_AT(mBuffer->data() + offset + 12); - } else { - return ERROR_MALFORMED; - } - - return OK; -} - -status_t FragmentedMP4Parser::parseMediaHandler( - uint32_t /* type */, size_t offset, uint64_t size) { - if (offset + 12 > size) { - return -EINVAL; - } - - if (readU32(offset) != 0) { - return -EINVAL; - } - - uint32_t handlerType = readU32(offset + 8); - - switch (handlerType) { - case FOURCC('v', 'i', 'd', 'e'): - case FOURCC('s', 'o', 'u', 'n'): - case FOURCC('h', 'i', 'n', 't'): - case FOURCC('m', 'e', 't', 'a'): - break; - - default: - return -EINVAL; - } - - editTrack(mCurrentTrackID)->mMediaHandlerType = handlerType; - - return OK; -} - -status_t FragmentedMP4Parser::parseVisualSampleEntry( - uint32_t type, size_t offset, uint64_t size) { - if (offset + 78 > size) { - return -EINVAL; - } - - TrackInfo *trackInfo = editTrack(mCurrentTrackID); - - trackInfo->mSampleDescs.push(); - SampleDescription *sampleDesc = - &trackInfo->mSampleDescs.editItemAt( - trackInfo->mSampleDescs.size() - 1); - - sampleDesc->mType = type; - sampleDesc->mDataRefIndex = readU16(offset + 6); - - sp format = new AMessage; - - switch (type) { - case FOURCC('a', 'v', 'c', '1'): - format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC); - break; - case FOURCC('m', 'p', '4', 'v'): - format->setString("mime", MEDIA_MIMETYPE_VIDEO_MPEG4); - break; - case FOURCC('s', '2', '6', '3'): - case FOURCC('h', '2', '6', '3'): - case FOURCC('H', '2', '6', '3'): - format->setString("mime", MEDIA_MIMETYPE_VIDEO_H263); - break; - default: - format->setString("mime", "application/octet-stream"); - break; - } - - format->setInt32("width", readU16(offset + 8 + 16)); - format->setInt32("height", readU16(offset + 8 + 18)); - - sampleDesc->mFormat = format; - - return OK; -} - -status_t FragmentedMP4Parser::parseAudioSampleEntry( - uint32_t type, size_t offset, uint64_t size) { - if (offset + 28 > size) { - return -EINVAL; - } - - TrackInfo *trackInfo = editTrack(mCurrentTrackID); - - trackInfo->mSampleDescs.push(); - SampleDescription *sampleDesc = - &trackInfo->mSampleDescs.editItemAt( - trackInfo->mSampleDescs.size() - 1); - - sampleDesc->mType = type; - sampleDesc->mDataRefIndex = readU16(offset + 6); - - sp format = new AMessage; - - format->setInt32("channel-count", readU16(offset + 8 + 8)); - format->setInt32("sample-size", readU16(offset + 8 + 10)); - format->setInt32("sample-rate", readU32(offset + 8 + 16) / 65536.0f); - - switch (type) { - case FOURCC('m', 'p', '4', 'a'): - format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC); - break; - - case FOURCC('s', 'a', 'm', 'r'): - format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB); - format->setInt32("channel-count", 1); - format->setInt32("sample-rate", 8000); - break; - - case FOURCC('s', 'a', 'w', 'b'): - format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_WB); - format->setInt32("channel-count", 1); - format->setInt32("sample-rate", 16000); - break; - default: - format->setString("mime", "application/octet-stream"); - break; - } - - sampleDesc->mFormat = format; - - return OK; -} - -static void addCodecSpecificData( - const sp &format, int32_t index, - const void *data, size_t size, - bool insertStartCode = false) { - sp csd = new ABuffer(insertStartCode ? size + 4 : size); - - memcpy(csd->data() + (insertStartCode ? 4 : 0), data, size); - - if (insertStartCode) { - memcpy(csd->data(), "\x00\x00\x00\x01", 4); - } - - csd->meta()->setInt32("csd", true); - csd->meta()->setInt64("timeUs", 0ll); - - format->setBuffer(StringPrintf("csd-%d", index).c_str(), csd); -} - -status_t FragmentedMP4Parser::parseSampleSizes( - uint32_t type, size_t offset, uint64_t size) { - return editTrack(mCurrentTrackID)->mStaticFragment->parseSampleSizes( - this, type, offset, size); -} - -status_t FragmentedMP4Parser::parseCompactSampleSizes( - uint32_t type, size_t offset, uint64_t size) { - return editTrack(mCurrentTrackID)->mStaticFragment->parseCompactSampleSizes( - this, type, offset, size); -} - -status_t FragmentedMP4Parser::parseSampleToChunk( - uint32_t type, size_t offset, uint64_t size) { - return editTrack(mCurrentTrackID)->mStaticFragment->parseSampleToChunk( - this, type, offset, size); -} - -status_t FragmentedMP4Parser::parseChunkOffsets( - uint32_t type, size_t offset, uint64_t size) { - return editTrack(mCurrentTrackID)->mStaticFragment->parseChunkOffsets( - this, type, offset, size); -} - -status_t FragmentedMP4Parser::parseChunkOffsets64( - uint32_t type, size_t offset, uint64_t size) { - return editTrack(mCurrentTrackID)->mStaticFragment->parseChunkOffsets64( - this, type, offset, size); -} - -status_t FragmentedMP4Parser::parseAVCCodecSpecificData( - uint32_t /* type */, size_t offset, uint64_t size) { - TrackInfo *trackInfo = editTrack(mCurrentTrackID); - - SampleDescription *sampleDesc = - &trackInfo->mSampleDescs.editItemAt( - trackInfo->mSampleDescs.size() - 1); - - if (sampleDesc->mType != FOURCC('a', 'v', 'c', '1')) { - return -EINVAL; - } - - const uint8_t *ptr = mBuffer->data() + offset; - - size -= offset; - offset = 0; - - if (size < 7 || ptr[0] != 0x01) { - return ERROR_MALFORMED; - } - - sampleDesc->mFormat->setSize("nal-length-size", 1 + (ptr[4] & 3)); - - size_t numSPS = ptr[5] & 31; - - ptr += 6; - size -= 6; - - for (size_t i = 0; i < numSPS; ++i) { - if (size < 2) { - return ERROR_MALFORMED; - } - - size_t length = U16_AT(ptr); - - ptr += 2; - size -= 2; - - if (size < length) { - return ERROR_MALFORMED; - } - - addCodecSpecificData( - sampleDesc->mFormat, i, ptr, length, - true /* insertStartCode */); - - ptr += length; - size -= length; - } - - if (size < 1) { - return ERROR_MALFORMED; - } - - size_t numPPS = *ptr; - ++ptr; - --size; - - for (size_t i = 0; i < numPPS; ++i) { - if (size < 2) { - return ERROR_MALFORMED; - } - - size_t length = U16_AT(ptr); - - ptr += 2; - size -= 2; - - if (size < length) { - return ERROR_MALFORMED; - } - - addCodecSpecificData( - sampleDesc->mFormat, numSPS + i, ptr, length, - true /* insertStartCode */); - - ptr += length; - size -= length; - } - - return OK; -} - -status_t FragmentedMP4Parser::parseESDSCodecSpecificData( - uint32_t /* type */, size_t offset, uint64_t size) { - TrackInfo *trackInfo = editTrack(mCurrentTrackID); - - SampleDescription *sampleDesc = - &trackInfo->mSampleDescs.editItemAt( - trackInfo->mSampleDescs.size() - 1); - - if (sampleDesc->mType != FOURCC('m', 'p', '4', 'a') - && sampleDesc->mType != FOURCC('m', 'p', '4', 'v')) { - return -EINVAL; - } - - const uint8_t *ptr = mBuffer->data() + offset; - - size -= offset; - offset = 0; - - if (size < 4) { - return -EINVAL; - } - - if (U32_AT(ptr) != 0) { - return -EINVAL; - } - - ptr += 4; - size -=4; - - ESDS esds(ptr, size); - - uint8_t objectTypeIndication; - if (esds.getObjectTypeIndication(&objectTypeIndication) != OK) { - return ERROR_MALFORMED; - } - - const uint8_t *csd; - size_t csd_size; - if (esds.getCodecSpecificInfo( - (const void **)&csd, &csd_size) != OK) { - return ERROR_MALFORMED; - } - - addCodecSpecificData(sampleDesc->mFormat, 0, csd, csd_size); - - if (sampleDesc->mType != FOURCC('m', 'p', '4', 'a')) { - return OK; - } - - if (csd_size == 0) { - // There's no further information, i.e. no codec specific data - // Let's assume that the information provided in the mpeg4 headers - // is accurate and hope for the best. - - return OK; - } - - if (csd_size < 2) { - return ERROR_MALFORMED; - } - - uint32_t objectType = csd[0] >> 3; - - if (objectType == 31) { - return ERROR_UNSUPPORTED; - } - - uint32_t freqIndex = (csd[0] & 7) << 1 | (csd[1] >> 7); - int32_t sampleRate = 0; - int32_t numChannels = 0; - if (freqIndex == 15) { - if (csd_size < 5) { - return ERROR_MALFORMED; - } - - sampleRate = (csd[1] & 0x7f) << 17 - | csd[2] << 9 - | csd[3] << 1 - | (csd[4] >> 7); - - numChannels = (csd[4] >> 3) & 15; - } else { - static uint32_t kSamplingRate[] = { - 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, - 16000, 12000, 11025, 8000, 7350 - }; - - if (freqIndex == 13 || freqIndex == 14) { - return ERROR_MALFORMED; - } - - sampleRate = kSamplingRate[freqIndex]; - numChannels = (csd[1] >> 3) & 15; - } - - if (numChannels == 0) { - return ERROR_UNSUPPORTED; - } - - sampleDesc->mFormat->setInt32("sample-rate", sampleRate); - sampleDesc->mFormat->setInt32("channel-count", numChannels); - - return OK; -} - -status_t FragmentedMP4Parser::parseMediaData( - uint32_t /* type */, size_t offset, uint64_t size) { - ALOGV("skipping 'mdat' chunk at offsets 0x%08lx-0x%08llx.", - mBufferPos + offset, mBufferPos + size); - - sp buffer = new ABuffer(size - offset); - memcpy(buffer->data(), mBuffer->data() + offset, size - offset); - - mMediaData.push(); - MediaDataInfo *info = &mMediaData.editItemAt(mMediaData.size() - 1); - info->mBuffer = buffer; - info->mOffset = mBufferPos + offset; - - if (mMediaData.size() > 10) { - ALOGV("suspending for now."); - mSuspended = true; - } - - return OK; -} - -status_t FragmentedMP4Parser::parseSegmentIndex( - uint32_t type, size_t offset, uint64_t size) { - UNUSED_UNLESS_VERBOSE(type); - ALOGV("sidx box type %d, offset %d, size %d", type, int(offset), int(size)); -// AString sidxstr; -// hexdump(mBuffer->data() + offset, size, 0 /* indent */, &sidxstr); -// ALOGV("raw sidx:"); -// ALOGV("%s", sidxstr.c_str()); - if (offset + 12 > size) { - return -EINVAL; - } - - uint32_t flags = readU32(offset); - - uint32_t version = flags >> 24; - flags &= 0xffffff; - - ALOGV("sidx version %d", version); - - uint32_t referenceId = readU32(offset + 4); - uint32_t timeScale = readU32(offset + 8); - ALOGV("sidx refid/timescale: %d/%d", referenceId, timeScale); - - uint64_t earliestPresentationTime; - uint64_t firstOffset; - - offset += 12; - - if (version == 0) { - if (offset + 8 > size) { - return -EINVAL; - } - earliestPresentationTime = readU32(offset); - firstOffset = readU32(offset + 4); - offset += 8; - } else { - if (offset + 16 > size) { - return -EINVAL; - } - earliestPresentationTime = readU64(offset); - firstOffset = readU64(offset + 8); - offset += 16; - } - ALOGV("sidx pres/off: %Ld/%Ld", earliestPresentationTime, firstOffset); - - if (offset + 4 > size) { - return -EINVAL; - } - if (readU16(offset) != 0) { // reserved - return -EINVAL; - } - int32_t referenceCount = readU16(offset + 2); - offset += 4; - ALOGV("refcount: %d", referenceCount); - - if (offset + referenceCount * 12 > size) { - return -EINVAL; - } - - TrackInfo *info = editTrack(mCurrentTrackID); - uint64_t total_duration = 0; - for (int i = 0; i < referenceCount; i++) { - uint32_t d1 = readU32(offset); - uint32_t d2 = readU32(offset + 4); - uint32_t d3 = readU32(offset + 8); - - if (d1 & 0x80000000) { - ALOGW("sub-sidx boxes not supported yet"); - } - bool sap = d3 & 0x80000000; - bool saptype = d3 >> 28; - if (!sap || saptype > 2) { - ALOGW("not a stream access point, or unsupported type"); - } - total_duration += d2; - offset += 12; - ALOGV(" item %d, %08x %08x %08x", i, d1, d2, d3); - SidxEntry se; - se.mSize = d1 & 0x7fffffff; - se.mDurationUs = 1000000LL * d2 / timeScale; - info->mSidx.add(se); - } - - info->mSidxDuration = total_duration * 1000000 / timeScale; - ALOGV("duration: %lld", info->mSidxDuration); - return OK; -} - -status_t FragmentedMP4Parser::parseTrackExtends( - uint32_t /* type */, size_t offset, uint64_t size) { - if (offset + 24 > size) { - return -EINVAL; - } - - if (readU32(offset) != 0) { - return -EINVAL; - } - - uint32_t trackID = readU32(offset + 4); - - TrackInfo *info = editTrack(trackID, true /* createIfNecessary */); - info->mDefaultSampleDescriptionIndex = readU32(offset + 8); - info->mDefaultSampleDuration = readU32(offset + 12); - info->mDefaultSampleSize = readU32(offset + 16); - info->mDefaultSampleFlags = readU32(offset + 20); - - return OK; -} - -FragmentedMP4Parser::TrackInfo *FragmentedMP4Parser::editTrack( - uint32_t trackID, bool createIfNecessary) { - ssize_t i = mTracks.indexOfKey(trackID); - - if (i >= 0) { - return &mTracks.editValueAt(i); - } - - if (!createIfNecessary) { - return NULL; - } - - TrackInfo info; - info.mTrackID = trackID; - info.mFlags = 0; - info.mDuration = 0xffffffff; - info.mSidxDuration = 0; - info.mMediaTimeScale = 0; - info.mMediaHandlerType = 0; - info.mDefaultSampleDescriptionIndex = 0; - info.mDefaultSampleDuration = 0; - info.mDefaultSampleSize = 0; - info.mDefaultSampleFlags = 0; - - info.mDecodingTime = 0; - - mTracks.add(trackID, info); - return &mTracks.editValueAt(mTracks.indexOfKey(trackID)); -} - -status_t FragmentedMP4Parser::parseTrackFragmentHeader( - uint32_t /* type */, size_t offset, uint64_t size) { - if (offset + 8 > size) { - return -EINVAL; - } - - uint32_t flags = readU32(offset); - - if (flags & 0xff000000) { - return -EINVAL; - } - - mTrackFragmentHeaderInfo.mFlags = flags; - - mTrackFragmentHeaderInfo.mTrackID = readU32(offset + 4); - offset += 8; - - if (flags & TrackFragmentHeaderInfo::kBaseDataOffsetPresent) { - if (offset + 8 > size) { - return -EINVAL; - } - - mTrackFragmentHeaderInfo.mBaseDataOffset = readU64(offset); - offset += 8; - } - - if (flags & TrackFragmentHeaderInfo::kSampleDescriptionIndexPresent) { - if (offset + 4 > size) { - return -EINVAL; - } - - mTrackFragmentHeaderInfo.mSampleDescriptionIndex = readU32(offset); - offset += 4; - } - - if (flags & TrackFragmentHeaderInfo::kDefaultSampleDurationPresent) { - if (offset + 4 > size) { - return -EINVAL; - } - - mTrackFragmentHeaderInfo.mDefaultSampleDuration = readU32(offset); - offset += 4; - } - - if (flags & TrackFragmentHeaderInfo::kDefaultSampleSizePresent) { - if (offset + 4 > size) { - return -EINVAL; - } - - mTrackFragmentHeaderInfo.mDefaultSampleSize = readU32(offset); - offset += 4; - } - - if (flags & TrackFragmentHeaderInfo::kDefaultSampleFlagsPresent) { - if (offset + 4 > size) { - return -EINVAL; - } - - mTrackFragmentHeaderInfo.mDefaultSampleFlags = readU32(offset); - offset += 4; - } - - if (!(flags & TrackFragmentHeaderInfo::kBaseDataOffsetPresent)) { - // This should point to the position of the first byte of the - // enclosing 'moof' container for the first track and - // the end of the data of the preceding fragment for subsequent - // tracks. - - CHECK_GE(mStack.size(), 2u); - - mTrackFragmentHeaderInfo.mBaseDataOffset = - mStack.itemAt(mStack.size() - 2).mOffset; - - // XXX TODO: This does not do the right thing for the 2nd and - // subsequent tracks yet. - } - - mTrackFragmentHeaderInfo.mDataOffset = - mTrackFragmentHeaderInfo.mBaseDataOffset; - - TrackInfo *trackInfo = editTrack(mTrackFragmentHeaderInfo.mTrackID); - - if (trackInfo->mFragments.empty() - || (*trackInfo->mFragments.begin())->complete()) { - trackInfo->mFragments.push_back(new DynamicTrackFragment); - } - - return OK; -} - -status_t FragmentedMP4Parser::parseTrackFragmentRun( - uint32_t /* type */, size_t offset, uint64_t size) { - if (offset + 8 > size) { - return -EINVAL; - } - - enum { - kDataOffsetPresent = 0x01, - kFirstSampleFlagsPresent = 0x04, - kSampleDurationPresent = 0x100, - kSampleSizePresent = 0x200, - kSampleFlagsPresent = 0x400, - kSampleCompositionTimeOffsetPresent = 0x800, - }; - - uint32_t flags = readU32(offset); - - if (flags & 0xff000000) { - return -EINVAL; - } - - if ((flags & kFirstSampleFlagsPresent) && (flags & kSampleFlagsPresent)) { - // These two shall not be used together. - return -EINVAL; - } - - uint32_t sampleCount = readU32(offset + 4); - offset += 8; - - uint64_t dataOffset = mTrackFragmentHeaderInfo.mDataOffset; - - uint32_t firstSampleFlags = 0; - - if (flags & kDataOffsetPresent) { - if (offset + 4 > size) { - return -EINVAL; - } - - int32_t dataOffsetDelta = (int32_t)readU32(offset); - - dataOffset = mTrackFragmentHeaderInfo.mBaseDataOffset + dataOffsetDelta; - - offset += 4; - } - - if (flags & kFirstSampleFlagsPresent) { - if (offset + 4 > size) { - return -EINVAL; - } - - firstSampleFlags = readU32(offset); - offset += 4; - } - - TrackInfo *info = editTrack(mTrackFragmentHeaderInfo.mTrackID); - - if (info == NULL) { - return -EINVAL; - } - - uint32_t sampleDuration = 0, sampleSize = 0, sampleFlags = 0, - sampleCtsOffset = 0; - - size_t bytesPerSample = 0; - if (flags & kSampleDurationPresent) { - bytesPerSample += 4; - } else if (mTrackFragmentHeaderInfo.mFlags - & TrackFragmentHeaderInfo::kDefaultSampleDurationPresent) { - sampleDuration = mTrackFragmentHeaderInfo.mDefaultSampleDuration; - } else { - sampleDuration = info->mDefaultSampleDuration; - } - - if (flags & kSampleSizePresent) { - bytesPerSample += 4; - } else if (mTrackFragmentHeaderInfo.mFlags - & TrackFragmentHeaderInfo::kDefaultSampleSizePresent) { - sampleSize = mTrackFragmentHeaderInfo.mDefaultSampleSize; - } else { - sampleSize = info->mDefaultSampleSize; - } - - if (flags & kSampleFlagsPresent) { - bytesPerSample += 4; - } else if (mTrackFragmentHeaderInfo.mFlags - & TrackFragmentHeaderInfo::kDefaultSampleFlagsPresent) { - sampleFlags = mTrackFragmentHeaderInfo.mDefaultSampleFlags; - } else { - sampleFlags = info->mDefaultSampleFlags; - } - - if (flags & kSampleCompositionTimeOffsetPresent) { - bytesPerSample += 4; - } else { - sampleCtsOffset = 0; - } - - if (offset + sampleCount * bytesPerSample > size) { - return -EINVAL; - } - - uint32_t sampleDescIndex = - (mTrackFragmentHeaderInfo.mFlags - & TrackFragmentHeaderInfo::kSampleDescriptionIndexPresent) - ? mTrackFragmentHeaderInfo.mSampleDescriptionIndex - : info->mDefaultSampleDescriptionIndex; - - for (uint32_t i = 0; i < sampleCount; ++i) { - if (flags & kSampleDurationPresent) { - sampleDuration = readU32(offset); - offset += 4; - } - - if (flags & kSampleSizePresent) { - sampleSize = readU32(offset); - offset += 4; - } - - if (flags & kSampleFlagsPresent) { - sampleFlags = readU32(offset); - offset += 4; - } - - if (flags & kSampleCompositionTimeOffsetPresent) { - sampleCtsOffset = readU32(offset); - offset += 4; - } - - ALOGV("adding sample at offset 0x%08llx, size %u, duration %u, " - "sampleDescIndex=%u, flags 0x%08x", - dataOffset, sampleSize, sampleDuration, - sampleDescIndex, - (flags & kFirstSampleFlagsPresent) && i == 0 - ? firstSampleFlags : sampleFlags); - - const sp &fragment = *--info->mFragments.end(); - - uint32_t decodingTime = info->mDecodingTime; - info->mDecodingTime += sampleDuration; - uint32_t presentationTime = decodingTime + sampleCtsOffset; - - static_cast( - fragment.get())->addSample( - dataOffset, - sampleSize, - presentationTime, - sampleDescIndex, - ((flags & kFirstSampleFlagsPresent) && i == 0) - ? firstSampleFlags : sampleFlags); - - dataOffset += sampleSize; - } - - mTrackFragmentHeaderInfo.mDataOffset = dataOffset; - - return OK; -} - -void FragmentedMP4Parser::copyBuffer( - sp *dst, size_t offset, uint64_t size) const { - sp buf = new ABuffer(size); - memcpy(buf->data(), mBuffer->data() + offset, size); - - *dst = buf; -} - -} // namespace android diff --git a/media/libstagefright/mp4/TrackFragment.cpp b/media/libstagefright/mp4/TrackFragment.cpp deleted file mode 100644 index 3e0056d..0000000 --- a/media/libstagefright/mp4/TrackFragment.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "TrackFragment" -#include - -#include "TrackFragment.h" - -#include -#include -#include -#include -#include - -namespace android { - -FragmentedMP4Parser::DynamicTrackFragment::DynamicTrackFragment() - : mComplete(false), - mSampleIndex(0) { -} - -FragmentedMP4Parser::DynamicTrackFragment::~DynamicTrackFragment() { -} - -status_t FragmentedMP4Parser::DynamicTrackFragment::getSample(SampleInfo *info) { - if (mSampleIndex >= mSamples.size()) { - return mComplete ? ERROR_END_OF_STREAM : -EWOULDBLOCK; - } - - *info = mSamples.itemAt(mSampleIndex); - - return OK; -} - -void FragmentedMP4Parser::DynamicTrackFragment::advance() { - ++mSampleIndex; -} - -void FragmentedMP4Parser::DynamicTrackFragment::addSample( - off64_t dataOffset, size_t sampleSize, - uint32_t presentationTime, - size_t sampleDescIndex, - uint32_t flags) { - mSamples.push(); - SampleInfo *sampleInfo = &mSamples.editItemAt(mSamples.size() - 1); - - sampleInfo->mOffset = dataOffset; - sampleInfo->mSize = sampleSize; - sampleInfo->mPresentationTime = presentationTime; - sampleInfo->mSampleDescIndex = sampleDescIndex; - sampleInfo->mFlags = flags; -} - -status_t FragmentedMP4Parser::DynamicTrackFragment::signalCompletion() { - mComplete = true; - - return OK; -} - -bool FragmentedMP4Parser::DynamicTrackFragment::complete() const { - return mComplete; -} - -//////////////////////////////////////////////////////////////////////////////// - -FragmentedMP4Parser::StaticTrackFragment::StaticTrackFragment() - : mSampleIndex(0), - mSampleCount(0), - mChunkIndex(0), - mSampleToChunkIndex(-1), - mSampleToChunkRemaining(0), - mPrevChunkIndex(0xffffffff), - mNextSampleOffset(0) { -} - -FragmentedMP4Parser::StaticTrackFragment::~StaticTrackFragment() { -} - -status_t FragmentedMP4Parser::StaticTrackFragment::getSample(SampleInfo *info) { - if (mSampleIndex >= mSampleCount) { - return ERROR_END_OF_STREAM; - } - - *info = mSampleInfo; - - ALOGV("returning sample %d at [0x%08llx, 0x%08llx)", - mSampleIndex, - info->mOffset, info->mOffset + info->mSize); - - return OK; -} - -void FragmentedMP4Parser::StaticTrackFragment::updateSampleInfo() { - if (mSampleIndex >= mSampleCount) { - return; - } - - if (mSampleSizes != NULL) { - uint32_t defaultSampleSize = U32_AT(mSampleSizes->data() + 4); - if (defaultSampleSize > 0) { - mSampleInfo.mSize = defaultSampleSize; - } else { - mSampleInfo.mSize= U32_AT(mSampleSizes->data() + 12 + 4 * mSampleIndex); - } - } else { - CHECK(mCompactSampleSizes != NULL); - - uint32_t fieldSize = U32_AT(mCompactSampleSizes->data() + 4); - - switch (fieldSize) { - case 4: - { - unsigned byte = mCompactSampleSizes->data()[12 + mSampleIndex / 2]; - mSampleInfo.mSize = (mSampleIndex & 1) ? byte & 0x0f : byte >> 4; - break; - } - - case 8: - { - mSampleInfo.mSize = mCompactSampleSizes->data()[12 + mSampleIndex]; - break; - } - - default: - { - CHECK_EQ(fieldSize, 16); - mSampleInfo.mSize = - U16_AT(mCompactSampleSizes->data() + 12 + mSampleIndex * 2); - break; - } - } - } - - CHECK_GT(mSampleToChunkRemaining, 0); - - // The sample desc index is 1-based... XXX - mSampleInfo.mSampleDescIndex = - U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 8); - - if (mChunkIndex != mPrevChunkIndex) { - mPrevChunkIndex = mChunkIndex; - - if (mChunkOffsets != NULL) { - uint32_t entryCount = U32_AT(mChunkOffsets->data() + 4); - - if (mChunkIndex >= entryCount) { - mSampleIndex = mSampleCount; - return; - } - - mNextSampleOffset = - U32_AT(mChunkOffsets->data() + 8 + 4 * mChunkIndex); - } else { - CHECK(mChunkOffsets64 != NULL); - - uint32_t entryCount = U32_AT(mChunkOffsets64->data() + 4); - - if (mChunkIndex >= entryCount) { - mSampleIndex = mSampleCount; - return; - } - - mNextSampleOffset = - U64_AT(mChunkOffsets64->data() + 8 + 8 * mChunkIndex); - } - } - - mSampleInfo.mOffset = mNextSampleOffset; - - mSampleInfo.mPresentationTime = 0; - mSampleInfo.mFlags = 0; -} - -void FragmentedMP4Parser::StaticTrackFragment::advance() { - mNextSampleOffset += mSampleInfo.mSize; - - ++mSampleIndex; - if (--mSampleToChunkRemaining == 0) { - ++mChunkIndex; - - uint32_t entryCount = U32_AT(mSampleToChunk->data() + 4); - - // If this is the last entry in the sample to chunk table, we will - // stay on this entry. - if ((uint32_t)(mSampleToChunkIndex + 1) < entryCount) { - uint32_t nextChunkIndex = - U32_AT(mSampleToChunk->data() + 8 + 12 * (mSampleToChunkIndex + 1)); - - CHECK_GE(nextChunkIndex, 1u); - --nextChunkIndex; - - if (mChunkIndex >= nextChunkIndex) { - CHECK_EQ(mChunkIndex, nextChunkIndex); - ++mSampleToChunkIndex; - } - } - - mSampleToChunkRemaining = - U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 4); - } - - updateSampleInfo(); -} - -static void setU32At(uint8_t *ptr, uint32_t x) { - ptr[0] = x >> 24; - ptr[1] = (x >> 16) & 0xff; - ptr[2] = (x >> 8) & 0xff; - ptr[3] = x & 0xff; -} - -status_t FragmentedMP4Parser::StaticTrackFragment::signalCompletion() { - mSampleToChunkIndex = 0; - - mSampleToChunkRemaining = - (mSampleToChunk == NULL) - ? 0 - : U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 4); - - updateSampleInfo(); - - return OK; -} - -bool FragmentedMP4Parser::StaticTrackFragment::complete() const { - return true; -} - -status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleSizes( - FragmentedMP4Parser *parser, - uint32_t /* type */, - size_t offset, - uint64_t size) { - if (offset + 12 > size) { - return ERROR_MALFORMED; - } - - if (parser->readU32(offset) != 0) { - return ERROR_MALFORMED; - } - - uint32_t sampleSize = parser->readU32(offset + 4); - uint32_t sampleCount = parser->readU32(offset + 8); - - if (sampleSize == 0 && offset + 12 + sampleCount * 4 != size) { - return ERROR_MALFORMED; - } - - parser->copyBuffer(&mSampleSizes, offset, size); - - mSampleCount = sampleCount; - - return OK; -} - -status_t FragmentedMP4Parser::StaticTrackFragment::parseCompactSampleSizes( - FragmentedMP4Parser *parser, - uint32_t /* type */, - size_t offset, - uint64_t size) { - if (offset + 12 > size) { - return ERROR_MALFORMED; - } - - if (parser->readU32(offset) != 0) { - return ERROR_MALFORMED; - } - - uint32_t fieldSize = parser->readU32(offset + 4); - - if (fieldSize != 4 && fieldSize != 8 && fieldSize != 16) { - return ERROR_MALFORMED; - } - - uint32_t sampleCount = parser->readU32(offset + 8); - - if (offset + 12 + (sampleCount * fieldSize + 4) / 8 != size) { - return ERROR_MALFORMED; - } - - parser->copyBuffer(&mCompactSampleSizes, offset, size); - - mSampleCount = sampleCount; - - return OK; -} - -status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleToChunk( - FragmentedMP4Parser *parser, - uint32_t /* type */, - size_t offset, - uint64_t size) { - if (offset + 8 > size) { - return ERROR_MALFORMED; - } - - if (parser->readU32(offset) != 0) { - return ERROR_MALFORMED; - } - - uint32_t entryCount = parser->readU32(offset + 4); - - if (entryCount == 0) { - return OK; - } - - if (offset + 8 + entryCount * 12 != size) { - return ERROR_MALFORMED; - } - - parser->copyBuffer(&mSampleToChunk, offset, size); - - return OK; -} - -status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets( - FragmentedMP4Parser *parser, - uint32_t /* type */, - size_t offset, - uint64_t size) { - if (offset + 8 > size) { - return ERROR_MALFORMED; - } - - if (parser->readU32(offset) != 0) { - return ERROR_MALFORMED; - } - - uint32_t entryCount = parser->readU32(offset + 4); - - if (offset + 8 + entryCount * 4 != size) { - return ERROR_MALFORMED; - } - - parser->copyBuffer(&mChunkOffsets, offset, size); - - return OK; -} - -status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets64( - FragmentedMP4Parser *parser, - uint32_t /* type */, - size_t offset, - uint64_t size) { - if (offset + 8 > size) { - return ERROR_MALFORMED; - } - - if (parser->readU32(offset) != 0) { - return ERROR_MALFORMED; - } - - uint32_t entryCount = parser->readU32(offset + 4); - - if (offset + 8 + entryCount * 8 != size) { - return ERROR_MALFORMED; - } - - parser->copyBuffer(&mChunkOffsets64, offset, size); - - return OK; -} - -} // namespace android - diff --git a/media/libstagefright/mp4/TrackFragment.h b/media/libstagefright/mp4/TrackFragment.h deleted file mode 100644 index e1ad46e..0000000 --- a/media/libstagefright/mp4/TrackFragment.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2012 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 TRACK_FRAGMENT_H_ - -#define TRACK_FRAGMENT_H_ - -#include "include/FragmentedMP4Parser.h" - -namespace android { - -struct FragmentedMP4Parser::TrackFragment : public RefBase { - TrackFragment() {} - - virtual status_t getSample(SampleInfo *info) = 0; - virtual void advance() = 0; - - virtual status_t signalCompletion() = 0; - virtual bool complete() const = 0; - -protected: - virtual ~TrackFragment() {} - -private: - DISALLOW_EVIL_CONSTRUCTORS(TrackFragment); -}; - -struct FragmentedMP4Parser::DynamicTrackFragment : public FragmentedMP4Parser::TrackFragment { - DynamicTrackFragment(); - - virtual status_t getSample(SampleInfo *info); - virtual void advance(); - - void addSample( - off64_t dataOffset, size_t sampleSize, - uint32_t presentationTime, - size_t sampleDescIndex, - uint32_t flags); - - // No more samples will be added to this fragment. - virtual status_t signalCompletion(); - - virtual bool complete() const; - -protected: - virtual ~DynamicTrackFragment(); - -private: - bool mComplete; - size_t mSampleIndex; - Vector mSamples; - - DISALLOW_EVIL_CONSTRUCTORS(DynamicTrackFragment); -}; - -struct FragmentedMP4Parser::StaticTrackFragment : public FragmentedMP4Parser::TrackFragment { - StaticTrackFragment(); - - virtual status_t getSample(SampleInfo *info); - virtual void advance(); - - virtual status_t signalCompletion(); - virtual bool complete() const; - - status_t parseSampleSizes( - FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size); - - status_t parseCompactSampleSizes( - FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size); - - status_t parseSampleToChunk( - FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size); - - status_t parseChunkOffsets( - FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size); - - status_t parseChunkOffsets64( - FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size); - -protected: - virtual ~StaticTrackFragment(); - -private: - size_t mSampleIndex; - size_t mSampleCount; - uint32_t mChunkIndex; - - SampleInfo mSampleInfo; - - sp mSampleSizes; - sp mCompactSampleSizes; - - sp mSampleToChunk; - ssize_t mSampleToChunkIndex; - size_t mSampleToChunkRemaining; - - sp mChunkOffsets; - sp mChunkOffsets64; - uint32_t mPrevChunkIndex; - uint64_t mNextSampleOffset; - - void updateSampleInfo(); - - DISALLOW_EVIL_CONSTRUCTORS(StaticTrackFragment); -}; - -} // namespace android - -#endif // TRACK_FRAGMENT_H_ -- cgit v1.1 From 8dd1c202aea703ed8beacaaa0dad5ae9c76a0863 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 6 Feb 2014 14:01:30 -0800 Subject: LiveSession: Add support for block-by-block fetchFile. Change-Id: I4025ba7fab8fab2e0c720f73894e908fd98a43d8 --- media/libstagefright/httplive/LiveSession.cpp | 97 +++++++++++++++++---------- media/libstagefright/httplive/LiveSession.h | 18 ++++- 2 files changed, 80 insertions(+), 35 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 149a817..f0a1c36 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -507,53 +507,80 @@ sp LiveSession::addFetcher(const char *uri) { return info.mFetcher; } +/* + * Illustration of parameters: + * + * 0 `range_offset` + * +------------+-------------------------------------------------------+--+--+ + * | | | next block to fetch | | | + * | | `source` handle => `out` buffer | | | | + * | `url` file |<--------- buffer size --------->|<--- `block_size` -->| | | + * | |<----------- `range_length` / buffer capacity ----------->| | + * |<------------------------------ file_size ------------------------------->| + * + * Special parameter values: + * - range_length == -1 means entire file + * - block_size == 0 means entire range + * + */ status_t LiveSession::fetchFile( const char *url, sp *out, - int64_t range_offset, int64_t range_length) { - *out = NULL; + int64_t range_offset, int64_t range_length, + uint32_t block_size, /* download block size */ + sp *source /* to return and reuse source */) { + off64_t size; + sp temp_source; + if (source == NULL) { + source = &temp_source; + } - sp source; + if (*source == NULL) { + if (!strncasecmp(url, "file://", 7)) { + *source = new FileSource(url + 7); + } else if (strncasecmp(url, "http://", 7) + && strncasecmp(url, "https://", 8)) { + return ERROR_UNSUPPORTED; + } else { + KeyedVector headers = mExtraHeaders; + if (range_offset > 0 || range_length >= 0) { + headers.add( + String8("Range"), + String8( + StringPrintf( + "bytes=%lld-%s", + range_offset, + range_length < 0 + ? "" : StringPrintf("%lld", + range_offset + range_length - 1).c_str()).c_str())); + } + status_t err = mHTTPDataSource->connect(url, &headers); - if (!strncasecmp(url, "file://", 7)) { - source = new FileSource(url + 7); - } else if (strncasecmp(url, "http://", 7) - && strncasecmp(url, "https://", 8)) { - return ERROR_UNSUPPORTED; - } else { - KeyedVector headers = mExtraHeaders; - if (range_offset > 0 || range_length >= 0) { - headers.add( - String8("Range"), - String8( - StringPrintf( - "bytes=%lld-%s", - range_offset, - range_length < 0 - ? "" : StringPrintf("%lld", range_offset + range_length - 1).c_str()).c_str())); - } - status_t err = mHTTPDataSource->connect(url, &headers); + if (err != OK) { + return err; + } - if (err != OK) { - return err; + *source = mHTTPDataSource; } - - source = mHTTPDataSource; } - off64_t size; - status_t err = source->getSize(&size); - - if (err != OK) { + status_t getSizeErr = (*source)->getSize(&size); + if (getSizeErr != OK) { size = 65536; } - sp buffer = new ABuffer(size); - buffer->setRange(0, 0); + sp buffer = *out != NULL ? *out : new ABuffer(size); + if (*out == NULL) { + buffer->setRange(0, 0); + } + // adjust range_length if only reading partial block + if (block_size > 0 && (range_length == -1 || buffer->size() + block_size < range_length)) { + range_length = buffer->size() + block_size; + } for (;;) { + // Only resize when we don't know the size. size_t bufferRemaining = buffer->capacity() - buffer->size(); - - if (bufferRemaining == 0) { + if (bufferRemaining == 0 && getSizeErr != OK) { bufferRemaining = 32768; ALOGV("increasing download buffer to %d bytes", @@ -578,7 +605,9 @@ status_t LiveSession::fetchFile( } } - ssize_t n = source->readAt( + // The DataSource is responsible for informing us of error (n < 0) or eof (n == 0) + // to help us break out of the loop. + ssize_t n = (*source)->readAt( buffer->size(), buffer->data() + buffer->size(), maxBytesToRead); diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index ee10e70..00569be 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -146,9 +146,25 @@ private: status_t onSeek(const sp &msg); void onFinishDisconnect2(); + // If given a non-zero block_size (default 0), it is used to cap the number of + // bytes read in from the DataSource. If given a non-NULL buffer, new content + // is read into the end. + // + // The DataSource we read from is responsible for signaling error or EOF to help us + // break out of the read loop. The DataSource can be returned to the caller, so + // that the caller can reuse it for subsequent fetches (within the initially + // requested range). + // + // For reused HTTP sources, the caller must download a file sequentially without + // any overlaps or gaps to prevent reconnection. status_t fetchFile( const char *url, sp *out, - int64_t range_offset = 0, int64_t range_length = -1); + /* request/open a file starting at range_offset for range_length bytes */ + int64_t range_offset = 0, int64_t range_length = -1, + /* download block size */ + uint32_t block_size = 0, + /* reuse DataSource if doing partial fetch */ + sp *source = NULL); sp fetchPlaylist( const char *url, uint8_t *curPlaylistHash, bool *unchanged); -- cgit v1.1 From ebe130923fb1a5b8dda4b3ee215593edcd804f0d Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 6 Feb 2014 14:25:25 -0800 Subject: PlaylistFetcher: Add support for block-by-block decryption. Change-Id: Ifd3f3369275889e716b360087b5b60d01635b578 --- media/libstagefright/httplive/PlaylistFetcher.cpp | 95 ++++++++++++++--------- media/libstagefright/httplive/PlaylistFetcher.h | 17 +++- 2 files changed, 75 insertions(+), 37 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index f095987..9cb16fe 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -170,7 +170,8 @@ int64_t PlaylistFetcher::delayUsToRefreshPlaylist() const { } status_t PlaylistFetcher::decryptBuffer( - size_t playlistIndex, const sp &buffer) { + size_t playlistIndex, const sp &buffer, + bool first) { sp itemMeta; bool found = false; AString method; @@ -188,6 +189,7 @@ status_t PlaylistFetcher::decryptBuffer( if (!found) { method = "NONE"; } + buffer->meta()->setString("cipher-method", method.c_str()); if (method == "NONE") { return OK; @@ -227,59 +229,77 @@ status_t PlaylistFetcher::decryptBuffer( return UNKNOWN_ERROR; } - unsigned char aes_ivec[16]; + size_t n = buffer->size(); + if (!n) { + return OK; + } + CHECK(n % 16 == 0); - AString iv; - if (itemMeta->findString("cipher-iv", &iv)) { - if ((!iv.startsWith("0x") && !iv.startsWith("0X")) - || iv.size() != 16 * 2 + 2) { - ALOGE("malformed cipher IV '%s'.", iv.c_str()); - return ERROR_MALFORMED; - } + if (first) { + // If decrypting the first block in a file, read the iv from the manifest + // or derive the iv from the file's sequence number. - memset(aes_ivec, 0, sizeof(aes_ivec)); - for (size_t i = 0; i < 16; ++i) { - char c1 = tolower(iv.c_str()[2 + 2 * i]); - char c2 = tolower(iv.c_str()[3 + 2 * i]); - if (!isxdigit(c1) || !isxdigit(c2)) { + AString iv; + if (itemMeta->findString("cipher-iv", &iv)) { + if ((!iv.startsWith("0x") && !iv.startsWith("0X")) + || iv.size() != 16 * 2 + 2) { ALOGE("malformed cipher IV '%s'.", iv.c_str()); return ERROR_MALFORMED; } - uint8_t nibble1 = isdigit(c1) ? c1 - '0' : c1 - 'a' + 10; - uint8_t nibble2 = isdigit(c2) ? c2 - '0' : c2 - 'a' + 10; - aes_ivec[i] = nibble1 << 4 | nibble2; + memset(mAESInitVec, 0, sizeof(mAESInitVec)); + for (size_t i = 0; i < 16; ++i) { + char c1 = tolower(iv.c_str()[2 + 2 * i]); + char c2 = tolower(iv.c_str()[3 + 2 * i]); + if (!isxdigit(c1) || !isxdigit(c2)) { + ALOGE("malformed cipher IV '%s'.", iv.c_str()); + return ERROR_MALFORMED; + } + uint8_t nibble1 = isdigit(c1) ? c1 - '0' : c1 - 'a' + 10; + uint8_t nibble2 = isdigit(c2) ? c2 - '0' : c2 - 'a' + 10; + + mAESInitVec[i] = nibble1 << 4 | nibble2; + } + } else { + memset(mAESInitVec, 0, sizeof(mAESInitVec)); + mAESInitVec[15] = mSeqNumber & 0xff; + mAESInitVec[14] = (mSeqNumber >> 8) & 0xff; + mAESInitVec[13] = (mSeqNumber >> 16) & 0xff; + mAESInitVec[12] = (mSeqNumber >> 24) & 0xff; } - } else { - memset(aes_ivec, 0, sizeof(aes_ivec)); - aes_ivec[15] = mSeqNumber & 0xff; - aes_ivec[14] = (mSeqNumber >> 8) & 0xff; - aes_ivec[13] = (mSeqNumber >> 16) & 0xff; - aes_ivec[12] = (mSeqNumber >> 24) & 0xff; } AES_cbc_encrypt( buffer->data(), buffer->data(), buffer->size(), - &aes_key, aes_ivec, AES_DECRYPT); - - // hexdump(buffer->data(), buffer->size()); + &aes_key, mAESInitVec, AES_DECRYPT); - size_t n = buffer->size(); - CHECK_GT(n, 0u); + return OK; +} - size_t pad = buffer->data()[n - 1]; +status_t PlaylistFetcher::checkDecryptPadding(const sp &buffer) { + status_t err; + AString method; + CHECK(buffer->meta()->findString("cipher-method", &method)); + if (method == "NONE") { + return OK; + } - CHECK_GT(pad, 0u); - CHECK_LE(pad, 16u); - CHECK_GE((size_t)n, pad); - for (size_t i = 0; i < pad; ++i) { - CHECK_EQ((unsigned)buffer->data()[n - 1 - i], pad); + uint8_t padding = 0; + if (buffer->size() > 0) { + padding = buffer->data()[buffer->size() - 1]; } - n -= pad; + if (padding > 16) { + return ERROR_MALFORMED; + } - buffer->setRange(buffer->offset(), n); + for (size_t i = buffer->size() - padding; i < padding; i++) { + if (buffer->data()[i] != padding) { + return ERROR_MALFORMED; + } + } + buffer->setRange(buffer->offset(), buffer->size() - padding); return OK; } @@ -706,6 +726,9 @@ void PlaylistFetcher::onDownloadNext() { CHECK(buffer != NULL); err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer); + if (err == OK) { + err = checkDecryptPadding(buffer); + } if (err != OK) { ALOGE("decryptBuffer failed w/ error %d", err); diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index 78dea20..ac04a77 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -119,8 +119,23 @@ private: uint64_t mFirstPTS; int64_t mAbsoluteTimeAnchorUs; + // Stores the initialization vector to decrypt the next block of cipher text, which can + // either be derived from the sequence number, read from the manifest, or copied from + // the last block of cipher text (cipher-block chaining). + unsigned char mAESInitVec[16]; + + // Set first to true if decrypting the first segment of a playlist segment. When + // first is true, reset the initialization vector based on the available + // information in the manifest; otherwise, use the initialization vector as + // updated by the last call to AES_cbc_encrypt. + // + // For the input to decrypt correctly, decryptBuffer must be called on + // consecutive byte ranges on block boundaries, e.g. 0..15, 16..47, 48..63, + // and so on. status_t decryptBuffer( - size_t playlistIndex, const sp &buffer); + size_t playlistIndex, const sp &buffer, + bool first = true); + status_t checkDecryptPadding(const sp &buffer); void postMonitorQueue(int64_t delayUs = 0, int64_t minDelayUs = 0); void cancelMonitorQueue(); -- cgit v1.1 From 6dc91c957cfad4393b205a3c2f8421e549fa7e85 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Fri, 14 Feb 2014 14:53:16 -0800 Subject: Skip scaling_list definitions in AVC seq header. Change-Id: Iad013550d9c5aecf3504624eddfc13e680162bf3 related-to-bug: 13030256 --- media/libstagefright/avc_utils.cpp | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp index c6ac0da..38a1f6b 100644 --- a/media/libstagefright/avc_utils.cpp +++ b/media/libstagefright/avc_utils.cpp @@ -40,6 +40,25 @@ unsigned parseUE(ABitReader *br) { return x + (1u << numZeroes) - 1; } +signed parseSE(ABitReader *br) { + unsigned codeNum = parseUE(br); + + return (codeNum & 1) ? (codeNum + 1) / 2 : -(codeNum / 2); +} + +static void skipScalingList(ABitReader *br, size_t sizeOfScalingList) { + size_t lastScale = 8; + size_t nextScale = 8; + for (size_t j = 0; j < sizeOfScalingList; ++j) { + if (nextScale != 0) { + signed delta_scale = parseSE(br); + nextScale = (lastScale + delta_scale + 256) % 256; + } + + lastScale = (nextScale == 0) ? lastScale : nextScale; + } +} + // Determine video dimensions from the sequence parameterset. void FindAVCDimensions( const sp &seqParamSet, @@ -63,7 +82,24 @@ void FindAVCDimensions( parseUE(&br); // bit_depth_luma_minus8 parseUE(&br); // bit_depth_chroma_minus8 br.skipBits(1); // qpprime_y_zero_transform_bypass_flag - CHECK_EQ(br.getBits(1), 0u); // seq_scaling_matrix_present_flag + + if (br.getBits(1)) { // seq_scaling_matrix_present_flag + for (size_t i = 0; i < 8; ++i) { + if (br.getBits(1)) { // seq_scaling_list_present_flag[i] + + // WARNING: the code below has not ever been exercised... + // need a real-world example. + + if (i < 6) { + // ScalingList4x4[i],16,... + skipScalingList(&br, 16); + } else { + // ScalingList8x8[i-6],64,... + skipScalingList(&br, 64); + } + } + } + } } parseUE(&br); // log2_max_frame_num_minus4 -- cgit v1.1 From b63d2433350d56bda9f3477549086c90bb6d535e Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Fri, 14 Feb 2014 15:26:00 -0800 Subject: fix codec buffer leak in error handling when timestamp goes backward don't touch codec buffer if we decided to drop a frame with bad pts Bug: 11971963 Change-Id: I9b4c56210f64258f1be257b14184381a1133e0d6 --- media/libstagefright/omx/GraphicBufferSource.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 1e6de55..8d65a1f 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -574,7 +574,7 @@ int64_t GraphicBufferSource::getTimestamp(const BufferQueue::BufferItem &item) { if (originalTimeUs < mPrevOriginalTimeUs) { // Drop the frame if it's going backward in time. Bad timestamp // could disrupt encoder's rate control completely. - ALOGV("Dropping frame that's going backward in time"); + ALOGW("Dropping frame that's going backward in time"); return -1; } int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs; @@ -593,6 +593,12 @@ int64_t GraphicBufferSource::getTimestamp(const BufferQueue::BufferItem &item) { status_t GraphicBufferSource::submitBuffer_l( const BufferQueue::BufferItem &item, int cbi) { ALOGV("submitBuffer_l cbi=%d", cbi); + + int64_t timeUs = getTimestamp(item); + if (timeUs < 0ll) { + return UNKNOWN_ERROR; + } + CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); codecBuffer.mGraphicBuffer = mBufferSlot[item.mBuf]; codecBuffer.mBuf = item.mBuf; @@ -606,12 +612,6 @@ status_t GraphicBufferSource::submitBuffer_l( memcpy(data, &type, 4); memcpy(data + 4, &handle, sizeof(buffer_handle_t)); - int64_t timeUs = getTimestamp(item); - if (timeUs < 0ll) { - ALOGE("Dropping frame with bad timestamp"); - return UNKNOWN_ERROR; - } - status_t err = mNodeInstance->emptyDirectBuffer(header, 0, 4 + sizeof(buffer_handle_t), OMX_BUFFERFLAG_ENDOFFRAME, timeUs); -- cgit v1.1 From 2c9c8cba8562cc3a27532e4cd348912cc78d8d98 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 11 Feb 2014 13:54:59 -0800 Subject: support for time lapse/slow motion when using SURFACE source Bug: 13032650 Change-Id: Iecbadf9f29c8c49353416fc467fb3acdde279595 --- .../libmediaplayerservice/StagefrightRecorder.cpp | 17 ++++++-- media/libstagefright/ACodec.cpp | 36 ++++++++++++++--- media/libstagefright/Utils.cpp | 5 +++ media/libstagefright/omx/GraphicBufferSource.cpp | 46 ++++++++++++++++++++-- media/libstagefright/omx/GraphicBufferSource.h | 13 ++++++ media/libstagefright/omx/OMXNodeInstance.cpp | 9 ++++- 6 files changed, 114 insertions(+), 12 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index e0eae37..a20c1d2 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -690,10 +690,10 @@ status_t StagefrightRecorder::setParameter( return setParamTimeLapseEnable(timeLapseEnable); } } else if (key == "time-between-time-lapse-frame-capture") { - int64_t timeBetweenTimeLapseFrameCaptureMs; - if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureMs)) { + int64_t timeBetweenTimeLapseFrameCaptureUs; + if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureUs)) { return setParamTimeBetweenTimeLapseFrameCapture( - 1000LL * timeBetweenTimeLapseFrameCaptureMs); + timeBetweenTimeLapseFrameCaptureUs); } } else { ALOGE("setParameter: failed to find key %s", key.string()); @@ -1436,6 +1436,17 @@ status_t StagefrightRecorder::setupVideoEncoder( format->setInt32("stride", mVideoWidth); format->setInt32("slice-height", mVideoWidth); format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque); + + // set up time lapse/slow motion for surface source + if (mCaptureTimeLapse) { + if (mTimeBetweenTimeLapseFrameCaptureUs <= 0) { + ALOGE("Invalid mTimeBetweenTimeLapseFrameCaptureUs value: %lld", + mTimeBetweenTimeLapseFrameCaptureUs); + return BAD_VALUE; + } + format->setInt64("time-lapse", + mTimeBetweenTimeLapseFrameCaptureUs); + } } format->setInt32("bitrate", mVideoBitRate); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index f2354b4..3d5b3b3 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -374,7 +374,9 @@ ACodec::ACodec() mStoreMetaDataInOutputBuffers(false), mMetaDataBuffersToSubmit(0), mRepeatFrameDelayUs(-1ll), - mMaxPtsGapUs(-1l), + mMaxPtsGapUs(-1ll), + mTimePerCaptureUs(-1ll), + mTimePerFrameUs(-1ll), mCreateInputBuffersSuspended(false) { mUninitializedState = new UninitializedState(this); mLoadedState = new LoadedState(this); @@ -1119,7 +1121,11 @@ status_t ACodec::configureCodec( } if (!msg->findInt64("max-pts-gap-to-encoder", &mMaxPtsGapUs)) { - mMaxPtsGapUs = -1l; + mMaxPtsGapUs = -1ll; + } + + if (!msg->findInt64("time-lapse", &mTimePerCaptureUs)) { + mTimePerCaptureUs = -1ll; } if (!msg->findInt32( @@ -1916,6 +1922,7 @@ status_t ACodec::setupVideoEncoder(const char *mime, const sp &msg) { return INVALID_OPERATION; } frameRate = (float)tmp; + mTimePerFrameUs = (int64_t) (1000000.0f / frameRate); } video_def->xFramerate = (OMX_U32)(frameRate * 65536.0f); @@ -3938,7 +3945,7 @@ void ACodec::LoadedState::onCreateInputSurface( } } - if (err == OK && mCodec->mMaxPtsGapUs > 0l) { + if (err == OK && mCodec->mMaxPtsGapUs > 0ll) { err = mCodec->mOMX->setInternalOption( mCodec->mNode, kPortIndexInput, @@ -3950,8 +3957,27 @@ void ACodec::LoadedState::onCreateInputSurface( ALOGE("[%s] Unable to configure max timestamp gap (err %d)", mCodec->mComponentName.c_str(), err); - } - } + } + } + + if (err == OK && mCodec->mTimePerCaptureUs > 0ll + && mCodec->mTimePerFrameUs > 0ll) { + int64_t timeLapse[2]; + timeLapse[0] = mCodec->mTimePerFrameUs; + timeLapse[1] = mCodec->mTimePerCaptureUs; + err = mCodec->mOMX->setInternalOption( + mCodec->mNode, + kPortIndexInput, + IOMX::INTERNAL_OPTION_TIME_LAPSE, + &timeLapse[0], + sizeof(timeLapse)); + + if (err != OK) { + ALOGE("[%s] Unable to configure time lapse (err %d)", + mCodec->mComponentName.c_str(), + err); + } + } if (err == OK && mCodec->mCreateInputBuffersSuspended) { bool suspend = true; diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 216a329..451e907 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -452,6 +452,11 @@ void convertMessageToMetaData(const sp &msg, sp &meta) { } } + int32_t timeScale; + if (msg->findInt32("time-scale", &timeScale)) { + meta->setInt32(kKeyTimeScale, timeScale); + } + // XXX TODO add whatever other keys there are #if 0 diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 8d65a1f..83f4e0a 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -51,7 +51,11 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, mLatestSubmittedBufferId(-1), mLatestSubmittedBufferFrameNum(0), mLatestSubmittedBufferUseCount(0), - mRepeatBufferDeferred(false) { + mRepeatBufferDeferred(false), + mTimePerCaptureUs(-1ll), + mTimePerFrameUs(-1ll), + mPrevCaptureUs(-1ll), + mPrevFrameUs(-1ll) { ALOGV("GraphicBufferSource w=%u h=%u c=%u", bufferWidth, bufferHeight, bufferCount); @@ -560,7 +564,30 @@ status_t GraphicBufferSource::signalEndOfInputStream() { int64_t GraphicBufferSource::getTimestamp(const BufferQueue::BufferItem &item) { int64_t timeUs = item.mTimestamp / 1000; - if (mMaxTimestampGapUs > 0ll) { + if (mTimePerCaptureUs > 0ll) { + // Time lapse or slow motion mode + if (mPrevCaptureUs < 0ll) { + // first capture + mPrevCaptureUs = timeUs; + mPrevFrameUs = timeUs; + } else { + // snap to nearest capture point + int64_t nFrames = (timeUs + mTimePerCaptureUs / 2 - mPrevCaptureUs) + / mTimePerCaptureUs; + if (nFrames <= 0) { + // skip this frame as it's too close to previous capture + ALOGV("skipping frame, timeUs %lld", timeUs); + return -1; + } + mPrevCaptureUs = mPrevCaptureUs + nFrames * mTimePerCaptureUs; + mPrevFrameUs += mTimePerFrameUs * nFrames; + } + + ALOGV("timeUs %lld, captureUs %lld, frameUs %lld", + timeUs, mPrevCaptureUs, mPrevFrameUs); + + return mPrevFrameUs; + } else if (mMaxTimestampGapUs > 0ll) { /* Cap timestamp gap between adjacent frames to specified max * * In the scenario of cast mirroring, encoding could be suspended for @@ -711,7 +738,7 @@ void GraphicBufferSource::onFrameAvailable() { // If this is the first time we're seeing this buffer, add it to our // slot table. if (item.mGraphicBuffer != NULL) { - ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf); + ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mBuf); mBufferSlot[item.mBuf] = item.mGraphicBuffer; } mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, @@ -782,6 +809,19 @@ void GraphicBufferSource::setSkipFramesBeforeUs(int64_t skipFramesBeforeUs) { (skipFramesBeforeUs > 0) ? (skipFramesBeforeUs * 1000) : -1ll; } +status_t GraphicBufferSource::setTimeLapseUs(int64_t* data) { + Mutex::Autolock autoLock(mMutex); + + if (mExecuting || data[0] <= 0ll || data[1] <= 0ll) { + return INVALID_OPERATION; + } + + mTimePerFrameUs = data[0]; + mTimePerCaptureUs = data[1]; + + return OK; +} + void GraphicBufferSource::onMessageReceived(const sp &msg) { switch (msg->what()) { case kWhatRepeatLastFrame: diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index 153f2a0..fba42b7 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -118,6 +118,13 @@ public: // of suspension on input. status_t setMaxTimestampGapUs(int64_t maxGapUs); + // Sets the time lapse (or slow motion) parameters. + // data[0] is the time (us) between two frames for playback + // data[1] is the time (us) between two frames for capture + // When set, the sample's timestamp will be modified to playback framerate, + // and capture timestamp will be modified to capture rate. + status_t setTimeLapseUs(int64_t* data); + // Sets the start time us (in system time), samples before which should // be dropped and not submitted to encoder void setSkipFramesBeforeUs(int64_t startTimeUs); @@ -250,6 +257,12 @@ private: // no codec buffer was available at the time. bool mRepeatBufferDeferred; + // Time lapse / slow motion configuration + int64_t mTimePerCaptureUs; + int64_t mTimePerFrameUs; + int64_t mPrevCaptureUs; + int64_t mPrevFrameUs; + void onMessageReceived(const sp &msg); DISALLOW_EVIL_CONSTRUCTORS(GraphicBufferSource); diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index dba522f..f3600ba 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -851,6 +851,7 @@ status_t OMXNodeInstance::setInternalOption( case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY: case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: case IOMX::INTERNAL_OPTION_START_TIME: + case IOMX::INTERNAL_OPTION_TIME_LAPSE: { const sp &bufferSource = getGraphicBufferSource(); @@ -884,7 +885,7 @@ status_t OMXNodeInstance::setInternalOption( int64_t maxGapUs = *(int64_t *)data; return bufferSource->setMaxTimestampGapUs(maxGapUs); - } else { // IOMX::INTERNAL_OPTION_START_TIME + } else if (type == IOMX::INTERNAL_OPTION_START_TIME) { if (size != sizeof(int64_t)) { return INVALID_OPERATION; } @@ -892,6 +893,12 @@ status_t OMXNodeInstance::setInternalOption( int64_t skipFramesBeforeUs = *(int64_t *)data; bufferSource->setSkipFramesBeforeUs(skipFramesBeforeUs); + } else { // IOMX::INTERNAL_OPTION_TIME_LAPSE + if (size != sizeof(int64_t) * 2) { + return INVALID_OPERATION; + } + + bufferSource->setTimeLapseUs((int64_t *)data); } return OK; -- cgit v1.1 From 7074296c72b3be919ebc9dfd504f4572a188d2e7 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 18 Feb 2014 08:00:47 -0800 Subject: Fix warning due to incorrect log format Change-Id: I58ff399ace74965ebf8e5690c20637385f9425ad --- media/libmedia/IAudioFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 7b15e68..e696323 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -988,7 +988,7 @@ status_t BnAudioFlinger::onTransact( &latency, flags, hasOffloadInfo ? &offloadInfo : NULL); - ALOGV("OPEN_OUTPUT output, %p", output); + ALOGV("OPEN_OUTPUT output, %d", output); reply->writeInt32((int32_t) output); reply->writeInt32(devices); reply->writeInt32(samplingRate); -- cgit v1.1 From 26cee964ab4e0a2bd6ae9ad199ba78ea9634421c Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Fri, 14 Feb 2014 15:07:21 -0800 Subject: Handle recording failure more gracefully. Bug: 13027666 Change-Id: Iec8239bfcd293c8f466b3780e69883b97f387949 --- media/libstagefright/CameraSource.cpp | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'media') diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index f3ff792..b31e9e8 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -586,14 +586,15 @@ CameraSource::~CameraSource() { } } -void CameraSource::startCameraRecording() { +status_t CameraSource::startCameraRecording() { ALOGV("startCameraRecording"); // Reset the identity to the current thread because media server owns the // camera and recording is started by the applications. The applications // will connect to the camera in ICameraRecordingProxy::startRecording. int64_t token = IPCThreadState::self()->clearCallingIdentity(); + status_t err; if (mNumInputBuffers > 0) { - status_t err = mCamera->sendCommand( + err = mCamera->sendCommand( CAMERA_CMD_SET_VIDEO_BUFFER_COUNT, mNumInputBuffers, 0); // This could happen for CameraHAL1 clients; thus the failure is @@ -604,17 +605,25 @@ void CameraSource::startCameraRecording() { } } + err = OK; if (mCameraFlags & FLAGS_HOT_CAMERA) { mCamera->unlock(); mCamera.clear(); - CHECK_EQ((status_t)OK, - mCameraRecordingProxy->startRecording(new ProxyListener(this))); + if ((err = mCameraRecordingProxy->startRecording( + new ProxyListener(this))) != OK) { + ALOGE("Failed to start recording, received error: %s (%d)", + strerror(-err), err); + } } else { mCamera->setListener(new CameraSourceListener(this)); mCamera->startRecording(); - CHECK(mCamera->recordingEnabled()); + if (!mCamera->recordingEnabled()) { + err = -EINVAL; + ALOGE("Failed to start recording"); + } } IPCThreadState::self()->restoreCallingIdentity(token); + return err; } status_t CameraSource::start(MetaData *meta) { @@ -646,10 +655,12 @@ status_t CameraSource::start(MetaData *meta) { } } - startCameraRecording(); + status_t err; + if ((err = startCameraRecording()) == OK) { + mStarted = true; + } - mStarted = true; - return OK; + return err; } void CameraSource::stopCameraRecording() { -- cgit v1.1 From ebfd32300605d67e4c45a97f4972d4b6ea268a37 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 18 Feb 2014 10:27:04 -0800 Subject: Fix crash when seeking fragmented mp4 files Rewinding a fragmented mp4 file without a segment index (sidx) after playing it to the end would crash. b/13028840 Change-Id: I280e74364589f0acefd432a59f85a6594c009a21 --- media/libstagefright/MPEG4Extractor.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 4756b3e..81ed6f7 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -3719,11 +3719,19 @@ status_t MPEG4Source::fragmentedRead( totalTime += se->mDurationUs; totalOffset += se->mSize; } - mCurrentMoofOffset = totalOffset; - mCurrentSamples.clear(); - mCurrentSampleIndex = 0; - parseChunk(&totalOffset); - mCurrentTime = totalTime * mTimescale / 1000000ll; + mCurrentMoofOffset = totalOffset; + mCurrentSamples.clear(); + mCurrentSampleIndex = 0; + parseChunk(&totalOffset); + mCurrentTime = totalTime * mTimescale / 1000000ll; + } else { + // without sidx boxes, we can only seek to 0 + mCurrentMoofOffset = mFirstMoofOffset; + mCurrentSamples.clear(); + mCurrentSampleIndex = 0; + off64_t tmp = mCurrentMoofOffset; + parseChunk(&tmp); + mCurrentTime = 0; } if (mBuffer != NULL) { @@ -3744,15 +3752,14 @@ status_t MPEG4Source::fragmentedRead( if (mCurrentSampleIndex >= mCurrentSamples.size()) { // move to next fragment - Sample lastSample = mCurrentSamples[mCurrentSamples.size() - 1]; - off64_t nextMoof = mNextMoofOffset; // lastSample.offset + lastSample.size; + off64_t nextMoof = mNextMoofOffset; mCurrentMoofOffset = nextMoof; mCurrentSamples.clear(); mCurrentSampleIndex = 0; parseChunk(&nextMoof); - if (mCurrentSampleIndex >= mCurrentSamples.size()) { - return ERROR_END_OF_STREAM; - } + if (mCurrentSampleIndex >= mCurrentSamples.size()) { + return ERROR_END_OF_STREAM; + } } const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex]; -- cgit v1.1 From 4e01ef6b2f6d288b9aa83b5817adad02cecc429f Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 11 Jul 2013 14:29:59 -0700 Subject: Add private method NBLog::Reader::dumpLine() This allows us to abstract out fdprintf vs ALOGI so that callers don't need an 'if' at every location. Change-Id: I4c68185fc19f32caeaed93347e6b7d09b8d4c4d8 --- media/libnbaio/NBLog.cpp | 80 ++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 37 deletions(-) (limited to 'media') diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp index 190824d..895fd60 100644 --- a/media/libnbaio/NBLog.cpp +++ b/media/libnbaio/NBLog.cpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace android { @@ -337,25 +338,25 @@ void NBLog::Reader::dump(int fd, size_t indent) } i -= length + 3; } + mFd = fd; + mIndent = indent; + String8 timestamp, body; if (i > 0) { lost += i; - if (fd >= 0) { - fdprintf(fd, "%*swarning: lost %zu bytes worth of events\n", indent, "", lost); - } else { - ALOGI("%*swarning: lost %u bytes worth of events\n", indent, "", lost); - } + body.appendFormat("warning: lost %u bytes worth of events", lost); + // TODO timestamp empty here, only other choice to wait for the first timestamp event in the + // log to push it out. Consider keeping the timestamp/body between calls to readAt(). + dumpLine(timestamp, body); } size_t width = 1; while (maxSec >= 10) { ++width; maxSec /= 10; } - char prefix[32]; if (maxSec >= 0) { - snprintf(prefix, sizeof(prefix), "[%*s] ", width + 4, ""); - } else { - prefix[0] = '\0'; + timestamp.appendFormat("[%*s]", width + 4, ""); } + bool deferredTimestamp = false; while (i < avail) { event = (Event) copy[i]; length = copy[i + 1]; @@ -363,11 +364,8 @@ void NBLog::Reader::dump(int fd, size_t indent) size_t advance = length + 3; switch (event) { case EVENT_STRING: - if (fd >= 0) { - fdprintf(fd, "%*s%s%.*s\n", indent, "", prefix, length, (const char *) data); - } else { - ALOGI("%*s%s%.*s", indent, "", prefix, length, (const char *) data); - } break; + body.appendFormat("%.*s", length, (const char *) data); + break; case EVENT_TIMESTAMP: { // already checked that length == sizeof(struct timespec); memcpy(&ts, data, sizeof(struct timespec)); @@ -400,45 +398,53 @@ void NBLog::Reader::dump(int fd, size_t indent) prevNsec = tsNext.tv_nsec; } size_t n = (j - i) / (sizeof(struct timespec) + 3); + if (deferredTimestamp) { + dumpLine(timestamp, body); + deferredTimestamp = false; + } + timestamp.clear(); if (n >= kSquashTimestamp) { - if (fd >= 0) { - fdprintf(fd, "%*s[%d.%03d to .%.03d by .%.03d to .%.03d]\n", indent, "", - (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000), - (int) ((ts.tv_nsec + deltaTotal) / 1000000), - (int) (deltaMin / 1000000), (int) (deltaMax / 1000000)); - } else { - ALOGI("%*s[%d.%03d to .%.03d by .%.03d to .%.03d]\n", indent, "", - (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000), - (int) ((ts.tv_nsec + deltaTotal) / 1000000), - (int) (deltaMin / 1000000), (int) (deltaMax / 1000000)); - } + timestamp.appendFormat("[%d.%03d to .%.03d by .%.03d to .%.03d]", + (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000), + (int) ((ts.tv_nsec + deltaTotal) / 1000000), + (int) (deltaMin / 1000000), (int) (deltaMax / 1000000)); i = j; advance = 0; break; } - if (fd >= 0) { - fdprintf(fd, "%*s[%d.%03d]\n", indent, "", (int) ts.tv_sec, - (int) (ts.tv_nsec / 1000000)); - } else { - ALOGI("%*s[%d.%03d]", indent, "", (int) ts.tv_sec, - (int) (ts.tv_nsec / 1000000)); - } + timestamp.appendFormat("[%d.%03d]", (int) ts.tv_sec, + (int) (ts.tv_nsec / 1000000)); + deferredTimestamp = true; } break; case EVENT_RESERVED: default: - if (fd >= 0) { - fdprintf(fd, "%*s%swarning: unknown event %d\n", indent, "", prefix, event); - } else { - ALOGI("%*s%swarning: unknown event %d", indent, "", prefix, event); - } + body.appendFormat("warning: unknown event %d", event); break; } i += advance; + + if (!body.isEmpty()) { + dumpLine(timestamp, body); + deferredTimestamp = false; + } + } + if (deferredTimestamp) { + dumpLine(timestamp, body); } // FIXME it would be more efficient to put a char mCopy[256] as a member variable of the dumper delete[] copy; } +void NBLog::Reader::dumpLine(const String8& timestamp, String8& body) +{ + if (mFd >= 0) { + fdprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string()); + } else { + ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string()); + } + body.clear(); +} + bool NBLog::Reader::isIMemory(const sp& iMemory) const { return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer(); -- cgit v1.1 From c02c96161dde9d6ca7b408cf08fcf10bd8e61a54 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 15 Oct 2013 09:25:11 -0700 Subject: Fix bug with not reporting lost bytes Change-Id: I431d989dbd115b43822e9e48fd4c2b8e6322cfe3 --- media/libnbaio/NBLog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp index 895fd60..96738a7 100644 --- a/media/libnbaio/NBLog.cpp +++ b/media/libnbaio/NBLog.cpp @@ -341,8 +341,8 @@ void NBLog::Reader::dump(int fd, size_t indent) mFd = fd; mIndent = indent; String8 timestamp, body; - if (i > 0) { - lost += i; + lost += i; + if (lost > 0) { body.appendFormat("warning: lost %u bytes worth of events", lost); // TODO timestamp empty here, only other choice to wait for the first timestamp event in the // log to push it out. Consider keeping the timestamp/body between calls to readAt(). -- cgit v1.1 From 3e8027a04c20a4b7028f1615538b36219386c9e5 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 15 Oct 2013 09:24:38 -0700 Subject: Move StateQueueInstantiations to libinstantssq This removes a circular dependency between libmedia and libnbaio Change-Id: I3692cbbe2b76028a953b36606b62cdda70c8c26f --- media/libmedia/Android.mk | 22 ++++++++++++++++------ media/libnbaio/Android.mk | 7 +++---- 2 files changed, 19 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index fc4b2a5..26d94b0 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -60,16 +60,13 @@ LOCAL_SRC_FILES:= \ LOCAL_SRC_FILES += ../libnbaio/roundup.c -# for -LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0) -LOCAL_SRC_FILES += SingleStateQueue.cpp -LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"' -# Consider a separate a library for SingleStateQueueInstantiations. - LOCAL_SHARED_LIBRARIES := \ libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \ libcamera_client libstagefright_foundation \ libgui libdl libaudioutils +LOCAL_SHARED_LIBRARIES += libnbaio + +LOCAL_STATIC_LIBRARIES += libinstantssq LOCAL_WHOLE_STATIC_LIBRARY := libmedia_helper @@ -84,3 +81,16 @@ LOCAL_C_INCLUDES := \ $(call include-path-for, audio-utils) include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +# for +LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0) +LOCAL_SRC_FILES += SingleStateQueue.cpp +LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"' +# Consider a separate a library for SingleStateQueueInstantiations. + +LOCAL_MODULE := libinstantssq +LOCAL_MODULE_TAGS := optional + +include $(BUILD_STATIC_LIBRARY) diff --git a/media/libnbaio/Android.mk b/media/libnbaio/Android.mk index 69c75b8..9707c4a 100644 --- a/media/libnbaio/Android.mk +++ b/media/libnbaio/Android.mk @@ -31,9 +31,8 @@ LOCAL_SHARED_LIBRARIES := \ libcommon_time_client \ libcutils \ libutils \ - liblog \ - libmedia -# This dependency on libmedia is for SingleStateQueueInstantiations. -# Consider a separate a library for SingleStateQueueInstantiations. + liblog + +LOCAL_STATIC_LIBRARIES += libinstantssq include $(BUILD_SHARED_LIBRARY) -- cgit v1.1 From ee3759090c2194eaeca4944a01104771ff1c91d2 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 18 Feb 2014 12:43:37 -0800 Subject: Simplify and remove old comment Change-Id: Iee41641252f65cea9ce0ea0ec1ea4229608f7c64 --- media/libmedia/Android.mk | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'media') diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index 26d94b0..e0acae6 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -63,8 +63,7 @@ LOCAL_SRC_FILES += ../libnbaio/roundup.c LOCAL_SHARED_LIBRARIES := \ libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \ libcamera_client libstagefright_foundation \ - libgui libdl libaudioutils -LOCAL_SHARED_LIBRARIES += libnbaio + libgui libdl libaudioutils libnbaio LOCAL_STATIC_LIBRARIES += libinstantssq @@ -88,7 +87,6 @@ include $(CLEAR_VARS) LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0) LOCAL_SRC_FILES += SingleStateQueue.cpp LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"' -# Consider a separate a library for SingleStateQueueInstantiations. LOCAL_MODULE := libinstantssq LOCAL_MODULE_TAGS := optional -- cgit v1.1 From 6dd62fb91d82dedcfa3ab38c02eb0940b4ba932a Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 5 Dec 2013 16:35:58 -0800 Subject: Multi-client recording Supports multiple clients both at native sample rate and with resampling. Change-Id: Icea55b4fd30751761b7debaa3ce016c79e712d8d --- media/libmedia/AudioRecord.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 6ca499b..700718d 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -462,7 +462,9 @@ status_t AudioRecord::openRecord_l(size_t epoch) audio_io_handle_t input = AudioSystem::getInput(mInputSource, mSampleRate, mFormat, mChannelMask, mSessionId); if (input == 0) { - ALOGE("Could not get audio input for record source %d", mInputSource); + ALOGE("Could not get audio input for record source %d, sample rate %u, format %#x, " + "channel mask %#x, session %d", + mInputSource, mSampleRate, mFormat, mChannelMask, mSessionId); return BAD_VALUE; } { -- cgit v1.1 From 3f80319d5bddfaf11a1513777561096fc1447172 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 19 Feb 2014 09:29:21 -0800 Subject: Expand support for fragmented mp4 Don't require that there are no other boxes between mdat and moof boxes, or that moof immediately follows moov. Fix SAP parsing and seeking to exact start of segment. Change-Id: I668644c5c7866dd2512f3b7f745fba438ae6e627 --- media/libstagefright/MPEG4Extractor.cpp | 39 +++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 81ed6f7..f80772a 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -488,12 +488,12 @@ status_t MPEG4Extractor::readMetaData() { break; } uint32_t chunk_type = ntohl(hdr[1]); - if (chunk_type == FOURCC('s', 'i', 'd', 'x')) { - // parse the sidx box too - continue; - } else if (chunk_type == FOURCC('m', 'o', 'o', 'f')) { + if (chunk_type == FOURCC('m', 'o', 'o', 'f')) { // store the offset of the first segment mMoofOffset = offset; + } else if (chunk_type != FOURCC('m', 'd', 'a', 't')) { + // keep parsing until we get to the data + continue; } break; } @@ -1921,9 +1921,10 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) { ALOGW("sub-sidx boxes not supported yet"); } bool sap = d3 & 0x80000000; - bool saptype = d3 >> 28; - if (!sap || saptype > 2) { - ALOGW("not a stream access point, or unsupported type"); + uint32_t saptype = (d3 >> 28) & 7; + if (!sap || (saptype != 1 && saptype != 2)) { + // type 1 and 2 are sync samples + ALOGW("not a stream access point, or unsupported type: %08x", d3); } total_duration += d2; offset += 12; @@ -2899,9 +2900,20 @@ status_t MPEG4Source::parseChunk(off64_t *offset) { } } if (chunk_type == FOURCC('m', 'o', 'o', 'f')) { - // *offset points to the mdat box following this moof - parseChunk(offset); // doesn't actually parse it, just updates offset - mNextMoofOffset = *offset; + // *offset points to the box following this moof. Find the next moof from there. + + while (true) { + if (mDataSource->readAt(*offset, hdr, 8) < 8) { + return ERROR_END_OF_STREAM; + } + chunk_size = ntohl(hdr[0]); + chunk_type = ntohl(hdr[1]); + if (chunk_type == FOURCC('m', 'o', 'o', 'f')) { + mNextMoofOffset = *offset; + break; + } + *offset += chunk_size; + } } break; } @@ -3706,7 +3718,7 @@ status_t MPEG4Source::fragmentedRead( const SidxEntry *se = &mSegments[i]; if (totalTime + se->mDurationUs > seekTimeUs) { // The requested time is somewhere in this segment - if ((mode == ReadOptions::SEEK_NEXT_SYNC) || + if ((mode == ReadOptions::SEEK_NEXT_SYNC && seekTimeUs > totalTime) || (mode == ReadOptions::SEEK_CLOSEST_SYNC && (seekTimeUs - totalTime) > (totalTime + se->mDurationUs - seekTimeUs))) { // requested next sync, or closest sync and it was closer to the end of @@ -3751,7 +3763,10 @@ status_t MPEG4Source::fragmentedRead( newBuffer = true; if (mCurrentSampleIndex >= mCurrentSamples.size()) { - // move to next fragment + // move to next fragment if there is one + if (mNextMoofOffset <= mCurrentMoofOffset) { + return ERROR_END_OF_STREAM; + } off64_t nextMoof = mNextMoofOffset; mCurrentMoofOffset = nextMoof; mCurrentSamples.clear(); -- cgit v1.1 From 8ca002eedc747dd854b61cbe364b52c06869273f Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 14 Feb 2014 12:21:50 -0800 Subject: LiveSession refactor Change-Id: Ia91dce109835e042f72934376d4838b4cc72cb10 --- media/libstagefright/httplive/LiveSession.cpp | 186 ++++++++++---------------- media/libstagefright/httplive/LiveSession.h | 28 +++- media/libstagefright/httplive/M3UParser.cpp | 12 -- media/libstagefright/httplive/M3UParser.h | 6 +- 4 files changed, 93 insertions(+), 139 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index f0a1c36..5c4c459 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -61,14 +61,14 @@ LiveSession::LiveSession( mRealTimeBaseUs(0ll), mReconfigurationInProgress(false), mDisconnectReplyID(0) { - mPacketSources.add( - STREAMTYPE_AUDIO, new AnotherPacketSource(NULL /* meta */)); - mPacketSources.add( - STREAMTYPE_VIDEO, new AnotherPacketSource(NULL /* meta */)); + mStreams[kAudioIndex] = StreamItem("audio"); + mStreams[kVideoIndex] = StreamItem("video"); + mStreams[kSubtitleIndex] = StreamItem("subtitle"); - mPacketSources.add( - STREAMTYPE_SUBTITLES, new AnotherPacketSource(NULL /* meta */)); + for (size_t i = 0; i < kMaxStreams; ++i) { + mPacketSources.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); + } } LiveSession::~LiveSession() { @@ -369,6 +369,12 @@ int LiveSession::SortByBandwidth(const BandwidthItem *a, const BandwidthItem *b) return 1; } +// static +LiveSession::StreamType LiveSession::indexToType(int idx) { + CHECK(idx >= 0 && idx < kMaxStreams); + return (StreamType)(1 << idx); +} + void LiveSession::onConnect(const sp &msg) { AString url; CHECK(msg->findString("url", &url)); @@ -850,19 +856,11 @@ void LiveSession::changeConfiguration( uint32_t streamMask = 0; - AString audioURI; - if (mPlaylist->getAudioURI(item.mPlaylistIndex, &audioURI)) { - streamMask |= STREAMTYPE_AUDIO; - } - - AString videoURI; - if (mPlaylist->getVideoURI(item.mPlaylistIndex, &videoURI)) { - streamMask |= STREAMTYPE_VIDEO; - } - - AString subtitleURI; - if (mPlaylist->getSubtitleURI(item.mPlaylistIndex, &subtitleURI)) { - streamMask |= STREAMTYPE_SUBTITLES; + AString URIs[kMaxStreams]; + for (size_t i = 0; i < kMaxStreams; ++i) { + if (mPlaylist->getTypeURI(item.mPlaylistIndex, mStreams[i].mType, &URIs[i])) { + streamMask |= indexToType(i); + } } // Step 1, stop and discard fetchers that are no longer needed. @@ -874,10 +872,10 @@ void LiveSession::changeConfiguration( // If we're seeking all current fetchers are discarded. if (timeUs < 0ll) { - if (((streamMask & STREAMTYPE_AUDIO) && uri == audioURI) - || ((streamMask & STREAMTYPE_VIDEO) && uri == videoURI) - || ((streamMask & STREAMTYPE_SUBTITLES) && uri == subtitleURI)) { - discardFetcher = false; + for (size_t j = 0; j < kMaxStreams; ++j) { + if ((streamMask & indexToType(j)) && uri == URIs[j]) { + discardFetcher = false; + } } } @@ -891,14 +889,10 @@ void LiveSession::changeConfiguration( sp msg = new AMessage(kWhatChangeConfiguration2, id()); msg->setInt32("streamMask", streamMask); msg->setInt64("timeUs", timeUs); - if (streamMask & STREAMTYPE_AUDIO) { - msg->setString("audioURI", audioURI.c_str()); - } - if (streamMask & STREAMTYPE_VIDEO) { - msg->setString("videoURI", videoURI.c_str()); - } - if (streamMask & STREAMTYPE_SUBTITLES) { - msg->setString("subtitleURI", subtitleURI.c_str()); + for (size_t i = 0; i < kMaxStreams; ++i) { + if (streamMask & indexToType(i)) { + msg->setString(mStreams[i].uriKey().c_str(), URIs[i].c_str()); + } } // Every time a fetcher acknowledges the stopAsync or pauseAsync request @@ -929,18 +923,13 @@ void LiveSession::onChangeConfiguration2(const sp &msg) { uint32_t streamMask; CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask)); - AString audioURI, videoURI, subtitleURI; - if (streamMask & STREAMTYPE_AUDIO) { - CHECK(msg->findString("audioURI", &audioURI)); - ALOGV("audioURI = '%s'", audioURI.c_str()); - } - if (streamMask & STREAMTYPE_VIDEO) { - CHECK(msg->findString("videoURI", &videoURI)); - ALOGV("videoURI = '%s'", videoURI.c_str()); - } - if (streamMask & STREAMTYPE_SUBTITLES) { - CHECK(msg->findString("subtitleURI", &subtitleURI)); - ALOGV("subtitleURI = '%s'", subtitleURI.c_str()); + AString URIs[kMaxStreams]; + for (size_t i = 0; i < kMaxStreams; ++i) { + if (streamMask & indexToType(i)) { + const AString &uriKey = mStreams[i].uriKey(); + CHECK(msg->findString(uriKey.c_str(), &URIs[i])); + ALOGV("%s = '%s'", uriKey.c_str(), URIs[i].c_str()); + } } // Determine which decoders to shutdown on the player side, @@ -950,15 +939,12 @@ void LiveSession::onChangeConfiguration2(const sp &msg) { // 2) its streamtype was already active and still is but the URI // has changed. uint32_t changedMask = 0; - if (((mStreamMask & streamMask & STREAMTYPE_AUDIO) - && !(audioURI == mAudioURI)) - || (mStreamMask & ~streamMask & STREAMTYPE_AUDIO)) { - changedMask |= STREAMTYPE_AUDIO; - } - if (((mStreamMask & streamMask & STREAMTYPE_VIDEO) - && !(videoURI == mVideoURI)) - || (mStreamMask & ~streamMask & STREAMTYPE_VIDEO)) { - changedMask |= STREAMTYPE_VIDEO; + for (size_t i = 0; i < kMaxStreams && i != kSubtitleIndex; ++i) { + if (((mStreamMask & streamMask & indexToType(i)) + && !(URIs[i] == mStreams[i].mUri)) + || (mStreamMask & ~streamMask & indexToType(i))) { + changedMask |= indexToType(i); + } } if (changedMask == 0) { @@ -990,15 +976,10 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { uint32_t streamMask; CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask)); - AString audioURI, videoURI, subtitleURI; - if (streamMask & STREAMTYPE_AUDIO) { - CHECK(msg->findString("audioURI", &audioURI)); - } - if (streamMask & STREAMTYPE_VIDEO) { - CHECK(msg->findString("videoURI", &videoURI)); - } - if (streamMask & STREAMTYPE_SUBTITLES) { - CHECK(msg->findString("subtitleURI", &subtitleURI)); + for (size_t i = 0; i < kMaxStreams; ++i) { + if (streamMask & indexToType(i)) { + CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mUri)); + } } int64_t timeUs; @@ -1010,9 +991,6 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { mRealTimeBaseUs = ALooper::GetNowUs() - timeUs; mStreamMask = streamMask; - mAudioURI = audioURI; - mVideoURI = videoURI; - mSubtitleURI = subtitleURI; // Resume all existing fetchers and assign them packet sources. for (size_t i = 0; i < mFetcherInfos.size(); ++i) { @@ -1020,22 +998,13 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { uint32_t resumeMask = 0; - sp audioSource; - if ((streamMask & STREAMTYPE_AUDIO) && uri == audioURI) { - audioSource = mPacketSources.valueFor(STREAMTYPE_AUDIO); - resumeMask |= STREAMTYPE_AUDIO; - } - - sp videoSource; - if ((streamMask & STREAMTYPE_VIDEO) && uri == videoURI) { - videoSource = mPacketSources.valueFor(STREAMTYPE_VIDEO); - resumeMask |= STREAMTYPE_VIDEO; - } - - sp subtitleSource; - if ((streamMask & STREAMTYPE_SUBTITLES) && uri == subtitleURI) { - subtitleSource = mPacketSources.valueFor(STREAMTYPE_SUBTITLES); - resumeMask |= STREAMTYPE_SUBTITLES; + sp sources[kMaxStreams]; + // TRICKY: looping from i as earlier streams are already removed from streamMask + for (size_t j = i; j < kMaxStreams; ++j) { + if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) { + sources[j] = mPacketSources.valueFor(indexToType(j)); + resumeMask |= indexToType(j); + } } CHECK_NE(resumeMask, 0u); @@ -1045,7 +1014,7 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { streamMask &= ~resumeMask; mFetcherInfos.valueAt(i).mFetcher->startAsync( - audioSource, videoSource, subtitleSource); + sources[kAudioIndex], sources[kVideoIndex], sources[kSubtitleIndex]); } // streamMask now only contains the types that need a new fetcher created. @@ -1054,52 +1023,33 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { ALOGV("creating new fetchers for mask 0x%08x", streamMask); } - while (streamMask != 0) { - StreamType streamType = (StreamType)(streamMask & ~(streamMask - 1)); + for (size_t i = 0; i < kMaxStreams; i++) { + if (!(indexToType(i) & streamMask)) { + continue; + } AString uri; - switch (streamType) { - case STREAMTYPE_AUDIO: - uri = audioURI; - break; - case STREAMTYPE_VIDEO: - uri = videoURI; - break; - case STREAMTYPE_SUBTITLES: - uri = subtitleURI; - break; - default: - TRESPASS(); - } + uri = mStreams[i].mUri; sp fetcher = addFetcher(uri.c_str()); CHECK(fetcher != NULL); - sp audioSource; - if ((streamMask & STREAMTYPE_AUDIO) && uri == audioURI) { - audioSource = mPacketSources.valueFor(STREAMTYPE_AUDIO); - audioSource->clear(); - - streamMask &= ~STREAMTYPE_AUDIO; - } - - sp videoSource; - if ((streamMask & STREAMTYPE_VIDEO) && uri == videoURI) { - videoSource = mPacketSources.valueFor(STREAMTYPE_VIDEO); - videoSource->clear(); + sp sources[kMaxStreams]; + // TRICKY: looping from i as earlier streams are already removed from streamMask + for (size_t j = i; j < kMaxStreams; ++j) { + if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) { + sources[j] = mPacketSources.valueFor(indexToType(j)); + sources[j]->clear(); - streamMask &= ~STREAMTYPE_VIDEO; - } - - sp subtitleSource; - if ((streamMask & STREAMTYPE_SUBTITLES) && uri == subtitleURI) { - subtitleSource = mPacketSources.valueFor(STREAMTYPE_SUBTITLES); - subtitleSource->clear(); - - streamMask &= ~STREAMTYPE_SUBTITLES; + streamMask &= ~indexToType(j); + } } - fetcher->startAsync(audioSource, videoSource, subtitleSource, timeUs); + fetcher->startAsync( + sources[kAudioIndex], + sources[kVideoIndex], + sources[kSubtitleIndex], + timeUs); } // All fetchers have now been started, the configuration change diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 00569be..973f2fa 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -44,10 +44,17 @@ struct LiveSession : public AHandler { uint32_t flags, const sp &httpService); + enum StreamIndex { + kAudioIndex = 0, + kVideoIndex = 1, + kSubtitleIndex = 2, + kMaxStreams = 3, + }; + enum StreamType { - STREAMTYPE_AUDIO = 1, - STREAMTYPE_VIDEO = 2, - STREAMTYPE_SUBTITLES = 4, + STREAMTYPE_AUDIO = 1 << kAudioIndex, + STREAMTYPE_VIDEO = 1 << kVideoIndex, + STREAMTYPE_SUBTITLES = 1 << kSubtitleIndex, }; status_t dequeueAccessUnit(StreamType stream, sp *accessUnit); @@ -107,6 +114,19 @@ private: bool mIsPrepared; }; + struct StreamItem { + const char *mType; + AString mUri; + StreamItem() : mType("") {} + StreamItem(const char *type) : mType(type) {} + AString uriKey() { + AString key(mType); + key.append("URI"); + return key; + } + }; + StreamItem mStreams[kMaxStreams]; + sp mNotify; uint32_t mFlags; sp mHTTPService; @@ -124,7 +144,6 @@ private: sp mPlaylist; KeyedVector mFetcherInfos; - AString mAudioURI, mVideoURI, mSubtitleURI; uint32_t mStreamMask; KeyedVector > mPacketSources; @@ -172,6 +191,7 @@ private: size_t getBandwidthIndex(); static int SortByBandwidth(const BandwidthItem *, const BandwidthItem *); + static StreamType indexToType(int idx); void changeConfiguration( int64_t timeUs, size_t bandwidthIndex, bool pickTrack = false); diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 39d80fc..4dc5db0 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -369,18 +369,6 @@ bool M3UParser::getTypeURI(size_t index, const char *key, AString *uri) const { return true; } -bool M3UParser::getAudioURI(size_t index, AString *uri) const { - return getTypeURI(index, "audio", uri); -} - -bool M3UParser::getVideoURI(size_t index, AString *uri) const { - return getTypeURI(index, "video", uri); -} - -bool M3UParser::getSubtitleURI(size_t index, AString *uri) const { - return getTypeURI(index, "subtitles", uri); -} - static bool MakeURL(const char *baseURL, const char *url, AString *out) { out->clear(); diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h index 5248004..2051e41 100644 --- a/media/libstagefright/httplive/M3UParser.h +++ b/media/libstagefright/httplive/M3UParser.h @@ -45,9 +45,7 @@ struct M3UParser : public RefBase { status_t getTrackInfo(Parcel* reply) const; ssize_t getSelectedIndex() const; - bool getAudioURI(size_t index, AString *uri) const; - bool getVideoURI(size_t index, AString *uri) const; - bool getSubtitleURI(size_t index, AString *uri) const; + bool getTypeURI(size_t index, const char *key, AString *uri) const; protected: virtual ~M3UParser(); @@ -95,8 +93,6 @@ private: status_t parseMedia(const AString &line); - bool getTypeURI(size_t index, const char *key, AString *uri) const; - static status_t ParseInt32(const char *s, int32_t *x); static status_t ParseDouble(const char *s, double *x); -- cgit v1.1 From c9c7e25a4b1c34439fb365f6cfbef063884566cc Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 21 Feb 2014 12:01:23 -0800 Subject: Add method to get redirected Uri Change-Id: Id8aac1077c3de1bb1f58bfcfcca93d685abe9b79 --- media/libmedia/IMediaHTTPConnection.cpp | 21 +++++++++++++++++++++ media/libstagefright/http/MediaHTTP.cpp | 4 ++++ 2 files changed, 25 insertions(+) (limited to 'media') diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp index 622d9cf..22c470a 100644 --- a/media/libmedia/IMediaHTTPConnection.cpp +++ b/media/libmedia/IMediaHTTPConnection.cpp @@ -33,6 +33,7 @@ enum { READ_AT, GET_SIZE, GET_MIME_TYPE, + GET_URI }; struct BpMediaHTTPConnection : public BpInterface { @@ -147,6 +148,26 @@ struct BpMediaHTTPConnection : public BpInterface { return OK; } + virtual status_t getUri(String8 *uri) { + *uri = String8(""); + + Parcel data, reply; + data.writeInterfaceToken( + IMediaHTTPConnection::getInterfaceDescriptor()); + + remote()->transact(GET_URI, data, &reply); + + int32_t exceptionCode = reply.readExceptionCode(); + + if (exceptionCode) { + return UNKNOWN_ERROR; + } + + *uri = String8(reply.readString16()); + + return OK; + } + private: sp mMemory; }; diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp index 157d967..2d29913 100644 --- a/media/libstagefright/http/MediaHTTP.cpp +++ b/media/libstagefright/http/MediaHTTP.cpp @@ -171,6 +171,10 @@ void MediaHTTP::getDrmInfo( } String8 MediaHTTP::getUri() { + String8 uri; + if (OK == mHTTPConnection->getUri(&uri)) { + return uri; + } return String8(mLastURI.c_str()); } -- cgit v1.1 From 6d0a94ead4f6e62b8ca9b2b1d775ffcd0a7a7aab Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 23 Jan 2014 16:18:22 -0800 Subject: NuPlayer side support for seamless format switch. Avoid reinstantiating decoder if seamless format switch is supported. Change-Id: I2c2be08d6da90cc835ec747d04a76db2313dfc7c --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 9 +++- .../nuplayer/NuPlayerDecoder.cpp | 61 ++++++++++++++++++++++ .../nuplayer/NuPlayerDecoder.h | 5 ++ 3 files changed, 74 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index d47ac98..a750ad0 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1006,7 +1006,14 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { &NuPlayer::performScanSources)); } - flushDecoder(audio, formatChange); + sp newFormat = mSource->getFormat(audio); + sp &decoder = audio ? mAudioDecoder : mVideoDecoder; + if (formatChange && !decoder->supportsSeamlessFormatChange(newFormat)) { + flushDecoder(audio, /* needShutdown = */ true); + } else { + flushDecoder(audio, /* needShutdown = */ false); + err = OK; + } } else { // This stream is unaffected by the discontinuity diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 22f699e..2423fd5 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -67,6 +67,7 @@ void NuPlayer::Decoder::configure(const sp &format) { // queue. bool needDedicatedLooper = !strncasecmp(mime.c_str(), "video/", 6); + mFormat = format; mCodec = new ACodec; if (needDedicatedLooper && mCodecLooper == NULL) { @@ -147,5 +148,65 @@ void NuPlayer::Decoder::initiateShutdown() { } } +bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp &targetFormat) const { + if (targetFormat == NULL) { + return true; + } + + AString mime; + if (!targetFormat->findString("mime", &mime)) { + return false; + } + + if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) { + // field-by-field comparison + const char * keys[] = { "channel-count", "sample-rate", "is-adts" }; + for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) { + int32_t oldVal, newVal; + if (!mFormat->findInt32(keys[i], &oldVal) || !targetFormat->findInt32(keys[i], &newVal) + || oldVal != newVal) { + return false; + } + } + + sp oldBuf, newBuf; + if (mFormat->findBuffer("csd-0", &oldBuf) && targetFormat->findBuffer("csd-0", &newBuf)) { + if (oldBuf->size() != newBuf->size()) { + return false; + } + return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size()); + } + } + return false; +} + +bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp &targetFormat) const { + if (mFormat == NULL) { + return false; + } + + if (targetFormat == NULL) { + return true; + } + + AString oldMime, newMime; + if (!mFormat->findString("mime", &oldMime) + || !targetFormat->findString("mime", &newMime) + || !(oldMime == newMime)) { + return false; + } + + bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/")); + bool seamless; + if (audio) { + seamless = supportsSeamlessAudioFormatChange(targetFormat); + } else { + seamless = mCodec != NULL && mCodec->isConfiguredForAdaptivePlayback(); + } + + ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str()); + return seamless; +} + } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index a876148..78ea74a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -36,6 +36,8 @@ struct NuPlayer::Decoder : public AHandler { void signalResume(); void initiateShutdown(); + bool supportsSeamlessFormatChange(const sp &to) const; + protected: virtual ~Decoder(); @@ -49,6 +51,7 @@ private: sp mNotify; sp mNativeWindow; + sp mFormat; sp mCodec; sp mCodecLooper; @@ -59,6 +62,8 @@ private: void onFillThisBuffer(const sp &msg); + bool supportsSeamlessAudioFormatChange(const sp &targetFormat) const; + DISALLOW_EVIL_CONSTRUCTORS(Decoder); }; -- cgit v1.1 From 11f15ddbca475b5f6a3d7970b22234e04c595b37 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 13 Dec 2013 17:52:09 -0800 Subject: MPEG4Writer: replace timestamp asserts in threadEntry w err return. Bug: 12117267 Change-Id: I13630221c1a8f2e70711f2488659b977db3be281 --- media/libstagefright/MPEG4Writer.cpp | 52 +++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index c839560..24e53b3 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -41,6 +41,12 @@ #include "include/ESDS.h" +#define WARN_UNLESS(condition, message, ...) \ +( (CONDITION(condition)) ? false : ({ \ + ALOGW("Condition %s failed " message, #condition, ##__VA_ARGS__); \ + true; \ +})) + namespace android { static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024; @@ -2098,6 +2104,7 @@ status_t MPEG4Writer::Track::threadEntry() { status_t err = OK; MediaBuffer *buffer; + const char *trackName = mIsAudio ? "Audio" : "Video"; while (!mDone && (err = mSource->read(&buffer)) == OK) { if (buffer->range_length() == 0) { buffer->release(); @@ -2193,15 +2200,27 @@ status_t MPEG4Writer::Track::threadEntry() { if (mResumed) { int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; - CHECK_GE(durExcludingEarlierPausesUs, 0ll); + if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) { + copy->release(); + return ERROR_MALFORMED; + } + int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; - CHECK_GE(pausedDurationUs, lastDurationUs); + if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) { + copy->release(); + return ERROR_MALFORMED; + } + previousPausedDurationUs += pausedDurationUs - lastDurationUs; mResumed = false; } timestampUs -= previousPausedDurationUs; - CHECK_GE(timestampUs, 0ll); + if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { + copy->release(); + return ERROR_MALFORMED; + } + if (!mIsAudio) { /* * Composition time: timestampUs @@ -2213,7 +2232,11 @@ status_t MPEG4Writer::Track::threadEntry() { decodingTimeUs -= previousPausedDurationUs; cttsOffsetTimeUs = timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs; - CHECK_GE(cttsOffsetTimeUs, 0ll); + if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) { + copy->release(); + return ERROR_MALFORMED; + } + timestampUs = decodingTimeUs; ALOGV("decoding time: %lld and ctts offset time: %lld", timestampUs, cttsOffsetTimeUs); @@ -2221,7 +2244,11 @@ status_t MPEG4Writer::Track::threadEntry() { // Update ctts box table if necessary currCttsOffsetTimeTicks = (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL; - CHECK_LE(currCttsOffsetTimeTicks, 0x0FFFFFFFFLL); + if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) { + copy->release(); + return ERROR_MALFORMED; + } + if (mStszTableEntries->count() == 0) { // Force the first ctts table entry to have one single entry // so that we can do adjustment for the initial track start @@ -2259,9 +2286,13 @@ status_t MPEG4Writer::Track::threadEntry() { } } - CHECK_GE(timestampUs, 0ll); + if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { + copy->release(); + return ERROR_MALFORMED; + } + ALOGV("%s media time stamp: %lld and previous paused duration %lld", - mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs); + trackName, timestampUs, previousPausedDurationUs); if (timestampUs > mTrackDurationUs) { mTrackDurationUs = timestampUs; } @@ -2276,7 +2307,8 @@ status_t MPEG4Writer::Track::threadEntry() { (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); if (currDurationTicks < 0ll) { ALOGE("timestampUs %lld < lastTimestampUs %lld for %s track", - timestampUs, lastTimestampUs, mIsAudio? "Audio": "Video"); + timestampUs, lastTimestampUs, trackName); + copy->release(); return UNKNOWN_ERROR; } @@ -2316,7 +2348,7 @@ status_t MPEG4Writer::Track::threadEntry() { previousSampleSize = sampleSize; } ALOGV("%s timestampUs/lastTimestampUs: %lld/%lld", - mIsAudio? "Audio": "Video", timestampUs, lastTimestampUs); + trackName, timestampUs, lastTimestampUs); lastDurationUs = timestampUs - lastTimestampUs; lastDurationTicks = currDurationTicks; lastTimestampUs = timestampUs; @@ -2421,7 +2453,7 @@ status_t MPEG4Writer::Track::threadEntry() { sendTrackSummary(hasMultipleTracks); ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", - count, nZeroLengthFrames, mStszTableEntries->count(), mIsAudio? "audio": "video"); + count, nZeroLengthFrames, mStszTableEntries->count(), trackName); if (mIsAudio) { ALOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs()); } -- cgit v1.1 From dc793ce8c0ead27ab43e40ce09f27fe338323502 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Mon, 24 Feb 2014 12:47:50 -0800 Subject: LiveSession refactor: reverted loop indice change. Change-Id: I465746b206e2253ad44aae0c59317473bc93f73e --- media/libstagefright/httplive/LiveSession.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index bc26de1..95779c4 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -1007,8 +1007,7 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { uint32_t resumeMask = 0; sp sources[kMaxStreams]; - // TRICKY: looping from i as earlier streams are already removed from streamMask - for (size_t j = i; j < kMaxStreams; ++j) { + for (size_t j = 0; j < kMaxStreams; ++j) { if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) { sources[j] = mPacketSources.valueFor(indexToType(j)); resumeMask |= indexToType(j); -- cgit v1.1 From 0517e0b6e4a86f34388631416dd6b3b4fcb91ff8 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 24 Feb 2014 14:13:10 -0800 Subject: Advance read pointer before failing to prevent infinite loops when processing a truncated chunk b/13130358 Change-Id: I24c46788ebc76c242da52a8f059b7577bbaebff4 --- media/libstagefright/MPEG4Extractor.cpp | 69 ++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 22 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index f80772a..2a3fa04 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -913,6 +913,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('e', 'l', 's', 't'): { + *offset += chunk_size; + // See 14496-12 8.6.6 uint8_t version; if (mDataSource->readAt(data_offset, &version, 1) < 1) { @@ -975,12 +977,13 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->meta->setInt32(kKeyEncoderPadding, paddingsamples); } } - *offset += chunk_size; break; } case FOURCC('f', 'r', 'm', 'a'): { + *offset += chunk_size; + uint32_t original_fourcc; if (mDataSource->readAt(data_offset, &original_fourcc, 4) < 4) { return ERROR_IO; @@ -994,12 +997,13 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->meta->setInt32(kKeyChannelCount, num_channels); mLastTrack->meta->setInt32(kKeySampleRate, sample_rate); } - *offset += chunk_size; break; } case FOURCC('t', 'e', 'n', 'c'): { + *offset += chunk_size; + if (chunk_size < 32) { return ERROR_MALFORMED; } @@ -1044,23 +1048,25 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->meta->setInt32(kKeyCryptoMode, defaultAlgorithmId); mLastTrack->meta->setInt32(kKeyCryptoDefaultIVSize, defaultIVSize); mLastTrack->meta->setData(kKeyCryptoKey, 'tenc', defaultKeyId, 16); - *offset += chunk_size; break; } case FOURCC('t', 'k', 'h', 'd'): { + *offset += chunk_size; + status_t err; if ((err = parseTrackHeader(data_offset, chunk_data_size)) != OK) { return err; } - *offset += chunk_size; break; } case FOURCC('p', 's', 's', 'h'): { + *offset += chunk_size; + PsshInfo pssh; if (mDataSource->readAt(data_offset + 4, &pssh.uuid, 16) < 16) { @@ -1086,12 +1092,13 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { } mPssh.push_back(pssh); - *offset += chunk_size; break; } case FOURCC('m', 'd', 'h', 'd'): { + *offset += chunk_size; + if (chunk_data_size < 4) { return ERROR_MALFORMED; } @@ -1172,7 +1179,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->meta->setCString( kKeyMediaLanguage, lang_code); - *offset += chunk_size; break; } @@ -1339,11 +1345,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->sampleTable->setChunkOffsetParams( chunk_type, data_offset, chunk_data_size); + *offset += chunk_size; + if (err != OK) { return err; } - *offset += chunk_size; break; } @@ -1353,11 +1360,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->sampleTable->setSampleToChunkParams( data_offset, chunk_data_size); + *offset += chunk_size; + if (err != OK) { return err; } - *offset += chunk_size; break; } @@ -1368,6 +1376,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->sampleTable->setSampleSizeParams( chunk_type, data_offset, chunk_data_size); + *offset += chunk_size; + if (err != OK) { return err; } @@ -1408,7 +1418,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { } mLastTrack->meta->setInt32(kKeyMaxInputSize, max_size); } - *offset += chunk_size; // NOTE: setting another piece of metadata invalidates any pointers (such as the // mimetype) previously obtained, so don't cache them. @@ -1432,6 +1441,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('s', 't', 't', 's'): { + *offset += chunk_size; + status_t err = mLastTrack->sampleTable->setTimeToSampleParams( data_offset, chunk_data_size); @@ -1440,12 +1451,13 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { return err; } - *offset += chunk_size; break; } case FOURCC('c', 't', 't', 's'): { + *offset += chunk_size; + status_t err = mLastTrack->sampleTable->setCompositionTimeToSampleParams( data_offset, chunk_data_size); @@ -1454,12 +1466,13 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { return err; } - *offset += chunk_size; break; } case FOURCC('s', 't', 's', 's'): { + *offset += chunk_size; + status_t err = mLastTrack->sampleTable->setSyncSampleParams( data_offset, chunk_data_size); @@ -1468,13 +1481,14 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { return err; } - *offset += chunk_size; break; } // @xyz case FOURCC('\xA9', 'x', 'y', 'z'): { + *offset += chunk_size; + // Best case the total data length inside "@xyz" box // would be 8, for instance "@xyz" + "\x00\x04\x15\xc7" + "0+0/", // where "\x00\x04" is the text string length with value = 4, @@ -1503,12 +1517,13 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { buffer[location_length] = '\0'; mFileMetaData->setCString(kKeyLocation, buffer); - *offset += chunk_size; break; } case FOURCC('e', 's', 'd', 's'): { + *offset += chunk_size; + if (chunk_data_size < 4) { return ERROR_MALFORMED; } @@ -1546,12 +1561,13 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { } } - *offset += chunk_size; break; } case FOURCC('a', 'v', 'c', 'C'): { + *offset += chunk_size; + sp buffer = new ABuffer(chunk_data_size); if (mDataSource->readAt( @@ -1562,12 +1578,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->meta->setData( kKeyAVCC, kTypeAVCC, buffer->data(), chunk_data_size); - *offset += chunk_size; break; } case FOURCC('d', '2', '6', '3'): { + *offset += chunk_size; /* * d263 contains a fixed 7 bytes part: * vendor - 4 bytes @@ -1593,7 +1609,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->meta->setData(kKeyD263, kTypeD263, buffer, chunk_data_size); - *offset += chunk_size; break; } @@ -1601,11 +1616,13 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { { uint8_t buffer[4]; if (chunk_data_size < (off64_t)sizeof(buffer)) { + *offset += chunk_size; return ERROR_MALFORMED; } if (mDataSource->readAt( data_offset, buffer, 4) < 4) { + *offset += chunk_size; return ERROR_IO; } @@ -1639,6 +1656,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('n', 'a', 'm', 'e'): case FOURCC('d', 'a', 't', 'a'): { + *offset += chunk_size; + if (mPath.size() == 6 && underMetaDataPath(mPath)) { status_t err = parseITunesMetaData(data_offset, chunk_data_size); @@ -1647,12 +1666,13 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { } } - *offset += chunk_size; break; } case FOURCC('m', 'v', 'h', 'd'): { + *offset += chunk_size; + if (chunk_data_size < 24) { return ERROR_MALFORMED; } @@ -1680,7 +1700,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mFileMetaData->setCString(kKeyDate, s.string()); - *offset += chunk_size; break; } @@ -1701,6 +1720,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('h', 'd', 'l', 'r'): { + *offset += chunk_size; + uint32_t buffer; if (mDataSource->readAt( data_offset + 8, &buffer, 4) < 4) { @@ -1715,7 +1736,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP); } - *offset += chunk_size; break; } @@ -1740,6 +1760,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { delete[] buffer; buffer = NULL; + // advance read pointer so we don't end up reading this again + *offset += chunk_size; return ERROR_IO; } @@ -1754,6 +1776,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('c', 'o', 'v', 'r'): { + *offset += chunk_size; + if (mFileMetaData != NULL) { ALOGV("chunk_data_size = %lld and data_offset = %lld", chunk_data_size, data_offset); @@ -1768,7 +1792,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { buffer->data() + kSkipBytesOfDataBox, chunk_data_size - kSkipBytesOfDataBox); } - *offset += chunk_size; break; } @@ -1779,25 +1802,27 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('a', 'l', 'b', 'm'): case FOURCC('y', 'r', 'r', 'c'): { + *offset += chunk_size; + status_t err = parse3GPPMetaData(data_offset, chunk_data_size, depth); if (err != OK) { return err; } - *offset += chunk_size; break; } case FOURCC('I', 'D', '3', '2'): { + *offset += chunk_size; + if (chunk_data_size < 6) { return ERROR_MALFORMED; } parseID3v2MetaData(data_offset + 6); - *offset += chunk_size; break; } -- cgit v1.1 From 86f04663032ddaa25110149d709bbf896ad83b02 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 24 Feb 2014 15:13:05 -0800 Subject: Add log at entry to set() in AudioTrack and AudioRecord Change-Id: Ife23b88474c1d62c0cf682c1a310d951f2c0f54a --- media/libmedia/AudioRecord.cpp | 8 +++++--- media/libmedia/AudioTrack.cpp | 5 +++++ 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 700718d..b6b6d14 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -133,6 +133,11 @@ status_t AudioRecord::set( transfer_type transferType, audio_input_flags_t flags) { + ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %d, " + "notificationFrames %d, sessionId %d, transferType %d, flags %#x", + inputSource, sampleRate, format, channelMask, frameCountInt, notificationFrames, + sessionId, transferType, flags); + switch (transferType) { case TRANSFER_DEFAULT: if (cbf == NULL || threadCanCallJava) { @@ -163,9 +168,6 @@ status_t AudioRecord::set( } size_t frameCount = frameCountInt; - ALOGV("set(): sampleRate %u, channelMask %#x, frameCount %u", sampleRate, channelMask, - frameCount); - AutoMutex lock(mLock); if (mAudioRecord != 0) { diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 5c62260..46025c0 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -195,6 +195,11 @@ status_t AudioTrack::set( int uid, pid_t pid) { + ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %d, " + "flags #%x, notificationFrames %d, sessionId %d, transferType %d", + streamType, sampleRate, format, channelMask, frameCountInt, flags, notificationFrames, + sessionId, transferType); + switch (transferType) { case TRANSFER_DEFAULT: if (sharedBuffer != 0) { -- cgit v1.1 From c85df82b1e8b05714268926a8bb3deb9c65f9a22 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 24 Feb 2014 15:13:40 -0800 Subject: Permit AudioRecord to support non-linear formats in future But still restricted to 16-bit PCM currently Change-Id: I5df0e5033da9144ca73e44addf14a63d31406034 --- media/libmedia/AudioRecord.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index b6b6d14..e18819c 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -211,8 +211,11 @@ status_t AudioRecord::set( uint32_t channelCount = popcount(channelMask); mChannelCount = channelCount; - // Assumes audio_is_linear_pcm(format), else sizeof(uint8_t) - mFrameSize = channelCount * audio_bytes_per_sample(format); + if (audio_is_linear_pcm(format)) { + mFrameSize = channelCount * audio_bytes_per_sample(format); + } else { + mFrameSize = sizeof(uint8_t); + } // validate framecount size_t minFrameCount = 0; -- cgit v1.1 From 11cb175005db0090345f44bfa049b52fd8c809b8 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 24 Feb 2014 15:16:59 -0800 Subject: Update mReqFrameCount at same point in AudioTrack and AudioRecord Change-Id: I12369dfbb9e75389f2cab015a706decdaf310a0d --- media/libmedia/AudioRecord.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index e18819c..bb0d196 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -523,11 +523,6 @@ status_t AudioRecord::openRecord_l(size_t epoch) ALOGW("Requested frameCount %u but received frameCount %u", frameCount, temp); } frameCount = temp; - // If IAudioRecord is re-created, don't let the requested frameCount - // decrease. This can confuse clients that cache frameCount(). - if (frameCount > mReqFrameCount) { - mReqFrameCount = frameCount; - } // FIXME missing fast track frameCount logic mAwaitBoost = false; @@ -553,6 +548,11 @@ status_t AudioRecord::openRecord_l(size_t epoch) void *buffers = (char*)cblk + sizeof(audio_track_cblk_t); mFrameCount = frameCount; + // If IAudioRecord is re-created, don't let the requested frameCount + // decrease. This can confuse clients that cache frameCount(). + if (frameCount > mReqFrameCount) { + mReqFrameCount = frameCount; + } // update proxy mProxy = new AudioRecordClientProxy(cblk, buffers, mFrameCount, mFrameSize); -- cgit v1.1 From e3247bf8dd4f8fa8dfa3a108260241ae4a967569 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 24 Feb 2014 15:19:07 -0800 Subject: Update channel fields at same place in AudioTrack and AudioRecord Change-Id: I4b649feeef47e7968a9fa3a460217017ca9b05fe --- media/libmedia/AudioTrack.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 46025c0..0eb0915 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -293,6 +293,9 @@ status_t AudioTrack::set( ALOGE("Invalid channel mask %#x", channelMask); return BAD_VALUE; } + mChannelMask = channelMask; + uint32_t channelCount = popcount(channelMask); + mChannelCount = channelCount; // AudioFlinger does not currently support 8-bit data in shared memory if (format == AUDIO_FORMAT_PCM_8_BIT && sharedBuffer != 0) { @@ -316,10 +319,6 @@ status_t AudioTrack::set( flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER); } - mChannelMask = channelMask; - uint32_t channelCount = popcount(channelMask); - mChannelCount = channelCount; - if (audio_is_linear_pcm(format)) { mFrameSize = channelCount * audio_bytes_per_sample(format); mFrameSizeAF = channelCount * sizeof(int16_t); -- cgit v1.1 From 5f631515d098c29603cda88f7a7e7580a2d55b57 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 24 Feb 2014 15:16:07 -0800 Subject: Unify comments and whitespace between AudioTrack and AudioRecord Change-Id: I5320a6b2d7f7077cb12d7da4f2ca30a940100bf2 --- media/libmedia/AudioRecord.cpp | 3 ++- media/libmedia/AudioTrack.cpp | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index bb0d196..bb66b4c 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -175,6 +175,7 @@ status_t AudioRecord::set( return INVALID_OPERATION; } + // handle default values first. if (inputSource == AUDIO_SOURCE_DEFAULT) { inputSource = AUDIO_SOURCE_MIC; } @@ -518,7 +519,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) mCblkMemory = iMem; audio_track_cblk_t* cblk = static_cast(iMemPointer); mCblk = cblk; - // note that temp is the (possibly revised) value of mFrameCount + // note that temp is the (possibly revised) value of frameCount if (temp < frameCount || (frameCount == 0 && temp == 0)) { ALOGW("Requested frameCount %u but received frameCount %u", frameCount, temp); } diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 0eb0915..eed7a0b 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1039,6 +1039,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) mDeathNotifier.clear(); } mAudioTrack = track; + mCblkMemory = iMem; audio_track_cblk_t* cblk = static_cast(iMemPointer); mCblk = cblk; @@ -1050,6 +1051,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) ALOGW("Requested frameCount %u but received frameCount %u", frameCount, temp); } frameCount = temp; + mAwaitBoost = false; if (mFlags & AUDIO_OUTPUT_FLAG_FAST) { if (trackFlags & IAudioFlinger::TRACK_FAST) { @@ -1103,6 +1105,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) mAudioTrack->attachAuxEffect(mAuxEffectId); // FIXME don't believe this lie mLatency = afLatency + (1000*frameCount) / mSampleRate; + mFrameCount = frameCount; // If IAudioTrack is re-created, don't let the requested frameCount // decrease. This can confuse clients that cache frameCount(). -- cgit v1.1 From 089e87201522c8979ac8f00fa729e907f54c790b Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 24 Feb 2014 15:12:48 -0800 Subject: mAudioRecord is always non-0 if set() is successful Change-Id: I0c2483210903c922f06f097ada373a37b9a90a02 --- media/libmedia/AudioRecord.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index bb66b4c..ad9e996 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -110,10 +110,8 @@ AudioRecord::~AudioRecord() mAudioRecordThread->requestExitAndWait(); mAudioRecordThread.clear(); } - if (mAudioRecord != 0) { - mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this); - mAudioRecord.clear(); - } + mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this); + mAudioRecord.clear(); IPCThreadState::self()->flushCommands(); AudioSystem::releaseAudioSessionId(mSessionId, -1); } @@ -170,6 +168,7 @@ status_t AudioRecord::set( AutoMutex lock(mLock); + // invariant that mAudioRecord != 0 is true only after set() returns successfully if (mAudioRecord != 0) { ALOGE("Track already in use"); return INVALID_OPERATION; @@ -508,6 +507,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) ALOGE("Could not get control block pointer"); return NO_INIT; } + // invariant that mAudioRecord != 0 is true only after set() returns successfully if (mAudioRecord != 0) { mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this); mDeathNotifier.clear(); -- cgit v1.1 From b42f318d9733f88c7eb9bedfd33b086b8ea5dff5 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 24 Feb 2014 13:42:58 -0800 Subject: Simplify and cleanup error handling in AudioRecord::getMinFrameCount Change-Id: I8721ecedfb429c4e233453d1e768ddf69ecabbe4 --- media/libmedia/AudioRecord.cpp | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 700718d..10aafed 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -41,30 +41,22 @@ status_t AudioRecord::getMinFrameCount( return BAD_VALUE; } - // default to 0 in case of error - *frameCount = 0; - - size_t size = 0; + size_t size; status_t status = AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &size); if (status != NO_ERROR) { - ALOGE("AudioSystem could not query the input buffer size; status %d", status); - return NO_INIT; + ALOGE("AudioSystem could not query the input buffer size for sampleRate %u, format %#x, " + "channelMask %#x; status %d", sampleRate, format, channelMask, status); + return status; } - if (size == 0) { + // We double the size of input buffer for ping pong use of record buffer. + // Assumes audio_is_linear_pcm(format) + if ((*frameCount = (size * 2) / (popcount(channelMask) * audio_bytes_per_sample(format))) == 0) { ALOGE("Unsupported configuration: sampleRate %u, format %#x, channelMask %#x", sampleRate, format, channelMask); return BAD_VALUE; } - // We double the size of input buffer for ping pong use of record buffer. - size <<= 1; - - // Assumes audio_is_linear_pcm(format) - uint32_t channelCount = popcount(channelMask); - size /= channelCount * audio_bytes_per_sample(format); - - *frameCount = size; return NO_ERROR; } @@ -213,11 +205,12 @@ status_t AudioRecord::set( mFrameSize = channelCount * audio_bytes_per_sample(format); // validate framecount - size_t minFrameCount = 0; + size_t minFrameCount; status_t status = AudioRecord::getMinFrameCount(&minFrameCount, sampleRate, format, channelMask); if (status != NO_ERROR) { - ALOGE("getMinFrameCount() failed; status %d", status); + ALOGE("getMinFrameCount() failed for sampleRate %u, format %#x, channelMask %#x; status %d", + sampleRate, format, channelMask, status); return status; } ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount); -- cgit v1.1 From a5ed48d3476df7dd1e10b380a68e3333f2b646fd Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 25 Feb 2014 15:13:37 -0800 Subject: Move initialization of mRefreshRemaining to match AudioTrack This also fixes a bug where, for a re-created IAudioRecord, mRefreshRemaining was not being reset correctly. Change-Id: I9f721a4edf92aab859cf3f247ab7f65562d14fb0 --- media/libmedia/AudioRecord.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 99f2fe5..123834b 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -256,7 +256,6 @@ status_t AudioRecord::set( mActive = false; mCbf = cbf; - mRefreshRemaining = true; mUserData = user; // TODO: add audio hardware input latency here mLatency = (1000*mFrameCount) / sampleRate; @@ -538,6 +537,8 @@ status_t AudioRecord::openRecord_l(size_t epoch) } } + mRefreshRemaining = true; + // starting address of buffers in shared memory void *buffers = (char*)cblk + sizeof(audio_track_cblk_t); -- cgit v1.1 From f7cc3631c5c264e13ce8c6bc15bd829b2ff9b036 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 25 Feb 2014 15:14:45 -0800 Subject: Update comments to match AudioTrack Change-Id: I7dd14eabd78c9130a157da2063a1d65ec4f9c65a --- media/libmedia/AudioRecord.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 123834b..83e9ea8 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -539,7 +539,9 @@ status_t AudioRecord::openRecord_l(size_t epoch) mRefreshRemaining = true; - // starting address of buffers in shared memory + // Starting address of buffers in shared memory, immediately after the control block. This + // address is for the mapping within client address space. AudioFlinger::TrackBase::mBuffer + // is for the server address space. void *buffers = (char*)cblk + sizeof(audio_track_cblk_t); mFrameCount = frameCount; -- cgit v1.1 From 045e739161f5ae00321a6cfba20935abb791005b Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 25 Feb 2014 15:15:53 -0800 Subject: Move initialize of mInput to match AudioTrack Change-Id: I4dc977f22f51cd618dc83d800b4b8756929a4612 --- media/libmedia/AudioRecord.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 83e9ea8..7f86032 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -504,10 +504,8 @@ status_t AudioRecord::openRecord_l(size_t epoch) mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this); mDeathNotifier.clear(); } - - // We retain a copy of the I/O handle, but don't own the reference - mInput = input; mAudioRecord = record; + mCblkMemory = iMem; audio_track_cblk_t* cblk = static_cast(iMemPointer); mCblk = cblk; @@ -537,6 +535,8 @@ status_t AudioRecord::openRecord_l(size_t epoch) } } + // We retain a copy of the I/O handle, but don't own the reference + mInput = input; mRefreshRemaining = true; // Starting address of buffers in shared memory, immediately after the control block. This -- cgit v1.1 From c08d20b6a37122ebf116262c9372509ed060d4c1 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 24 Feb 2014 15:21:10 -0800 Subject: Simplify error handling after track creation IAudioFlinger::createTrack and IAudioFlinger::openRecord both guarantee that (status == OK) == (sp<> != 0). Change-Id: I91cb4f7e843019efb65cace7ba146f7da7aa5b59 --- media/libmedia/AudioRecord.cpp | 4 +++- media/libmedia/AudioTrack.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 7f86032..4438dfd 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -482,10 +482,12 @@ status_t AudioRecord::openRecord_l(size_t epoch) ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId, "session ID changed from %d to %d", originalSessionId, mSessionId); - if (record == 0 || status != NO_ERROR) { + if (status != NO_ERROR) { ALOGE("AudioFlinger could not create record track, status: %d", status); goto release; } + ALOG_ASSERT(record != 0); + // AudioFlinger now owns the reference to the I/O handle, // so we are no longer responsible for releasing it. diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index eed7a0b..adf3847 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1016,10 +1016,12 @@ status_t AudioTrack::createTrack_l(size_t epoch) mClientUid, &status); - if (track == 0) { + if (status != NO_ERROR) { ALOGE("AudioFlinger could not create track, status: %d", status); goto release; } + ALOG_ASSERT(track != 0); + // AudioFlinger now owns the reference to the I/O handle, // so we are no longer responsible for releasing it. -- cgit v1.1 From 1a5690652f3f6ee40f15c2f9f6c4b6badf4dbcf5 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 25 Feb 2014 21:56:07 -0800 Subject: initialize encoder at start() time for camera source Bug: 13156212 Change-Id: I845ef51f662f04c50179dbfb128204922a424e1d --- .../libmediaplayerservice/StagefrightRecorder.cpp | 22 +++++++++++++++++----- media/libmediaplayerservice/StagefrightRecorder.h | 1 + 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 845a589..5b7a236 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -748,7 +748,7 @@ status_t StagefrightRecorder::setClientName(const String16& clientName) { return OK; } -status_t StagefrightRecorder::prepare() { +status_t StagefrightRecorder::prepareInternal() { ALOGV("prepare"); if (mOutputFd < 0) { ALOGE("Output file descriptor is invalid"); @@ -794,6 +794,13 @@ status_t StagefrightRecorder::prepare() { return status; } +status_t StagefrightRecorder::prepare() { + if (mVideoSource == VIDEO_SOURCE_SURFACE) { + return prepareInternal(); + } + return OK; +} + status_t StagefrightRecorder::start() { ALOGV("start"); if (mOutputFd < 0) { @@ -801,15 +808,20 @@ status_t StagefrightRecorder::start() { return INVALID_OPERATION; } - // Get UID here for permission checking - mClientUid = IPCThreadState::self()->getCallingUid(); + status_t status = OK; + + if (mVideoSource != VIDEO_SOURCE_SURFACE) { + status = prepareInternal(); + if (status != OK) { + return status; + } + } + if (mWriter == NULL) { ALOGE("File writer is not avaialble"); return UNKNOWN_ERROR; } - status_t status = OK; - switch (mOutputFormat) { case OUTPUT_FORMAT_DEFAULT: case OUTPUT_FORMAT_THREE_GPP: diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 7d6abd3..377d168 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -127,6 +127,7 @@ private: sp mGraphicBufferProducer; sp mLooper; + status_t prepareInternal(); status_t setupMPEG4Recording(); void setupMPEG4MetaData(sp *meta); status_t setupAMRRecording(); -- cgit v1.1 From e27e2d9bcabc1a367cb56b4599665c931a1d22ec Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Thu, 27 Feb 2014 14:29:56 -0500 Subject: Fix includes to no longer pull in Skia includes directories. bug:13225538 Change-Id: I4fccc414923f7e62cd46d691c67cb44b9692c225 --- media/libeffects/visualizer/Android.mk | 1 - media/libmedia/Android.mk | 1 - media/libmediaplayerservice/Android.mk | 1 - 3 files changed, 3 deletions(-) (limited to 'media') diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk index dd2d306..c92c543 100644 --- a/media/libeffects/visualizer/Android.mk +++ b/media/libeffects/visualizer/Android.mk @@ -17,7 +17,6 @@ LOCAL_MODULE_RELATIVE_PATH := soundfx LOCAL_MODULE:= libvisualizer LOCAL_C_INCLUDES := \ - $(call include-path-for, graphics corecg) \ $(call include-path-for, audio-effects) diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index e0acae6..f3770e4 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -72,7 +72,6 @@ LOCAL_WHOLE_STATIC_LIBRARY := libmedia_helper LOCAL_MODULE:= libmedia LOCAL_C_INCLUDES := \ - $(call include-path-for, graphics corecg) \ $(TOP)/frameworks/native/include/media/openmax \ external/icu4c/common \ external/icu4c/i18n \ diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index 8f21632..4189a5e 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -45,7 +45,6 @@ LOCAL_STATIC_LIBRARIES := \ libstagefright_rtsp \ LOCAL_C_INCLUDES := \ - $(call include-path-for, graphics corecg) \ $(TOP)/frameworks/av/media/libstagefright/include \ $(TOP)/frameworks/av/media/libstagefright/rtsp \ $(TOP)/frameworks/av/media/libstagefright/wifi-display \ -- cgit v1.1 From 19a9fef6d2970a615f4f33025f9141e44b7c9f34 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 27 Feb 2014 13:20:07 -0800 Subject: Don't crash on remote read error, just return Change-Id: I35a2af255f55e008d64142ed0eceb6e83473d630 --- media/libmedia/IMediaHTTPConnection.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp index 22c470a..7e26ee6 100644 --- a/media/libmedia/IMediaHTTPConnection.cpp +++ b/media/libmedia/IMediaHTTPConnection.cpp @@ -95,7 +95,10 @@ struct BpMediaHTTPConnection : public BpInterface { data.writeInt32(size); status_t err = remote()->transact(READ_AT, data, &reply); - CHECK_EQ(err, (status_t)OK); + if (err != OK) { + ALOGE("remote readAt failed"); + return UNKNOWN_ERROR; + } int32_t exceptionCode = reply.readExceptionCode(); -- cgit v1.1 From c6ba823a397abf865b02f4f48fe18231f94d8e87 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 27 Feb 2014 13:34:29 -0800 Subject: Make openRecord_l more like createTrack_l for fast tracks: part 1 Use the transfer mode to distinguish use cases, as the presence of a callback handler is not sufficient. For example, the track could be configured for synchronous transfer with write() or read(), and also have a callback handler for position updates. But that does not mean the track can operate in fast track mode. Change-Id: I2a7f1f0ca98e68efe180b524496985109d8ce291 --- media/libmedia/AudioRecord.cpp | 30 +++++++++++++++++++++--------- media/libmedia/AudioTrack.cpp | 4 ++-- 2 files changed, 23 insertions(+), 11 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 4438dfd..28daf16 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -430,18 +430,30 @@ status_t AudioRecord::openRecord_l(size_t epoch) return NO_INIT; } - IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT; - pid_t tid = -1; + // Fast tracks must be at the primary _output_ [sic] sampling rate, + // because there is currently no concept of a primary input sampling rate + uint32_t afSampleRate = AudioSystem::getPrimaryOutputSamplingRate(); + if (afSampleRate == 0) { + ALOGW("getPrimaryOutputSamplingRate failed"); + } // Client can only express a preference for FAST. Server will perform additional tests. - // The only supported use case for FAST is callback transfer mode. + if ((mFlags & AUDIO_INPUT_FLAG_FAST) && !( + // use case: callback transfer mode + (mTransfer == TRANSFER_CALLBACK) && + // matching sample rate + (mSampleRate == afSampleRate))) { + ALOGW("AUDIO_INPUT_FLAG_FAST denied by client"); + // once denied, do not request again if IAudioRecord is re-created + mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST); + } + + IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT; + + pid_t tid = -1; if (mFlags & AUDIO_INPUT_FLAG_FAST) { - if ((mTransfer != TRANSFER_CALLBACK) || (mAudioRecordThread == 0)) { - ALOGW("AUDIO_INPUT_FLAG_FAST denied by client"); - // once denied, do not request again if IAudioRecord is re-created - mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST); - } else { - trackFlags |= IAudioFlinger::TRACK_FAST; + trackFlags |= IAudioFlinger::TRACK_FAST; + if (mAudioRecordThread != 0) { tid = mAudioRecordThread->getTid(); } } diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index adf3847..c79b2c8 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -892,8 +892,8 @@ status_t AudioTrack::createTrack_l(size_t epoch) // either of these use cases: // use case 1: shared buffer (mSharedBuffer != 0) || - // use case 2: callback handler - (mCbf != NULL)) && + // use case 2: callback transfer mode + (mTransfer == TRANSFER_CALLBACK)) && // matching sample rate (mSampleRate == afSampleRate))) { ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client"); -- cgit v1.1 From 838b3d8bafa4a781e277870dee4e0390165cff52 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 27 Feb 2014 15:30:41 -0800 Subject: Fix type of AudioTrack/AudioRecord parameter notificationFrames It's uint32_t consistently Change-Id: If8298c7e9aeea2b951fe47b675adbdf48d104846 --- media/libmedia/AudioRecord.cpp | 8 ++++---- media/libmedia/AudioTrack.cpp | 10 +++++----- media/libstagefright/AudioSource.cpp | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 4438dfd..f372da6 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -76,7 +76,7 @@ AudioRecord::AudioRecord( int frameCount, callback_t cbf, void* user, - int notificationFrames, + uint32_t notificationFrames, int sessionId, transfer_type transferType, audio_input_flags_t flags __unused) @@ -117,14 +117,14 @@ status_t AudioRecord::set( int frameCountInt, callback_t cbf, void* user, - int notificationFrames, + uint32_t notificationFrames, bool threadCanCallJava, int sessionId, transfer_type transferType, audio_input_flags_t flags) { ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %d, " - "notificationFrames %d, sessionId %d, transferType %d, flags %#x", + "notificationFrames %u, sessionId %d, transferType %d, flags %#x", inputSource, sampleRate, format, channelMask, frameCountInt, notificationFrames, sessionId, transferType, flags); @@ -803,7 +803,7 @@ nsecs_t AudioRecord::processAudioBuffer() } // Cache other fields that will be needed soon - size_t notificationFrames = mNotificationFramesAct; + uint32_t notificationFrames = mNotificationFramesAct; if (mRefreshRemaining) { mRefreshRemaining = false; mRemainingFrames = notificationFrames; diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index adf3847..aea164b 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -112,7 +112,7 @@ AudioTrack::AudioTrack( audio_output_flags_t flags, callback_t cbf, void* user, - int notificationFrames, + uint32_t notificationFrames, int sessionId, transfer_type transferType, const audio_offload_info_t *offloadInfo, @@ -138,7 +138,7 @@ AudioTrack::AudioTrack( audio_output_flags_t flags, callback_t cbf, void* user, - int notificationFrames, + uint32_t notificationFrames, int sessionId, transfer_type transferType, const audio_offload_info_t *offloadInfo, @@ -186,7 +186,7 @@ status_t AudioTrack::set( audio_output_flags_t flags, callback_t cbf, void* user, - int notificationFrames, + uint32_t notificationFrames, const sp& sharedBuffer, bool threadCanCallJava, int sessionId, @@ -196,7 +196,7 @@ status_t AudioTrack::set( pid_t pid) { ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %d, " - "flags #%x, notificationFrames %d, sessionId %d, transferType %d", + "flags #%x, notificationFrames %u, sessionId %d, transferType %d", streamType, sampleRate, format, channelMask, frameCountInt, flags, notificationFrames, sessionId, transferType); @@ -1487,7 +1487,7 @@ nsecs_t AudioTrack::processAudioBuffer() // Cache other fields that will be needed soon uint32_t loopPeriod = mLoopPeriod; uint32_t sampleRate = mSampleRate; - size_t notificationFrames = mNotificationFramesAct; + uint32_t notificationFrames = mNotificationFramesAct; if (mRefreshRemaining) { mRefreshRemaining = false; mRemainingFrames = notificationFrames; diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index df7da0a..ee789bd 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -65,7 +65,7 @@ AudioSource::AudioSource( if (status == OK) { // make sure that the AudioRecord callback never returns more than the maximum // buffer size - int frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount; + uint32_t frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount; // make sure that the AudioRecord total buffer size is large enough size_t bufCount = 2; @@ -79,7 +79,7 @@ AudioSource::AudioSource( bufCount * frameCount, AudioRecordCallbackFunction, this, - frameCount); + frameCount /*notificationFrames*/); mInitCheck = mRecord->initCheck(); } else { mInitCheck = status; -- cgit v1.1 From bce50bfc3846ab008bafa75c5d3f29fd7b5395f7 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 27 Feb 2014 15:29:51 -0800 Subject: Fix type of AudioTrack/AudioRecord parameter frameCount It's size_t consistently Change-Id: I29638ef59ac773218025f2403a3508a307b487e0 --- media/libmedia/AudioRecord.cpp | 15 ++++----------- media/libmedia/AudioTrack.cpp | 15 ++++----------- media/libmedia/JetPlayer.cpp | 2 +- media/libmedia/SoundPool.cpp | 2 +- media/libmediaplayerservice/MediaPlayerService.cpp | 2 +- media/libstagefright/AudioSource.cpp | 2 +- 6 files changed, 12 insertions(+), 26 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index f372da6..a3cb538 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -73,7 +73,7 @@ AudioRecord::AudioRecord( uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, - int frameCount, + size_t frameCount, callback_t cbf, void* user, uint32_t notificationFrames, @@ -114,7 +114,7 @@ status_t AudioRecord::set( uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, - int frameCountInt, + size_t frameCount, callback_t cbf, void* user, uint32_t notificationFrames, @@ -123,9 +123,9 @@ status_t AudioRecord::set( transfer_type transferType, audio_input_flags_t flags) { - ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %d, " + ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, " "notificationFrames %u, sessionId %d, transferType %d, flags %#x", - inputSource, sampleRate, format, channelMask, frameCountInt, notificationFrames, + inputSource, sampleRate, format, channelMask, frameCount, notificationFrames, sessionId, transferType, flags); switch (transferType) { @@ -151,13 +151,6 @@ status_t AudioRecord::set( } mTransfer = transferType; - // FIXME "int" here is legacy and will be replaced by size_t later - if (frameCountInt < 0) { - ALOGE("Invalid frame count %d", frameCountInt); - return BAD_VALUE; - } - size_t frameCount = frameCountInt; - AutoMutex lock(mLock); // invariant that mAudioRecord != 0 is true only after set() returns successfully diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index aea164b..f85b0ce 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -108,7 +108,7 @@ AudioTrack::AudioTrack( uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, - int frameCount, + size_t frameCount, audio_output_flags_t flags, callback_t cbf, void* user, @@ -182,7 +182,7 @@ status_t AudioTrack::set( uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, - int frameCountInt, + size_t frameCount, audio_output_flags_t flags, callback_t cbf, void* user, @@ -195,9 +195,9 @@ status_t AudioTrack::set( int uid, pid_t pid) { - ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %d, " + ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, " "flags #%x, notificationFrames %u, sessionId %d, transferType %d", - streamType, sampleRate, format, channelMask, frameCountInt, flags, notificationFrames, + streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames, sessionId, transferType); switch (transferType) { @@ -236,13 +236,6 @@ status_t AudioTrack::set( mSharedBuffer = sharedBuffer; mTransfer = transferType; - // FIXME "int" here is legacy and will be replaced by size_t later - if (frameCountInt < 0) { - ALOGE("Invalid frame count %d", frameCountInt); - return BAD_VALUE; - } - size_t frameCount = frameCountInt; - ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp index e914b34..f0f1832 100644 --- a/media/libmedia/JetPlayer.cpp +++ b/media/libmedia/JetPlayer.cpp @@ -90,7 +90,7 @@ int JetPlayer::init() pLibConfig->sampleRate, AUDIO_FORMAT_PCM_16_BIT, audio_channel_out_mask_from_count(pLibConfig->numChannels), - mTrackBufferSize, + (size_t) mTrackBufferSize, AUDIO_OUTPUT_FLAG_NONE); // create render and playback thread diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp index 4885b4f..a55e09c 100644 --- a/media/libmedia/SoundPool.cpp +++ b/media/libmedia/SoundPool.cpp @@ -587,7 +587,7 @@ void SoundChannel::play(const sp& sample, int nextChannelID, float leftV uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5); uint32_t totalFrames = (kDefaultBufferCount * afFrameCount * sampleRate) / afSampleRate; uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount; - uint32_t frameCount = 0; + size_t frameCount = 0; if (loop) { frameCount = sample->size()/numChannels/ diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 142788d..200c561 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1455,7 +1455,7 @@ status_t MediaPlayerService::AudioOutput::open( format, bufferCount, mSessionId, flags); uint32_t afSampleRate; size_t afFrameCount; - uint32_t frameCount; + size_t frameCount; // offloading is only supported in callback mode for now. // offloadInfo must be present if offload flag is set diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index ee789bd..d0e0e8e 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -76,7 +76,7 @@ AudioSource::AudioSource( mRecord = new AudioRecord( inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT, audio_channel_in_mask_from_count(channelCount), - bufCount * frameCount, + (size_t) (bufCount * frameCount), AudioRecordCallbackFunction, this, frameCount /*notificationFrames*/); -- cgit v1.1 From 4d462fbd20c7e4b214f1d9b9396a623f4e4b6f38 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 28 Feb 2014 10:00:21 -0800 Subject: Fix race condition in AwesomePlayer This fixes a race condition that could cause two threads to attempt to connect to a server at the same time, resulting in multiple requests and/or aborted connections. In some cases, it could cause other operations on MediaPlayer to block until network access was complete. b/13187722 Change-Id: Ibf78acff15dbfbf6c443a4c60623e8eac967d955 --- media/libstagefright/AwesomePlayer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index e83ec62..4bad14b 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -2217,6 +2217,10 @@ status_t AwesomePlayer::finishSetDataSource_l() { mLock.unlock(); status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders); + // force connection at this point, to avoid a race condition between getMIMEType and the + // caching datasource constructed below, which could result in multiple requests to the + // server, and/or failed connections. + String8 contentType = mConnectingDataSource->getMIMEType(); mLock.lock(); if (err != OK) { @@ -2247,8 +2251,6 @@ status_t AwesomePlayer::finishSetDataSource_l() { mConnectingDataSource.clear(); - String8 contentType = dataSource->getMIMEType(); - if (strncasecmp(contentType.string(), "audio/", 6)) { // We're not doing this for streams that appear to be audio-only // streams to ensure that even low bandwidth streams start -- cgit v1.1 From d2304db2fcb5112292105a0949a55986a4c9875f Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 3 Feb 2014 07:40:31 -0800 Subject: Rename setStreamOutput to invalidateStream And simplify by removing the unused I/O handle parameter 'output'. Change-Id: Ie9c4df17a7378066312d4ed8790fda7a9125c95e --- media/libmedia/IAudioFlinger.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'media') diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index e696323..a9a9f1a 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -58,7 +58,7 @@ enum { RESTORE_OUTPUT, OPEN_INPUT, CLOSE_INPUT, - SET_STREAM_OUTPUT, + INVALIDATE_STREAM, SET_VOICE_VOLUME, GET_RENDER_POSITION, GET_INPUT_FRAMES_LOST, @@ -545,13 +545,12 @@ public: return reply.readInt32(); } - virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output) + virtual status_t invalidateStream(audio_stream_type_t stream) { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInt32((int32_t) stream); - data.writeInt32((int32_t) output); - remote()->transact(SET_STREAM_OUTPUT, data, &reply); + remote()->transact(INVALIDATE_STREAM, data, &reply); return reply.readInt32(); } @@ -1044,11 +1043,10 @@ status_t BnAudioFlinger::onTransact( reply->writeInt32(closeInput((audio_io_handle_t) data.readInt32())); return NO_ERROR; } break; - case SET_STREAM_OUTPUT: { + case INVALIDATE_STREAM: { CHECK_INTERFACE(IAudioFlinger, data, reply); - uint32_t stream = data.readInt32(); - audio_io_handle_t output = (audio_io_handle_t) data.readInt32(); - reply->writeInt32(setStreamOutput((audio_stream_type_t) stream, output)); + audio_stream_type_t stream = (audio_stream_type_t) data.readInt32(); + reply->writeInt32(invalidateStream(stream)); return NO_ERROR; } break; case SET_VOICE_VOLUME: { -- cgit v1.1 From 2c48f27be6b3ae58e451d9b56c1dfd00e606f345 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 27 Feb 2014 13:35:06 -0800 Subject: Make openRecord_l more like createTrack_l for fast tracks: part 2 Assume double-buffering because we don't know the true HAL sample rate, and for fast tracks we must accomodate kernel scheduling and app computation jitter. Change-Id: I983d6048a8b4814cfa5bf789397cdd9f1572256c --- media/libmedia/AudioRecord.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 8b92669..a8e1f5d 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -451,6 +451,9 @@ status_t AudioRecord::openRecord_l(size_t epoch) } } + // FIXME Assume double buffering, because we don't know the true HAL sample rate + const uint32_t nBuffering = 2; + mNotificationFramesAct = mNotificationFramesReq; size_t frameCount = mReqFrameCount; @@ -522,23 +525,21 @@ status_t AudioRecord::openRecord_l(size_t epoch) } frameCount = temp; - // FIXME missing fast track frameCount logic mAwaitBoost = false; if (mFlags & AUDIO_INPUT_FLAG_FAST) { if (trackFlags & IAudioFlinger::TRACK_FAST) { - ALOGV("AUDIO_INPUT_FLAG_FAST successful; frameCount %u", mFrameCount); + ALOGV("AUDIO_INPUT_FLAG_FAST successful; frameCount %u", frameCount); mAwaitBoost = true; - // double-buffering is not required for fast tracks, due to tighter scheduling - if (mNotificationFramesAct == 0 || mNotificationFramesAct > mFrameCount) { - mNotificationFramesAct = mFrameCount; - } } else { - ALOGV("AUDIO_INPUT_FLAG_FAST denied by server; frameCount %u", mFrameCount); + ALOGV("AUDIO_INPUT_FLAG_FAST denied by server; frameCount %u", frameCount); // once denied, do not request again if IAudioRecord is re-created mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST); - if (mNotificationFramesAct == 0 || mNotificationFramesAct > mFrameCount/2) { - mNotificationFramesAct = mFrameCount/2; - } + } + // Theoretically double-buffering is not required for fast tracks, + // due to tighter scheduling. But in practice, to accomodate kernels with + // scheduling jitter, and apps with computation jitter, we use double-buffering. + if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/nBuffering) { + mNotificationFramesAct = frameCount/nBuffering; } } -- cgit v1.1 From 879707057cde0a83b5f6143c918c66b8f4a97581 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 27 Feb 2014 15:31:39 -0800 Subject: Make openRecord_l more like createTrack_l for fast tracks: part 3 Create the callback thread earlier, before creating the IAudioRecord, so that the thread's tid is available as a parameter to openRecord(). Also move initialization of mCbf to same point as in AudioTrack.cpp. Change-Id: I61ea4c5e2724ccfc691aaf51bc02a7c10d5a7495 --- media/libmedia/AudioRecord.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index a8e1f5d..961b0a2 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -233,22 +233,27 @@ status_t AudioRecord::set( ALOGV("set(): mSessionId %d", mSessionId); mFlags = flags; + mCbf = cbf; + + if (cbf != NULL) { + mAudioRecordThread = new AudioRecordThread(*this, threadCanCallJava); + mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO); + } // create the IAudioRecord status = openRecord_l(0 /*epoch*/); + if (status != NO_ERROR) { + if (mAudioRecordThread != 0) { + mAudioRecordThread->requestExit(); // see comment in AudioRecord.h + mAudioRecordThread->requestExitAndWait(); + mAudioRecordThread.clear(); + } return status; } - if (cbf != NULL) { - mAudioRecordThread = new AudioRecordThread(*this, threadCanCallJava); - mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO); - } - mStatus = NO_ERROR; - mActive = false; - mCbf = cbf; mUserData = user; // TODO: add audio hardware input latency here mLatency = (1000*mFrameCount) / sampleRate; -- cgit v1.1 From 1543d3c735a5ba4ddfcf8ab644575df13c7e30a9 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 20 Feb 2014 13:07:26 -0800 Subject: Initial HLS seamless switch implementation. Bug: 11854054 Change-Id: I75fc2a258111295039ac13cc37e407df25891dd2 --- media/libstagefright/httplive/LiveSession.cpp | 280 +++++++++++++++++++--- media/libstagefright/httplive/LiveSession.h | 36 +++ media/libstagefright/httplive/PlaylistFetcher.cpp | 251 +++++++++++++++++-- media/libstagefright/httplive/PlaylistFetcher.h | 22 +- 4 files changed, 541 insertions(+), 48 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 95779c4..2af4682 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -40,6 +40,8 @@ #include #include +#include + #include #include #include @@ -56,10 +58,14 @@ LiveSession::LiveSession( mHTTPDataSource(new MediaHTTP(mHTTPService->makeHTTPConnection())), mPrevBandwidthIndex(-1), mStreamMask(0), + mNewStreamMask(0), + mSwapMask(0), mCheckBandwidthGeneration(0), + mSwitchGeneration(0), mLastDequeuedTimeUs(0ll), mRealTimeBaseUs(0ll), mReconfigurationInProgress(false), + mSwitchInProgress(false), mDisconnectReplyID(0) { mStreams[kAudioIndex] = StreamItem("audio"); @@ -68,16 +74,37 @@ LiveSession::LiveSession( for (size_t i = 0; i < kMaxStreams; ++i) { mPacketSources.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); + mPacketSources2.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); } } LiveSession::~LiveSession() { } +sp LiveSession::createFormatChangeBuffer(bool swap) { + ABuffer *discontinuity = new ABuffer(0); + discontinuity->meta()->setInt32("discontinuity", ATSParser::DISCONTINUITY_FORMATCHANGE); + discontinuity->meta()->setInt32("swapPacketSource", swap); + discontinuity->meta()->setInt32("switchGeneration", mSwitchGeneration); + discontinuity->meta()->setInt64("timeUs", -1); + return discontinuity; +} + +void LiveSession::swapPacketSource(StreamType stream) { + sp &aps = mPacketSources.editValueFor(stream); + sp &aps2 = mPacketSources2.editValueFor(stream); + sp tmp = aps; + aps = aps2; + aps2 = tmp; + aps2->clear(); +} + status_t LiveSession::dequeueAccessUnit( StreamType stream, sp *accessUnit) { if (!(mStreamMask & stream)) { - return UNKNOWN_ERROR; + // return -EWOULDBLOCK to avoid halting the decoder + // when switching between audio/video and audio only. + return -EWOULDBLOCK; } sp packetSource = mPacketSources.valueFor(stream); @@ -117,6 +144,25 @@ status_t LiveSession::dequeueAccessUnit( streamStr, type, extra == NULL ? "NULL" : extra->debugString().c_str()); + + int32_t swap; + if (type == ATSParser::DISCONTINUITY_FORMATCHANGE + && (*accessUnit)->meta()->findInt32("swapPacketSource", &swap) + && swap) { + + int32_t switchGeneration; + CHECK((*accessUnit)->meta()->findInt32("switchGeneration", &switchGeneration)); + { + Mutex::Autolock lock(mSwapMutex); + if (switchGeneration == mSwitchGeneration) { + swapPacketSource(stream); + sp msg = new AMessage(kWhatSwapped, id()); + msg->setInt32("stream", stream); + msg->setInt32("switchGeneration", switchGeneration); + msg->post(); + } + } + } } else if (err == OK) { if (stream == STREAMTYPE_AUDIO || stream == STREAMTYPE_VIDEO) { int64_t timeUs; @@ -138,6 +184,7 @@ status_t LiveSession::dequeueAccessUnit( } status_t LiveSession::getStreamFormat(StreamType stream, sp *format) { + // No swapPacketSource race condition; called from the same thread as dequeueAccessUnit. if (!(mStreamMask & stream)) { return UNKNOWN_ERROR; } @@ -234,7 +281,12 @@ void LiveSession::onMessageReceived(const sp &msg) { if (what == PlaylistFetcher::kWhatStopped) { AString uri; CHECK(msg->findString("uri", &uri)); - mFetcherInfos.removeItem(uri); + if (mFetcherInfos.removeItem(uri) < 0) { + // ignore duplicated kWhatStopped messages. + break; + } + + tryToFinishBandwidthSwitch(); } if (mContinuation != NULL) { @@ -270,6 +322,8 @@ void LiveSession::onMessageReceived(const sp &msg) { postPrepared(err); } + cancelBandwidthSwitch(); + mPacketSources.valueFor(STREAMTYPE_AUDIO)->signalEOS(err); mPacketSources.valueFor(STREAMTYPE_VIDEO)->signalEOS(err); @@ -308,6 +362,27 @@ void LiveSession::onMessageReceived(const sp &msg) { break; } + case PlaylistFetcher::kWhatStartedAt: + { + int32_t switchGeneration; + CHECK(msg->findInt32("switchGeneration", &switchGeneration)); + + if (switchGeneration != mSwitchGeneration) { + break; + } + + // Resume fetcher for the original variant; the resumed fetcher should + // continue until the timestamps found in msg, which is stored by the + // new fetcher to indicate where the new variant has started buffering. + for (size_t i = 0; i < mFetcherInfos.size(); i++) { + const FetcherInfo info = mFetcherInfos.valueAt(i); + if (info.mToBeRemoved) { + info.mFetcher->resumeUntilAsync(msg); + } + } + break; + } + default: TRESPASS(); } @@ -352,6 +427,11 @@ void LiveSession::onMessageReceived(const sp &msg) { break; } + case kWhatSwapped: + { + onSwapped(msg); + break; + } default: TRESPASS(); break; @@ -462,6 +542,10 @@ void LiveSession::finishDisconnect() { // during disconnection either. cancelCheckBandwidthEvent(); + // Protect mPacketSources from a swapPacketSource race condition through disconnect. + // (finishDisconnect, onFinishDisconnect2) + cancelBandwidthSwitch(); + for (size_t i = 0; i < mFetcherInfos.size(); ++i) { mFetcherInfos.valueAt(i).mFetcher->stopAsync(); } @@ -501,11 +585,13 @@ sp LiveSession::addFetcher(const char *uri) { sp notify = new AMessage(kWhatFetcherNotify, id()); notify->setString("uri", uri); + notify->setInt32("switchGeneration", mSwitchGeneration); FetcherInfo info; info.mFetcher = new PlaylistFetcher(notify, this, uri); info.mDurationUs = -1ll; info.mIsPrepared = false; + info.mToBeRemoved = false; looper()->registerHandler(info.mFetcher); mFetcherInfos.add(uri, info); @@ -845,8 +931,25 @@ status_t LiveSession::selectTrack(size_t index, bool select) { return err; } +bool LiveSession::canSwitchUp() { + // Allow upwards bandwidth switch when a stream has buffered at least 10 seconds. + status_t err = OK; + for (size_t i = 0; i < mPacketSources.size(); ++i) { + sp source = mPacketSources.valueAt(i); + int64_t dur = source->getBufferedDurationUs(&err); + if (err == OK && dur > 10000000) { + return true; + } + } + return false; +} + void LiveSession::changeConfiguration( int64_t timeUs, size_t bandwidthIndex, bool pickTrack) { + // Protect mPacketSources from a swapPacketSource race condition through reconfiguration. + // (changeConfiguration, onChangeConfiguration2, onChangeConfiguration3). + cancelBandwidthSwitch(); + CHECK(!mReconfigurationInProgress); mReconfigurationInProgress = true; @@ -862,7 +965,8 @@ void LiveSession::changeConfiguration( CHECK_LT(bandwidthIndex, mBandwidthItems.size()); const BandwidthItem &item = mBandwidthItems.itemAt(bandwidthIndex); - uint32_t streamMask = 0; + uint32_t streamMask = 0; // streams that should be fetched by the new fetcher + uint32_t resumeMask = 0; // streams that should be fetched by the original fetcher AString URIs[kMaxStreams]; for (size_t i = 0; i < kMaxStreams; ++i) { @@ -880,9 +984,14 @@ void LiveSession::changeConfiguration( // If we're seeking all current fetchers are discarded. if (timeUs < 0ll) { + // delay fetcher removal + discardFetcher = false; + for (size_t j = 0; j < kMaxStreams; ++j) { - if ((streamMask & indexToType(j)) && uri == URIs[j]) { - discardFetcher = false; + StreamType type = indexToType(j); + if ((streamMask & type) && uri == URIs[j]) { + resumeMask |= type; + streamMask &= ~type; } } } @@ -894,8 +1003,15 @@ void LiveSession::changeConfiguration( } } - sp msg = new AMessage(kWhatChangeConfiguration2, id()); + sp msg; + if (timeUs < 0ll) { + // skip onChangeConfiguration2 (decoder destruction) if switching. + msg = new AMessage(kWhatChangeConfiguration3, id()); + } else { + msg = new AMessage(kWhatChangeConfiguration2, id()); + } msg->setInt32("streamMask", streamMask); + msg->setInt32("resumeMask", resumeMask); msg->setInt64("timeUs", timeUs); for (size_t i = 0; i < kMaxStreams; ++i) { if (streamMask & indexToType(i)) { @@ -978,11 +1094,13 @@ void LiveSession::onChangeConfiguration2(const sp &msg) { } void LiveSession::onChangeConfiguration3(const sp &msg) { + mContinuation.clear(); // All remaining fetchers are still suspended, the player has shutdown // any decoders that needed it. - uint32_t streamMask; + uint32_t streamMask, resumeMask; CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask)); + CHECK(msg->findInt32("resumeMask", (int32_t *)&resumeMask)); for (size_t i = 0; i < kMaxStreams; ++i) { if (streamMask & indexToType(i)) { @@ -991,37 +1109,39 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { } int64_t timeUs; + bool switching = false; CHECK(msg->findInt64("timeUs", &timeUs)); if (timeUs < 0ll) { timeUs = mLastDequeuedTimeUs; + switching = true; } mRealTimeBaseUs = ALooper::GetNowUs() - timeUs; - mStreamMask = streamMask; + mNewStreamMask = streamMask; - // Resume all existing fetchers and assign them packet sources. + // Of all existing fetchers: + // * Resume fetchers that are still needed and assign them original packet sources. + // * Mark otherwise unneeded fetchers for removal. + ALOGV("resuming fetchers for mask 0x%08x", resumeMask); for (size_t i = 0; i < mFetcherInfos.size(); ++i) { const AString &uri = mFetcherInfos.keyAt(i); - uint32_t resumeMask = 0; - sp sources[kMaxStreams]; for (size_t j = 0; j < kMaxStreams; ++j) { - if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) { + if ((resumeMask & indexToType(j)) && uri == mStreams[j].mUri) { sources[j] = mPacketSources.valueFor(indexToType(j)); - resumeMask |= indexToType(j); } } - CHECK_NE(resumeMask, 0u); - - ALOGV("resuming fetchers for mask 0x%08x", resumeMask); - - streamMask &= ~resumeMask; - - mFetcherInfos.valueAt(i).mFetcher->startAsync( - sources[kAudioIndex], sources[kVideoIndex], sources[kSubtitleIndex]); + FetcherInfo &info = mFetcherInfos.editValueAt(i); + if (sources[kAudioIndex] != NULL || sources[kVideoIndex] != NULL + || sources[kSubtitleIndex] != NULL) { + info.mFetcher->startAsync( + sources[kAudioIndex], sources[kVideoIndex], sources[kSubtitleIndex]); + } else { + info.mToBeRemoved = true; + } } // streamMask now only contains the types that need a new fetcher created. @@ -1030,6 +1150,8 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { ALOGV("creating new fetchers for mask 0x%08x", streamMask); } + // Find out when the original fetchers have buffered up to and start the new fetchers + // at a later timestamp. for (size_t i = 0; i < kMaxStreams; i++) { if (!(indexToType(i) & streamMask)) { continue; @@ -1041,12 +1163,40 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { sp fetcher = addFetcher(uri.c_str()); CHECK(fetcher != NULL); + int32_t latestSeq = -1; + int64_t latestTimeUs = 0ll; sp sources[kMaxStreams]; + // TRICKY: looping from i as earlier streams are already removed from streamMask for (size_t j = i; j < kMaxStreams; ++j) { if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) { sources[j] = mPacketSources.valueFor(indexToType(j)); - sources[j]->clear(); + + if (!switching) { + sources[j]->clear(); + } else { + int32_t type, seq; + int64_t srcTimeUs; + sp meta = sources[j]->getLatestMeta(); + + if (meta != NULL && !meta->findInt32("discontinuity", &type)) { + CHECK(meta->findInt32("seq", &seq)); + if (seq > latestSeq) { + latestSeq = seq; + } + CHECK(meta->findInt64("timeUs", &srcTimeUs)); + if (srcTimeUs > latestTimeUs) { + latestTimeUs = srcTimeUs; + } + } + + sources[j] = mPacketSources2.valueFor(indexToType(j)); + sources[j]->clear(); + uint32_t extraStreams = mNewStreamMask & (~mStreamMask); + if (extraStreams & indexToType(j)) { + sources[j]->queueAccessUnit(createFormatChangeBuffer(/* swap = */ false)); + } + } streamMask &= ~indexToType(j); } @@ -1056,7 +1206,9 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { sources[kAudioIndex], sources[kVideoIndex], sources[kSubtitleIndex], - timeUs); + timeUs, + latestTimeUs /* min start time(us) */, + latestSeq >= 0 ? latestSeq + 1 : -1 /* starting sequence number hint */ ); } // All fetchers have now been started, the configuration change @@ -1065,14 +1217,61 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { scheduleCheckBandwidthEvent(); ALOGV("XXX configuration change completed."); - mReconfigurationInProgress = false; + if (switching) { + mSwitchInProgress = true; + } else { + mStreamMask = mNewStreamMask; + } if (mDisconnectReplyID != 0) { finishDisconnect(); } } +void LiveSession::onSwapped(const sp &msg) { + int32_t switchGeneration; + CHECK(msg->findInt32("switchGeneration", &switchGeneration)); + if (switchGeneration != mSwitchGeneration) { + return; + } + + int32_t stream; + CHECK(msg->findInt32("stream", &stream)); + mSwapMask |= stream; + if (mSwapMask != mStreamMask) { + return; + } + + // Check if new variant contains extra streams. + uint32_t extraStreams = mNewStreamMask & (~mStreamMask); + while (extraStreams) { + StreamType extraStream = (StreamType) (extraStreams & ~(extraStreams - 1)); + swapPacketSource(extraStream); + extraStreams &= ~extraStream; + } + + tryToFinishBandwidthSwitch(); +} + +// Mark switch done when: +// 1. all old buffers are swapped out, AND +// 2. all old fetchers are removed. +void LiveSession::tryToFinishBandwidthSwitch() { + bool needToRemoveFetchers = false; + for (size_t i = 0; i < mFetcherInfos.size(); ++i) { + if (mFetcherInfos.valueAt(i).mToBeRemoved) { + needToRemoveFetchers = true; + break; + } + } + if (!needToRemoveFetchers && mSwapMask == mStreamMask) { + mStreamMask = mNewStreamMask; + mSwitchInProgress = false; + mSwapMask = 0; + } +} + void LiveSession::scheduleCheckBandwidthEvent() { sp msg = new AMessage(kWhatCheckBandwidth, id()); msg->setInt32("generation", mCheckBandwidthGeneration); @@ -1083,16 +1282,37 @@ void LiveSession::cancelCheckBandwidthEvent() { ++mCheckBandwidthGeneration; } -void LiveSession::onCheckBandwidth() { - if (mReconfigurationInProgress) { - scheduleCheckBandwidthEvent(); - return; +void LiveSession::cancelBandwidthSwitch() { + Mutex::Autolock lock(mSwapMutex); + mSwitchGeneration++; + mSwitchInProgress = false; + mSwapMask = 0; +} + +bool LiveSession::canSwitchBandwidthTo(size_t bandwidthIndex) { + if (mReconfigurationInProgress || mSwitchInProgress) { + return false; + } + + if (mPrevBandwidthIndex < 0) { + return true; } + if (bandwidthIndex == (size_t)mPrevBandwidthIndex) { + return false; + } else if (bandwidthIndex > (size_t)mPrevBandwidthIndex) { + return canSwitchUp(); + } else { + return true; + } +} + +void LiveSession::onCheckBandwidth() { size_t bandwidthIndex = getBandwidthIndex(); - if (mPrevBandwidthIndex < 0 - || bandwidthIndex != (size_t)mPrevBandwidthIndex) { + if (canSwitchBandwidthTo(bandwidthIndex)) { changeConfiguration(-1ll /* timeUs */, bandwidthIndex); + } else { + scheduleCheckBandwidthEvent(); } // Handling the kWhatCheckBandwidth even here does _not_ automatically diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index c4d125c..91bbcea 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -83,6 +83,11 @@ struct LiveSession : public AHandler { kWhatPreparationFailed, }; + // create a format-change discontinuity + // + // swap: + // whether is format-change discontinuity should trigger a buffer swap + sp createFormatChangeBuffer(bool swap = true); protected: virtual ~LiveSession(); @@ -101,6 +106,7 @@ private: kWhatChangeConfiguration2 = 'chC2', kWhatChangeConfiguration3 = 'chC3', kWhatFinishDisconnect2 = 'fin2', + kWhatSwapped = 'swap', }; struct BandwidthItem { @@ -112,6 +118,7 @@ private: sp mFetcher; int64_t mDurationUs; bool mIsPrepared; + bool mToBeRemoved; }; struct StreamItem { @@ -146,9 +153,26 @@ private: KeyedVector mFetcherInfos; uint32_t mStreamMask; + // Masks used during reconfiguration: + // mNewStreamMask: streams in the variant playlist we're switching to; + // we don't want to immediately overwrite the original value. + uint32_t mNewStreamMask; + + // mSwapMask: streams that have started to playback content in the new variant playlist; + // we use this to track reconfiguration progress. + uint32_t mSwapMask; + KeyedVector > mPacketSources; + // A second set of packet sources that buffer content for the variant we're switching to. + KeyedVector > mPacketSources2; + + // A mutex used to serialize two sets of events: + // * the swapping of packet sources in dequeueAccessUnit on the player thread, AND + // * a forced bandwidth switch termination in cancelSwitch on the live looper. + Mutex mSwapMutex; int32_t mCheckBandwidthGeneration; + int32_t mSwitchGeneration; size_t mContinuationCounter; sp mContinuation; @@ -157,6 +181,7 @@ private: int64_t mRealTimeBaseUs; bool mReconfigurationInProgress; + bool mSwitchInProgress; uint32_t mDisconnectReplyID; sp addFetcher(const char *uri); @@ -199,16 +224,27 @@ private: void onChangeConfiguration(const sp &msg); void onChangeConfiguration2(const sp &msg); void onChangeConfiguration3(const sp &msg); + void onSwapped(const sp &msg); + void tryToFinishBandwidthSwitch(); void scheduleCheckBandwidthEvent(); void cancelCheckBandwidthEvent(); + // cancelBandwidthSwitch is atomic wrt swapPacketSource; call it to prevent packet sources + // from being swapped out on stale discontinuities while manipulating + // mPacketSources/mPacketSources2. + void cancelBandwidthSwitch(); + + bool canSwitchBandwidthTo(size_t bandwidthIndex); void onCheckBandwidth(); void finishDisconnect(); void postPrepared(status_t err); + void swapPacketSource(StreamType stream); + bool canSwitchUp(); + DISALLOW_EVIL_CONSTRUCTORS(LiveSession); }; diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 030cbde..1a02e85 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -48,16 +48,20 @@ namespace android { // static const int64_t PlaylistFetcher::kMinBufferedDurationUs = 10000000ll; const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll; +const int32_t PlaylistFetcher::kNumSkipFrames = 10; PlaylistFetcher::PlaylistFetcher( const sp ¬ify, const sp &session, const char *uri) : mNotify(notify), + mStartTimeUsNotify(notify->dup()), mSession(session), mURI(uri), mStreamTypeMask(0), mStartTimeUs(-1ll), + mMinStartTimeUs(0ll), + mStopParams(NULL), mLastPlaylistFetchTimeUs(-1ll), mSeqNumber(-1), mNumRetries(0), @@ -69,6 +73,8 @@ PlaylistFetcher::PlaylistFetcher( mFirstPTSValid(false), mAbsoluteTimeAnchorUs(0ll) { memset(mPlaylistHash, 0, sizeof(mPlaylistHash)); + mStartTimeUsNotify->setInt32("what", kWhatStartedAt); + mStartTimeUsNotify->setInt32("streamMask", 0); } PlaylistFetcher::~PlaylistFetcher() { @@ -325,7 +331,9 @@ void PlaylistFetcher::startAsync( const sp &audioSource, const sp &videoSource, const sp &subtitleSource, - int64_t startTimeUs) { + int64_t startTimeUs, + int64_t minStartTimeUs, + int32_t startSeqNumberHint) { sp msg = new AMessage(kWhatStart, id()); uint32_t streamTypeMask = 0ul; @@ -347,6 +355,8 @@ void PlaylistFetcher::startAsync( msg->setInt32("streamTypeMask", streamTypeMask); msg->setInt64("startTimeUs", startTimeUs); + msg->setInt64("minStartTimeUs", minStartTimeUs); + msg->setInt32("startSeqNumberHint", startSeqNumberHint); msg->post(); } @@ -358,6 +368,12 @@ void PlaylistFetcher::stopAsync() { (new AMessage(kWhatStop, id()))->post(); } +void PlaylistFetcher::resumeUntilAsync(const sp ¶ms) { + AMessage* msg = new AMessage(kWhatResumeUntil, id()); + msg->setMessage("params", params); + msg->post(); +} + void PlaylistFetcher::onMessageReceived(const sp &msg) { switch (msg->what()) { case kWhatStart: @@ -392,6 +408,7 @@ void PlaylistFetcher::onMessageReceived(const sp &msg) { } case kWhatMonitorQueue: + case kWhatDownloadNext: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); @@ -401,7 +418,17 @@ void PlaylistFetcher::onMessageReceived(const sp &msg) { break; } - onMonitorQueue(); + if (msg->what() == kWhatMonitorQueue) { + onMonitorQueue(); + } else { + onDownloadNext(); + } + break; + } + + case kWhatResumeUntil: + { + onResumeUntil(msg); break; } @@ -417,7 +444,10 @@ status_t PlaylistFetcher::onStart(const sp &msg) { CHECK(msg->findInt32("streamTypeMask", (int32_t *)&streamTypeMask)); int64_t startTimeUs; + int32_t startSeqNumberHint; CHECK(msg->findInt64("startTimeUs", &startTimeUs)); + CHECK(msg->findInt64("minStartTimeUs", (int64_t *) &mMinStartTimeUs)); + CHECK(msg->findInt32("startSeqNumberHint", &startSeqNumberHint)); if (streamTypeMask & LiveSession::STREAMTYPE_AUDIO) { void *ptr; @@ -455,6 +485,10 @@ status_t PlaylistFetcher::onStart(const sp &msg) { mPrepared = false; } + if (startSeqNumberHint >= 0) { + mSeqNumber = startSeqNumberHint; + } + postMonitorQueue(); return OK; @@ -462,20 +496,70 @@ status_t PlaylistFetcher::onStart(const sp &msg) { void PlaylistFetcher::onPause() { cancelMonitorQueue(); +} + +void PlaylistFetcher::onStop() { + cancelMonitorQueue(); mPacketSources.clear(); mStreamTypeMask = 0; } -void PlaylistFetcher::onStop() { - cancelMonitorQueue(); +// Resume until we have reached the boundary timestamps listed in `msg`; when +// the remaining time is too short (within a resume threshold) stop immediately +// instead. +status_t PlaylistFetcher::onResumeUntil(const sp &msg) { + sp params; + CHECK(msg->findMessage("params", ¶ms)); + + bool stop = false; + for (size_t i = 0; i < mPacketSources.size(); i++) { + sp packetSource = mPacketSources.valueAt(i); + + const char *stopKey; + int streamType = mPacketSources.keyAt(i); + switch (streamType) { + case LiveSession::STREAMTYPE_VIDEO: + stopKey = "timeUsVideo"; + break; - for (size_t i = 0; i < mPacketSources.size(); ++i) { - mPacketSources.valueAt(i)->clear(); + case LiveSession::STREAMTYPE_AUDIO: + stopKey = "timeUsAudio"; + break; + + case LiveSession::STREAMTYPE_SUBTITLES: + stopKey = "timeUsSubtitle"; + break; + + default: + TRESPASS(); + } + + // Don't resume if we would stop within a resume threshold. + int64_t latestTimeUs = 0, stopTimeUs = 0; + sp latestMeta = packetSource->getLatestMeta(); + if (latestMeta != NULL + && (latestMeta->findInt64("timeUs", &latestTimeUs) + && params->findInt64(stopKey, &stopTimeUs))) { + int64_t diffUs = stopTimeUs - latestTimeUs; + if (diffUs < resumeThreshold(latestMeta)) { + stop = true; + } + } } - mPacketSources.clear(); - mStreamTypeMask = 0; + if (stop) { + for (size_t i = 0; i < mPacketSources.size(); i++) { + mPacketSources.valueAt(i)->queueAccessUnit(mSession->createFormatChangeBuffer()); + } + stopAsync(); + return OK; + } + + mStopParams = params; + postMonitorQueue(); + + return OK; } void PlaylistFetcher::notifyError(status_t err) { @@ -519,8 +603,9 @@ void PlaylistFetcher::onMonitorQueue() { packetSource->getBufferedDurationUs(&finalResult); finalResult = OK; } else { - bool first = true; - + // Use max stream duration to prevent us from waiting on a non-existent stream; + // when we cannot make out from the manifest what streams are included in a playlist + // we might assume extra streams. for (size_t i = 0; i < mPacketSources.size(); ++i) { if ((mStreamTypeMask & mPacketSources.keyAt(i)) == 0) { continue; @@ -528,9 +613,10 @@ void PlaylistFetcher::onMonitorQueue() { int64_t bufferedStreamDurationUs = mPacketSources.valueAt(i)->getBufferedDurationUs(&finalResult); - if (first || bufferedStreamDurationUs < bufferedDurationUs) { + ALOGV("buffered %lld for stream %d", + bufferedStreamDurationUs, mPacketSources.keyAt(i)); + if (bufferedStreamDurationUs > bufferedDurationUs) { bufferedDurationUs = bufferedStreamDurationUs; - first = false; } } } @@ -550,7 +636,12 @@ void PlaylistFetcher::onMonitorQueue() { if (finalResult == OK && downloadMore) { ALOGV("monitoring, buffered=%lld < %lld", bufferedDurationUs, durationToBufferUs); - onDownloadNext(); + // delay the next download slightly; hopefully this gives other concurrent fetchers + // a better chance to run. + // onDownloadNext(); + sp msg = new AMessage(kWhatDownloadNext, id()); + msg->setInt32("generation", mMonitorQueueGeneration); + msg->post(1000l); } else { // Nothing to do yet, try again in a second. @@ -617,6 +708,12 @@ void PlaylistFetcher::onDownloadNext() { const int32_t lastSeqNumberInPlaylist = firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1; + if (mStartup && mSeqNumber >= 0 + && (mSeqNumber < firstSeqNumberInPlaylist || mSeqNumber > lastSeqNumberInPlaylist)) { + // in case we guessed wrong during reconfiguration, try fetching the latest content. + mSeqNumber = lastSeqNumberInPlaylist; + } + if (mSeqNumber < 0) { CHECK_GE(mStartTimeUs, 0ll); @@ -762,6 +859,18 @@ void PlaylistFetcher::onDownloadNext() { err = extractAndQueueAccessUnits(buffer, itemMeta); + if (err == -EAGAIN) { + // bad starting sequence number hint + postMonitorQueue(); + return; + } + + if (err == ERROR_OUT_OF_RANGE) { + // reached stopping point + stopAsync(); + return; + } + if (err != OK) { notifyError(err); return; @@ -818,12 +927,15 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( } if (mTSParser == NULL) { - mTSParser = new ATSParser; + // Use TS_TIMESTAMPS_ARE_ABSOLUTE so pts carry over between fetchers. + mTSParser = new ATSParser(ATSParser::TS_TIMESTAMPS_ARE_ABSOLUTE); } if (mNextPTSTimeUs >= 0ll) { sp extra = new AMessage; - extra->setInt64(IStreamListener::kKeyMediaTimeUs, mNextPTSTimeUs); + // Since we are using absolute timestamps, signal an offset of 0 to prevent + // ATSParser from skewing the timestamps of access units. + extra->setInt64(IStreamListener::kKeyMediaTimeUs, 0); mTSParser->signalDiscontinuity( ATSParser::DISCONTINUITY_SEEK, extra); @@ -842,17 +954,23 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( offset += 188; } + status_t err = OK; for (size_t i = mPacketSources.size(); i-- > 0;) { sp packetSource = mPacketSources.valueAt(i); + const char *key; ATSParser::SourceType type; - switch (mPacketSources.keyAt(i)) { + const LiveSession::StreamType stream = mPacketSources.keyAt(i); + switch (stream) { + case LiveSession::STREAMTYPE_VIDEO: type = ATSParser::VIDEO; + key = "timeUsVideo"; break; case LiveSession::STREAMTYPE_AUDIO: type = ATSParser::AUDIO; + key = "timeUsAudio"; break; case LiveSession::STREAMTYPE_SUBTITLES: @@ -879,19 +997,87 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( continue; } + int64_t timeUs; sp accessUnit; status_t finalResult; while (source->hasBufferAvailable(&finalResult) && source->dequeueAccessUnit(&accessUnit) == OK) { - // Note that we do NOT dequeue any discontinuities. + + CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); + if (mMinStartTimeUs > 0) { + if (timeUs < mMinStartTimeUs) { + // TODO untested path + // try a later ts + int32_t targetDuration; + mPlaylist->meta()->findInt32("target-duration", &targetDuration); + int32_t incr = (mMinStartTimeUs - timeUs) / 1000000 / targetDuration; + if (incr == 0) { + // increment mSeqNumber by at least one + incr = 1; + } + mSeqNumber += incr; + err = -EAGAIN; + break; + } else { + int64_t startTimeUs; + if (mStartTimeUsNotify != NULL + && !mStartTimeUsNotify->findInt64(key, &startTimeUs)) { + mStartTimeUsNotify->setInt64(key, timeUs); + + uint32_t streamMask = 0; + mStartTimeUsNotify->findInt32("streamMask", (int32_t *) &streamMask); + streamMask |= mPacketSources.keyAt(i); + mStartTimeUsNotify->setInt32("streamMask", streamMask); + + if (streamMask == mStreamTypeMask) { + mStartTimeUsNotify->post(); + mStartTimeUsNotify.clear(); + } + } + } + } + + if (mStopParams != NULL) { + // Queue discontinuity in original stream. + int64_t stopTimeUs; + if (!mStopParams->findInt64(key, &stopTimeUs) || timeUs >= stopTimeUs) { + packetSource->queueAccessUnit(mSession->createFormatChangeBuffer()); + mStreamTypeMask &= ~stream; + mPacketSources.removeItemsAt(i); + break; + } + } + + // Note that we do NOT dequeue any discontinuities except for format change. // for simplicity, store a reference to the format in each unit sp format = source->getFormat(); if (format != NULL) { accessUnit->meta()->setObject("format", format); } + + // Stash the sequence number so we can hint future fetchers where to start at. + accessUnit->meta()->setInt32("seq", mSeqNumber); packetSource->queueAccessUnit(accessUnit); } + + if (err != OK) { + break; + } + } + + if (err != OK) { + for (size_t i = mPacketSources.size(); i-- > 0;) { + sp packetSource = mPacketSources.valueAt(i); + packetSource->clear(); + } + return err; + } + + if (!mStreamTypeMask) { + // Signal gap is filled between original and new stream. + ALOGV("ERROR OUT OF RANGE"); + return ERROR_OUT_OF_RANGE; } return OK; @@ -908,6 +1094,7 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( CHECK(itemMeta->findInt64("durationUs", &durationUs)); buffer->meta()->setInt64("timeUs", getSegmentStartTimeUs(mSeqNumber)); buffer->meta()->setInt64("durationUs", durationUs); + buffer->meta()->setInt32("seq", mSeqNumber); packetSource->queueAccessUnit(buffer); return OK; @@ -1044,6 +1231,7 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( // Each AAC frame encodes 1024 samples. numSamples += 1024; + unit->meta()->setInt32("seq", mSeqNumber); packetSource->queueAccessUnit(unit); offset += aac_frame_length; @@ -1071,4 +1259,33 @@ void PlaylistFetcher::updateDuration() { msg->post(); } +int64_t PlaylistFetcher::resumeThreshold(const sp &msg) { + int64_t durationUs, threshold; + if (msg->findInt64("durationUs", &durationUs)) { + return kNumSkipFrames * durationUs; + } + + sp obj; + msg->findObject("format", &obj); + MetaData *format = static_cast(obj.get()); + + const char *mime; + CHECK(format->findCString(kKeyMIMEType, &mime)); + bool audio = !strncasecmp(mime, "audio/", 6); + if (audio) { + // Assumes 1000 samples per frame. + int32_t sampleRate; + CHECK(format->findInt32(kKeySampleRate, &sampleRate)); + return kNumSkipFrames /* frames */ * 1000 /* samples */ + * (1000000 / sampleRate) /* sample duration (us) */; + } else { + int32_t frameRate; + if (format->findInt32(kKeyFrameRate, &frameRate) && frameRate > 0) { + return kNumSkipFrames * (1000000 / frameRate); + } + } + + return 500000ll; +} + } // namespace android diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index ac04a77..2e0349f 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -43,6 +43,7 @@ struct PlaylistFetcher : public AHandler { kWhatTemporarilyDoneFetching, kWhatPrepared, kWhatPreparationFailed, + kWhatStartedAt, }; PlaylistFetcher( @@ -56,12 +57,16 @@ struct PlaylistFetcher : public AHandler { const sp &audioSource, const sp &videoSource, const sp &subtitleSource, - int64_t startTimeUs = -1ll); + int64_t startTimeUs = -1ll, + int64_t minStartTimeUs = 0ll /* start after this timestamp */, + int32_t startSeqNumberHint = -1 /* try starting at this sequence number */); void pauseAsync(); void stopAsync(); + void resumeUntilAsync(const sp ¶ms); + protected: virtual ~PlaylistFetcher(); virtual void onMessageReceived(const sp &msg); @@ -76,17 +81,25 @@ private: kWhatPause = 'paus', kWhatStop = 'stop', kWhatMonitorQueue = 'moni', + kWhatResumeUntil = 'rsme', + kWhatDownloadNext = 'dlnx', }; static const int64_t kMinBufferedDurationUs; static const int64_t kMaxMonitorDelayUs; + static const int32_t kNumSkipFrames; + // notifications to mSession sp mNotify; + sp mStartTimeUsNotify; + sp mSession; AString mURI; uint32_t mStreamTypeMask; int64_t mStartTimeUs; + int64_t mMinStartTimeUs; // start fetching no earlier than this value + sp mStopParams; // message containing the latest timestamps we should fetch. KeyedVector > mPacketSources; @@ -153,6 +166,9 @@ private: void onMonitorQueue(); void onDownloadNext(); + // Resume a fetcher to continue until the stopping point stored in msg. + status_t onResumeUntil(const sp &msg); + status_t extractAndQueueAccessUnits( const sp &buffer, const sp &itemMeta); @@ -165,6 +181,10 @@ private: void updateDuration(); + // Before resuming a fetcher in onResume, check the remaining duration is longer than that + // returned by resumeThreshold. + int64_t resumeThreshold(const sp &msg); + DISALLOW_EVIL_CONSTRUCTORS(PlaylistFetcher); }; -- cgit v1.1 From 720ad9ddb2ac6b55b0dfbfcd2d8360151d8ac427 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 4 Feb 2014 11:00:59 -0800 Subject: AudioTrack non-blocking write Bug 7531968 Change-Id: I6d0e79fa8cab5b6eb36bcc34977f4cf0d7eec8ea --- media/libmedia/AudioTrack.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 5c62260..3184902 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1270,7 +1270,7 @@ void AudioTrack::releaseBuffer(Buffer* audioBuffer) // ------------------------------------------------------------------------- -ssize_t AudioTrack::write(const void* buffer, size_t userSize) +ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking) { if (mTransfer != TRANSFER_SYNC || mIsTimed) { return INVALID_OPERATION; @@ -1289,7 +1289,8 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) while (userSize >= mFrameSize) { audioBuffer.frameCount = userSize / mFrameSize; - status_t err = obtainBuffer(&audioBuffer, &ClientProxy::kForever); + status_t err = obtainBuffer(&audioBuffer, + blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking); if (err < 0) { if (written > 0) { break; -- cgit v1.1 From bf927f8ec7979f2b64331c2b2f12a6a5dba05bca Mon Sep 17 00:00:00 2001 From: Vignesh Venkatasubramanian Date: Wed, 29 Jan 2014 09:00:46 -0800 Subject: Opus Matroska support in OpenMax Adding Openmax component for libopus software decoder. This can decode opus audio files embedded in matroska containers. Change-Id: I7e0691cfc6d719c4e927b9efbd05a3143be49abc Note: This CL is part of adding Opus support to Android. --- media/libstagefright/ACodec.cpp | 2 + media/libstagefright/Android.mk | 1 + media/libstagefright/MediaDefs.cpp | 1 + media/libstagefright/OMXCodec.cpp | 10 + media/libstagefright/Utils.cpp | 8 + media/libstagefright/codecs/opus/Android.mk | 4 + media/libstagefright/codecs/opus/dec/Android.mk | 19 + media/libstagefright/codecs/opus/dec/SoftOpus.cpp | 537 +++++++++++++++++++++ media/libstagefright/codecs/opus/dec/SoftOpus.h | 94 ++++ .../libstagefright/matroska/MatroskaExtractor.cpp | 11 +- media/libstagefright/matroska/MatroskaExtractor.h | 1 + media/libstagefright/omx/SoftOMXPlugin.cpp | 1 + media/libstagefright/omx/tests/OMXHarness.cpp | 2 + 13 files changed, 689 insertions(+), 2 deletions(-) create mode 100644 media/libstagefright/codecs/opus/Android.mk create mode 100644 media/libstagefright/codecs/opus/dec/Android.mk create mode 100644 media/libstagefright/codecs/opus/dec/SoftOpus.cpp create mode 100644 media/libstagefright/codecs/opus/dec/SoftOpus.h (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index ac78d6c..13f2a2e 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -962,6 +962,8 @@ status_t ACodec::setComponentRole( "audio_decoder.aac", "audio_encoder.aac" }, { MEDIA_MIMETYPE_AUDIO_VORBIS, "audio_decoder.vorbis", "audio_encoder.vorbis" }, + { MEDIA_MIMETYPE_AUDIO_OPUS, + "audio_decoder.opus", "audio_encoder.opus" }, { MEDIA_MIMETYPE_AUDIO_G711_MLAW, "audio_decoder.g711mlaw", "audio_encoder.g711mlaw" }, { MEDIA_MIMETYPE_AUDIO_G711_ALAW, diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 0636dcc..0fd1e69 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -81,6 +81,7 @@ LOCAL_SHARED_LIBRARIES := \ libicuuc \ liblog \ libmedia \ + libopus \ libsonivox \ libssl \ libstagefright_omx \ diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp index 340cba7..c670bb4 100644 --- a/media/libstagefright/MediaDefs.cpp +++ b/media/libstagefright/MediaDefs.cpp @@ -36,6 +36,7 @@ const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II = "audio/mpeg-L2"; const char *MEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm"; const char *MEDIA_MIMETYPE_AUDIO_QCELP = "audio/qcelp"; const char *MEDIA_MIMETYPE_AUDIO_VORBIS = "audio/vorbis"; +const char *MEDIA_MIMETYPE_AUDIO_OPUS = "audio/opus"; const char *MEDIA_MIMETYPE_AUDIO_G711_ALAW = "audio/g711-alaw"; const char *MEDIA_MIMETYPE_AUDIO_G711_MLAW = "audio/g711-mlaw"; const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw"; diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 625922f..4d3b5bd 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -489,6 +489,13 @@ status_t OMXCodec::configureCodec(const sp &meta) { CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size)); addCodecSpecificData(data, size); + } else if (meta->findData(kKeyOpusHeader, &type, &data, &size)) { + addCodecSpecificData(data, size); + + CHECK(meta->findData(kKeyOpusCodecDelay, &type, &data, &size)); + addCodecSpecificData(data, size); + CHECK(meta->findData(kKeyOpusSeekPreRoll, &type, &data, &size)); + addCodecSpecificData(data, size); } } @@ -1387,6 +1394,8 @@ void OMXCodec::setComponentRole( "audio_decoder.aac", "audio_encoder.aac" }, { MEDIA_MIMETYPE_AUDIO_VORBIS, "audio_decoder.vorbis", "audio_encoder.vorbis" }, + { MEDIA_MIMETYPE_AUDIO_OPUS, + "audio_decoder.opus", "audio_encoder.opus" }, { MEDIA_MIMETYPE_AUDIO_G711_MLAW, "audio_decoder.g711mlaw", "audio_encoder.g711mlaw" }, { MEDIA_MIMETYPE_AUDIO_G711_ALAW, @@ -4125,6 +4134,7 @@ static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) { "OMX_AUDIO_CodingMP3", "OMX_AUDIO_CodingSBC", "OMX_AUDIO_CodingVORBIS", + "OMX_AUDIO_CodingOPUS", "OMX_AUDIO_CodingWMA", "OMX_AUDIO_CodingRA", "OMX_AUDIO_CodingMIDI", diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 216a329..b5a730e 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -251,6 +251,13 @@ status_t convertMetaDataToMessage( buffer->meta()->setInt32("csd", true); buffer->meta()->setInt64("timeUs", 0); msg->setBuffer("csd-1", buffer); + } else if (meta->findData(kKeyOpusHeader, &type, &data, &size)) { + sp buffer = new ABuffer(size); + memcpy(buffer->data(), data, size); + + buffer->meta()->setInt32("csd", true); + buffer->meta()->setInt64("timeUs", 0); + msg->setBuffer("csd-0", buffer); } *format = msg; @@ -523,6 +530,7 @@ static const struct mime_conv_t mimeLookup[] = { { MEDIA_MIMETYPE_AUDIO_AMR_WB, AUDIO_FORMAT_AMR_WB }, { MEDIA_MIMETYPE_AUDIO_AAC, AUDIO_FORMAT_AAC }, { MEDIA_MIMETYPE_AUDIO_VORBIS, AUDIO_FORMAT_VORBIS }, + { MEDIA_MIMETYPE_AUDIO_OPUS, AUDIO_FORMAT_OPUS}, { 0, AUDIO_FORMAT_INVALID } }; diff --git a/media/libstagefright/codecs/opus/Android.mk b/media/libstagefright/codecs/opus/Android.mk new file mode 100644 index 0000000..365b179 --- /dev/null +++ b/media/libstagefright/codecs/opus/Android.mk @@ -0,0 +1,4 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +include $(call all-makefiles-under,$(LOCAL_PATH)) \ No newline at end of file diff --git a/media/libstagefright/codecs/opus/dec/Android.mk b/media/libstagefright/codecs/opus/dec/Android.mk new file mode 100644 index 0000000..2379c5f --- /dev/null +++ b/media/libstagefright/codecs/opus/dec/Android.mk @@ -0,0 +1,19 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + SoftOpus.cpp + +LOCAL_C_INCLUDES := \ + external/libopus/include \ + frameworks/av/media/libstagefright/include \ + frameworks/native/include/media/openmax \ + +LOCAL_SHARED_LIBRARIES := \ + libopus libstagefright libstagefright_omx \ + libstagefright_foundation libutils liblog + +LOCAL_MODULE := libstagefright_soft_opusdec +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp new file mode 100644 index 0000000..6e41097 --- /dev/null +++ b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoftOpus" +#include + +#include "SoftOpus.h" + +#include +#include + +extern "C" { + #include + #include +} + +namespace android { + +static const int kRate = 48000; + +template +static void InitOMXParams(T *params) { + params->nSize = sizeof(T); + params->nVersion.s.nVersionMajor = 1; + params->nVersion.s.nVersionMinor = 0; + params->nVersion.s.nRevision = 0; + params->nVersion.s.nStep = 0; +} + +SoftOpus::SoftOpus( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component) + : SimpleSoftOMXComponent(name, callbacks, appData, component), + mInputBufferCount(0), + mDecoder(NULL), + mHeader(NULL), + mCodecDelay(0), + mSeekPreRoll(0), + mAnchorTimeUs(0), + mNumFramesOutput(0), + mOutputPortSettingsChange(NONE) { + initPorts(); + CHECK_EQ(initDecoder(), (status_t)OK); +} + +SoftOpus::~SoftOpus() { + if (mDecoder != NULL) { + opus_multistream_decoder_destroy(mDecoder); + mDecoder = NULL; + } + if (mHeader != NULL) { + delete mHeader; + mHeader = NULL; + } +} + +void SoftOpus::initPorts() { + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + + def.nPortIndex = 0; + def.eDir = OMX_DirInput; + def.nBufferCountMin = kNumBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.nBufferSize = 960 * 6; + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainAudio; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 1; + + def.format.audio.cMIMEType = + const_cast(MEDIA_MIMETYPE_AUDIO_OPUS); + + def.format.audio.pNativeRender = NULL; + def.format.audio.bFlagErrorConcealment = OMX_FALSE; + def.format.audio.eEncoding = OMX_AUDIO_CodingAndroidOPUS; + + addPort(def); + + def.nPortIndex = 1; + def.eDir = OMX_DirOutput; + def.nBufferCountMin = kNumBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t); + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainAudio; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 2; + + def.format.audio.cMIMEType = const_cast("audio/raw"); + def.format.audio.pNativeRender = NULL; + def.format.audio.bFlagErrorConcealment = OMX_FALSE; + def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; + + addPort(def); +} + +status_t SoftOpus::initDecoder() { + return OK; +} + +OMX_ERRORTYPE SoftOpus::internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params) { + switch (index) { + case OMX_IndexParamAudioAndroidOpus: + { + OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams = + (OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *)params; + + if (opusParams->nPortIndex != 0) { + return OMX_ErrorUndefined; + } + + opusParams->nAudioBandWidth = 0; + opusParams->nSampleRate = kRate; + opusParams->nBitRate = 0; + + if (!isConfigured()) { + opusParams->nChannels = 1; + } else { + opusParams->nChannels = mHeader->channels; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPcm: + { + OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = + (OMX_AUDIO_PARAM_PCMMODETYPE *)params; + + if (pcmParams->nPortIndex != 1) { + return OMX_ErrorUndefined; + } + + pcmParams->eNumData = OMX_NumericalDataSigned; + pcmParams->eEndian = OMX_EndianBig; + pcmParams->bInterleaved = OMX_TRUE; + pcmParams->nBitPerSample = 16; + pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; + pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; + pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; + pcmParams->nSamplingRate = kRate; + + if (!isConfigured()) { + pcmParams->nChannels = 1; + } else { + pcmParams->nChannels = mHeader->channels; + } + + return OMX_ErrorNone; + } + + default: + return SimpleSoftOMXComponent::internalGetParameter(index, params); + } +} + +OMX_ERRORTYPE SoftOpus::internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params) { + switch (index) { + case OMX_IndexParamStandardComponentRole: + { + const OMX_PARAM_COMPONENTROLETYPE *roleParams = + (const OMX_PARAM_COMPONENTROLETYPE *)params; + + if (strncmp((const char *)roleParams->cRole, + "audio_decoder.opus", + OMX_MAX_STRINGNAME_SIZE - 1)) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioAndroidOpus: + { + const OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams = + (const OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *)params; + + if (opusParams->nPortIndex != 0) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + default: + return SimpleSoftOMXComponent::internalSetParameter(index, params); + } +} + +bool SoftOpus::isConfigured() const { + return mInputBufferCount >= 1; +} + +static uint16_t ReadLE16(const uint8_t *data, size_t data_size, + uint32_t read_offset) { + if (read_offset + 1 > data_size) + return 0; + uint16_t val; + val = data[read_offset]; + val |= data[read_offset + 1] << 8; + return val; +} + +// Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies +// mappings for up to 8 channels. This information is part of the Vorbis I +// Specification: +// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html +static const int kMaxChannels = 8; + +// Maximum packet size used in Xiph's opusdec. +static const int kMaxOpusOutputPacketSizeSamples = 960 * 6; + +// Default audio output channel layout. Used to initialize |stream_map| in +// OpusHeader, and passed to opus_multistream_decoder_create() when the header +// does not contain mapping information. The values are valid only for mono and +// stereo output: Opus streams with more than 2 channels require a stream map. +static const int kMaxChannelsWithDefaultLayout = 2; +static const uint8_t kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = { 0, 1 }; + +// Parses Opus Header. Header spec: http://wiki.xiph.org/OggOpus#ID_Header +static bool ParseOpusHeader(const uint8_t *data, size_t data_size, + OpusHeader* header) { + // Size of the Opus header excluding optional mapping information. + const int kOpusHeaderSize = 19; + + // Offset to the channel count byte in the Opus header. + const int kOpusHeaderChannelsOffset = 9; + + // Offset to the pre-skip value in the Opus header. + const int kOpusHeaderSkipSamplesOffset = 10; + + // Offset to the gain value in the Opus header. + const int kOpusHeaderGainOffset = 16; + + // Offset to the channel mapping byte in the Opus header. + const int kOpusHeaderChannelMappingOffset = 18; + + // Opus Header contains a stream map. The mapping values are in the header + // beyond the always present |kOpusHeaderSize| bytes of data. The mapping + // data contains stream count, coupling information, and per channel mapping + // values: + // - Byte 0: Number of streams. + // - Byte 1: Number coupled. + // - Byte 2: Starting at byte 2 are |header->channels| uint8 mapping + // values. + const int kOpusHeaderNumStreamsOffset = kOpusHeaderSize; + const int kOpusHeaderNumCoupledOffset = kOpusHeaderNumStreamsOffset + 1; + const int kOpusHeaderStreamMapOffset = kOpusHeaderNumStreamsOffset + 2; + + if (data_size < kOpusHeaderSize) { + ALOGV("Header size is too small."); + return false; + } + header->channels = *(data + kOpusHeaderChannelsOffset); + + if (header->channels <= 0 || header->channels > kMaxChannels) { + ALOGV("Invalid Header, wrong channel count: %d", header->channels); + return false; + } + header->skip_samples = ReadLE16(data, data_size, + kOpusHeaderSkipSamplesOffset); + header->gain_db = static_cast( + ReadLE16(data, data_size, + kOpusHeaderGainOffset)); + header->channel_mapping = *(data + kOpusHeaderChannelMappingOffset); + if (!header->channel_mapping) { + if (header->channels > kMaxChannelsWithDefaultLayout) { + ALOGV("Invalid Header, missing stream map."); + return false; + } + header->num_streams = 1; + header->num_coupled = header->channels > 1; + header->stream_map[0] = 0; + header->stream_map[1] = 1; + return true; + } + if (data_size < kOpusHeaderStreamMapOffset + header->channels) { + ALOGV("Invalid stream map; insufficient data for current channel " + "count: %d", header->channels); + return false; + } + header->num_streams = *(data + kOpusHeaderNumStreamsOffset); + header->num_coupled = *(data + kOpusHeaderNumCoupledOffset); + if (header->num_streams + header->num_coupled != header->channels) { + ALOGV("Inconsistent channel mapping."); + return false; + } + for (int i = 0; i < header->channels; ++i) + header->stream_map[i] = *(data + kOpusHeaderStreamMapOffset + i); + return true; +} + +// Convert nanoseconds to number of samples. +static uint64_t ns_to_samples(uint64_t ns, int kRate) { + return static_cast(ns) * kRate / 1000000000; +} + +void SoftOpus::onQueueFilled(OMX_U32 portIndex) { + List &inQueue = getPortQueue(0); + List &outQueue = getPortQueue(1); + + if (mOutputPortSettingsChange != NONE) { + return; + } + + if (portIndex == 0 && mInputBufferCount < 3) { + BufferInfo *info = *inQueue.begin(); + OMX_BUFFERHEADERTYPE *header = info->mHeader; + + const uint8_t *data = header->pBuffer + header->nOffset; + size_t size = header->nFilledLen; + + if (mInputBufferCount == 0) { + CHECK(mHeader == NULL); + mHeader = new OpusHeader(); + memset(mHeader, 0, sizeof(*mHeader)); + if (!ParseOpusHeader(data, size, mHeader)) { + ALOGV("Parsing Opus Header failed."); + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } + + uint8_t channel_mapping[kMaxChannels] = {0}; + memcpy(&channel_mapping, + kDefaultOpusChannelLayout, + kMaxChannelsWithDefaultLayout); + + int status = OPUS_INVALID_STATE; + mDecoder = opus_multistream_decoder_create(kRate, + mHeader->channels, + mHeader->num_streams, + mHeader->num_coupled, + channel_mapping, + &status); + if (!mDecoder || status != OPUS_OK) { + ALOGV("opus_multistream_decoder_create failed status=%s", + opus_strerror(status)); + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } + status = + opus_multistream_decoder_ctl(mDecoder, + OPUS_SET_GAIN(mHeader->gain_db)); + if (status != OPUS_OK) { + ALOGV("Failed to set OPUS header gain; status=%s", + opus_strerror(status)); + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } + } else if (mInputBufferCount == 1) { + mCodecDelay = ns_to_samples( + *(reinterpret_cast(header->pBuffer + + header->nOffset)), + kRate); + mSamplesToDiscard = mCodecDelay; + } else { + mSeekPreRoll = ns_to_samples( + *(reinterpret_cast(header->pBuffer + + header->nOffset)), + kRate); + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + } + + inQueue.erase(inQueue.begin()); + info->mOwnedByUs = false; + notifyEmptyBufferDone(header); + ++mInputBufferCount; + return; + } + + while (!inQueue.empty() && !outQueue.empty()) { + BufferInfo *inInfo = *inQueue.begin(); + OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; + + BufferInfo *outInfo = *outQueue.begin(); + OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; + + if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { + inQueue.erase(inQueue.begin()); + inInfo->mOwnedByUs = false; + notifyEmptyBufferDone(inHeader); + + outHeader->nFilledLen = 0; + outHeader->nFlags = OMX_BUFFERFLAG_EOS; + + outQueue.erase(outQueue.begin()); + outInfo->mOwnedByUs = false; + notifyFillBufferDone(outHeader); + return; + } + + if (inHeader->nOffset == 0) { + mAnchorTimeUs = inHeader->nTimeStamp; + mNumFramesOutput = 0; + } + + // When seeking to zero, |mCodecDelay| samples has to be discarded + // instead of |mSeekPreRoll| samples (as we would when seeking to any + // other timestamp). + if (inHeader->nTimeStamp == 0) { + mSamplesToDiscard = mCodecDelay; + } + + const uint8_t *data = inHeader->pBuffer + inHeader->nOffset; + const uint32_t size = inHeader->nFilledLen; + + int numFrames = opus_multistream_decode(mDecoder, + data, + size, + (int16_t *)outHeader->pBuffer, + kMaxOpusOutputPacketSizeSamples, + 0); + if (numFrames < 0) { + ALOGE("opus_multistream_decode returned %d", numFrames); + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } + + outHeader->nOffset = 0; + if (mSamplesToDiscard > 0) { + if (mSamplesToDiscard > numFrames) { + mSamplesToDiscard -= numFrames; + numFrames = 0; + } else { + numFrames -= mSamplesToDiscard; + outHeader->nOffset = mSamplesToDiscard * sizeof(int16_t) * + mHeader->channels; + mSamplesToDiscard = 0; + } + } + + outHeader->nFilledLen = numFrames * sizeof(int16_t) * mHeader->channels; + outHeader->nFlags = 0; + + outHeader->nTimeStamp = mAnchorTimeUs + + (mNumFramesOutput * 1000000ll) / + kRate; + + mNumFramesOutput += numFrames; + + inInfo->mOwnedByUs = false; + inQueue.erase(inQueue.begin()); + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + + outInfo->mOwnedByUs = false; + outQueue.erase(outQueue.begin()); + outInfo = NULL; + notifyFillBufferDone(outHeader); + outHeader = NULL; + + ++mInputBufferCount; + } +} + +void SoftOpus::onPortFlushCompleted(OMX_U32 portIndex) { + if (portIndex == 0 && mDecoder != NULL) { + // Make sure that the next buffer output does not still + // depend on fragments from the last one decoded. + mNumFramesOutput = 0; + opus_multistream_decoder_ctl(mDecoder, OPUS_RESET_STATE); + mAnchorTimeUs = 0; + mSamplesToDiscard = mSeekPreRoll; + } +} + +void SoftOpus::onReset() { + mInputBufferCount = 0; + mNumFramesOutput = 0; + if (mDecoder != NULL) { + opus_multistream_decoder_destroy(mDecoder); + mDecoder = NULL; + } + if (mHeader != NULL) { + delete mHeader; + mHeader = NULL; + } + + mOutputPortSettingsChange = NONE; +} + +void SoftOpus::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { + if (portIndex != 1) { + return; + } + + switch (mOutputPortSettingsChange) { + case NONE: + break; + + case AWAITING_DISABLED: + { + CHECK(!enabled); + mOutputPortSettingsChange = AWAITING_ENABLED; + break; + } + + default: + { + CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); + CHECK(enabled); + mOutputPortSettingsChange = NONE; + break; + } + } +} + +} // namespace android + +android::SoftOMXComponent *createSoftOMXComponent( + const char *name, const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, OMX_COMPONENTTYPE **component) { + return new android::SoftOpus(name, callbacks, appData, component); +} diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.h b/media/libstagefright/codecs/opus/dec/SoftOpus.h new file mode 100644 index 0000000..97f6561 --- /dev/null +++ b/media/libstagefright/codecs/opus/dec/SoftOpus.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014 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. + */ + +/* + * The Opus specification is part of IETF RFC 6716: + * http://tools.ietf.org/html/rfc6716 + */ + +#ifndef SOFT_OPUS_H_ + +#define SOFT_OPUS_H_ + +#include "SimpleSoftOMXComponent.h" + +struct OpusMSDecoder; + +namespace android { + +struct OpusHeader { + int channels; + int skip_samples; + int channel_mapping; + int num_streams; + int num_coupled; + int16_t gain_db; + uint8_t stream_map[8]; +}; + +struct SoftOpus : public SimpleSoftOMXComponent { + SoftOpus(const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component); + +protected: + virtual ~SoftOpus(); + + virtual OMX_ERRORTYPE internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params); + + virtual OMX_ERRORTYPE internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params); + + virtual void onQueueFilled(OMX_U32 portIndex); + virtual void onPortFlushCompleted(OMX_U32 portIndex); + virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled); + virtual void onReset(); + +private: + enum { + kNumBuffers = 4, + kMaxNumSamplesPerBuffer = 960 * 6 + }; + + size_t mInputBufferCount; + + OpusMSDecoder *mDecoder; + OpusHeader *mHeader; + + int64_t mCodecDelay; + int64_t mSeekPreRoll; + int64_t mSamplesToDiscard; + int64_t mAnchorTimeUs; + int64_t mNumFramesOutput; + + enum { + NONE, + AWAITING_DISABLED, + AWAITING_ENABLED + } mOutputPortSettingsChange; + + void initPorts(); + status_t initDecoder(); + bool isConfigured() const; + + DISALLOW_EVIL_CONSTRUCTORS(SoftOpus); +}; + +} // namespace android + +#endif // SOFT_OPUS_H_ diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index 6f69d0b..6ec9263 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -313,7 +313,7 @@ void BlockIterator::seek( *actualFrameTimeUs = -1ll; - const int64_t seekTimeNs = seekTimeUs * 1000ll; + const int64_t seekTimeNs = seekTimeUs * 1000ll - mExtractor->mSeekPreRollNs; mkvparser::Segment* const pSegment = mExtractor->mSegment; @@ -628,7 +628,8 @@ MatroskaExtractor::MatroskaExtractor(const sp &source) mReader(new DataSourceReader(mDataSource)), mSegment(NULL), mExtractedThumbnails(false), - mIsWebm(false) { + mIsWebm(false), + mSeekPreRollNs(0) { off64_t size; mIsLiveStreaming = (mDataSource->flags() @@ -919,6 +920,12 @@ void MatroskaExtractor::addTracks() { err = addVorbisCodecInfo( meta, codecPrivate, codecPrivateSize); + } else if (!strcmp("A_OPUS", codecID)) { + meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_OPUS); + meta->setData(kKeyOpusHeader, 0, codecPrivate, codecPrivateSize); + meta->setInt64(kKeyOpusCodecDelay, track->GetCodecDelay()); + meta->setInt64(kKeyOpusSeekPreRoll, track->GetSeekPreRoll()); + mSeekPreRollNs = track->GetSeekPreRoll(); } else if (!strcmp("A_MPEG/L3", codecID)) { meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); } else { diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h index 1294b4f..cf200f3 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.h +++ b/media/libstagefright/matroska/MatroskaExtractor.h @@ -69,6 +69,7 @@ private: bool mExtractedThumbnails; bool mIsLiveStreaming; bool mIsWebm; + int64_t mSeekPreRollNs; void addTracks(); void findThumbnails(); diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp index d49e50b..65f5404 100644 --- a/media/libstagefright/omx/SoftOMXPlugin.cpp +++ b/media/libstagefright/omx/SoftOMXPlugin.cpp @@ -50,6 +50,7 @@ static const struct { { "OMX.google.mpeg4.encoder", "mpeg4enc", "video_encoder.mpeg4" }, { "OMX.google.mp3.decoder", "mp3dec", "audio_decoder.mp3" }, { "OMX.google.vorbis.decoder", "vorbisdec", "audio_decoder.vorbis" }, + { "OMX.google.opus.decoder", "opusdec", "audio_decoder.opus" }, { "OMX.google.vp8.decoder", "vpxdec", "video_decoder.vp8" }, { "OMX.google.vp9.decoder", "vpxdec", "video_decoder.vp9" }, { "OMX.google.vp8.encoder", "vpxenc", "video_encoder.vp8" }, diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp index 03725df..f4dfd6b 100644 --- a/media/libstagefright/omx/tests/OMXHarness.cpp +++ b/media/libstagefright/omx/tests/OMXHarness.cpp @@ -463,6 +463,7 @@ static const char *GetMimeFromComponentRole(const char *componentRole) { { "audio_decoder.aac", "audio/mp4a-latm" }, { "audio_decoder.mp3", "audio/mpeg" }, { "audio_decoder.vorbis", "audio/vorbis" }, + { "audio_decoder.opus", "audio/opus" }, { "audio_decoder.g711alaw", MEDIA_MIMETYPE_AUDIO_G711_ALAW }, { "audio_decoder.g711mlaw", MEDIA_MIMETYPE_AUDIO_G711_MLAW }, }; @@ -495,6 +496,7 @@ static const char *GetURLForMime(const char *mime) { { "audio/mpeg", "file:///sdcard/media_api/music/MP3_48KHz_128kbps_s_1_17_CBR.mp3" }, { "audio/vorbis", NULL }, + { "audio/opus", NULL }, { "video/x-vnd.on2.vp8", "file:///sdcard/media_api/video/big-buck-bunny_trailer.webm" }, { MEDIA_MIMETYPE_AUDIO_G711_ALAW, "file:///sdcard/M1F1-Alaw-AFsp.wav" }, -- cgit v1.1 From 17d653523898c01816457743ab376a7b0427611f Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 3 Mar 2014 22:23:13 -0800 Subject: stagefright: SoftOpus: add explicit include files Also resolved new warnings Change-Id: I41423b20f80400567bf192c4b4e95c6a29d84782 --- media/libstagefright/codecs/opus/dec/SoftOpus.cpp | 25 +++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp index 6e41097..b8084ae 100644 --- a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp +++ b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp @@ -19,6 +19,8 @@ #include #include "SoftOpus.h" +#include +#include #include #include @@ -90,7 +92,8 @@ void SoftOpus::initPorts() { def.format.audio.pNativeRender = NULL; def.format.audio.bFlagErrorConcealment = OMX_FALSE; - def.format.audio.eEncoding = OMX_AUDIO_CodingAndroidOPUS; + def.format.audio.eEncoding = + (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS; addPort(def); @@ -119,7 +122,7 @@ status_t SoftOpus::initDecoder() { OMX_ERRORTYPE SoftOpus::internalGetParameter( OMX_INDEXTYPE index, OMX_PTR params) { - switch (index) { + switch ((int)index) { case OMX_IndexParamAudioAndroidOpus: { OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams = @@ -176,7 +179,7 @@ OMX_ERRORTYPE SoftOpus::internalGetParameter( OMX_ERRORTYPE SoftOpus::internalSetParameter( OMX_INDEXTYPE index, const OMX_PTR params) { - switch (index) { + switch ((int)index) { case OMX_IndexParamStandardComponentRole: { const OMX_PARAM_COMPONENTROLETYPE *roleParams = @@ -242,19 +245,19 @@ static const uint8_t kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = static bool ParseOpusHeader(const uint8_t *data, size_t data_size, OpusHeader* header) { // Size of the Opus header excluding optional mapping information. - const int kOpusHeaderSize = 19; + const size_t kOpusHeaderSize = 19; // Offset to the channel count byte in the Opus header. - const int kOpusHeaderChannelsOffset = 9; + const size_t kOpusHeaderChannelsOffset = 9; // Offset to the pre-skip value in the Opus header. - const int kOpusHeaderSkipSamplesOffset = 10; + const size_t kOpusHeaderSkipSamplesOffset = 10; // Offset to the gain value in the Opus header. - const int kOpusHeaderGainOffset = 16; + const size_t kOpusHeaderGainOffset = 16; // Offset to the channel mapping byte in the Opus header. - const int kOpusHeaderChannelMappingOffset = 18; + const size_t kOpusHeaderChannelMappingOffset = 18; // Opus Header contains a stream map. The mapping values are in the header // beyond the always present |kOpusHeaderSize| bytes of data. The mapping @@ -264,9 +267,9 @@ static bool ParseOpusHeader(const uint8_t *data, size_t data_size, // - Byte 1: Number coupled. // - Byte 2: Starting at byte 2 are |header->channels| uint8 mapping // values. - const int kOpusHeaderNumStreamsOffset = kOpusHeaderSize; - const int kOpusHeaderNumCoupledOffset = kOpusHeaderNumStreamsOffset + 1; - const int kOpusHeaderStreamMapOffset = kOpusHeaderNumStreamsOffset + 2; + const size_t kOpusHeaderNumStreamsOffset = kOpusHeaderSize; + const size_t kOpusHeaderNumCoupledOffset = kOpusHeaderNumStreamsOffset + 1; + const size_t kOpusHeaderStreamMapOffset = kOpusHeaderNumStreamsOffset + 2; if (data_size < kOpusHeaderSize) { ALOGV("Header size is too small."); -- cgit v1.1 From bdc0609f8133517b8e051938ad66bac750be90b4 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 7 Feb 2014 12:26:58 -0800 Subject: PlaylistFetcher: fix infinite loop when parsing ADTS. First check for embedded ID3 tag, then bail out if invalid. Bug: 12934795 Change-Id: I74acebed4bfb2c6ca44dfe936166fdba8510233f --- media/libstagefright/httplive/PlaylistFetcher.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'media') diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 1a02e85..2649705 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -1220,6 +1220,18 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( | (adtsHeader[4] << 3) | (adtsHeader[5] >> 5); + if (aac_frame_length == 0) { + const uint8_t *id3Header = adtsHeader; + if (!memcmp(id3Header, "ID3", 3)) { + ID3 id3(id3Header, buffer->size() - offset, true); + if (id3.isValid()) { + offset += id3.rawSize(); + continue; + }; + } + return ERROR_MALFORMED; + } + CHECK_LE(offset + aac_frame_length, buffer->size()); sp unit = new ABuffer(aac_frame_length); -- cgit v1.1 From f2e55f1f42180f61f2bac90cc60f23f3509ce95d Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Wed, 5 Mar 2014 15:38:26 -0800 Subject: FramebufferNativeWindow.h is obsolete Change-Id: I7d2b06bc711694deb481ae50596080b6bef23f11 --- media/libstagefright/tests/SurfaceMediaSource_test.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp index aeecdbc..a3093d0 100644 --- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp +++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp @@ -35,7 +35,6 @@ #include #include -#include #include #include -- cgit v1.1 From ebcb254adb7402ab89ae97c4d9d16d886790dcb3 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 5 Mar 2014 18:30:08 -0800 Subject: audio policy service: clean up type casting. Change-Id: If16d6495c16e0d61a221f81bfd49e7d14bbfdc12 --- media/libmedia/IAudioPolicyService.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 4be3c09..1a027a6 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -476,10 +476,11 @@ status_t BnAudioPolicyService::onTransact( case START_OUTPUT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_io_handle_t output = static_cast (data.readInt32()); - uint32_t stream = data.readInt32(); + audio_stream_type_t stream = + static_cast (data.readInt32()); int session = data.readInt32(); reply->writeInt32(static_cast (startOutput(output, - (audio_stream_type_t)stream, + stream, session))); return NO_ERROR; } break; @@ -487,10 +488,11 @@ status_t BnAudioPolicyService::onTransact( case STOP_OUTPUT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_io_handle_t output = static_cast (data.readInt32()); - uint32_t stream = data.readInt32(); + audio_stream_type_t stream = + static_cast (data.readInt32()); int session = data.readInt32(); reply->writeInt32(static_cast (stopOutput(output, - (audio_stream_type_t)stream, + stream, session))); return NO_ERROR; } break; @@ -633,7 +635,7 @@ status_t BnAudioPolicyService::onTransact( CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_stream_type_t stream = (audio_stream_type_t) data.readInt32(); uint32_t inPastMs = (uint32_t)data.readInt32(); - reply->writeInt32( isStreamActive((audio_stream_type_t) stream, inPastMs) ); + reply->writeInt32( isStreamActive(stream, inPastMs) ); return NO_ERROR; } break; @@ -641,7 +643,7 @@ status_t BnAudioPolicyService::onTransact( CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_stream_type_t stream = (audio_stream_type_t) data.readInt32(); uint32_t inPastMs = (uint32_t)data.readInt32(); - reply->writeInt32( isStreamActiveRemotely((audio_stream_type_t) stream, inPastMs) ); + reply->writeInt32( isStreamActiveRemotely(stream, inPastMs) ); return NO_ERROR; } break; -- cgit v1.1 From ac3e9db88ddb1f24bc6c8fb744a37dfdeec332bb Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 6 Mar 2014 08:00:31 -0800 Subject: Add mFrameSize but do not remove mFrameBitShift yet Change-Id: Icb1edefeb6a0e659503f6b7a92c9d15784df9865 --- media/libnbaio/AudioStreamInSource.cpp | 1 + media/libnbaio/AudioStreamOutSink.cpp | 1 + media/libnbaio/SourceAudioBufferProvider.cpp | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp index ae8fac8..ca7b8e0 100644 --- a/media/libnbaio/AudioStreamInSource.cpp +++ b/media/libnbaio/AudioStreamInSource.cpp @@ -49,6 +49,7 @@ ssize_t AudioStreamInSource::negotiate(const NBAIO_Format offers[], size_t numOf (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); mFormat = Format_from_SR_C(sampleRate, popcount(channelMask)); mBitShift = Format_frameBitShift(mFormat); + mFrameSize = Format_frameSize(mFormat); } } return NBAIO_Source::negotiate(offers, numOffers, counterOffers, numCounterOffers); diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp index aa9810e..5158f01 100644 --- a/media/libnbaio/AudioStreamOutSink.cpp +++ b/media/libnbaio/AudioStreamOutSink.cpp @@ -46,6 +46,7 @@ ssize_t AudioStreamOutSink::negotiate(const NBAIO_Format offers[], size_t numOff (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); mFormat = Format_from_SR_C(sampleRate, popcount(channelMask)); mBitShift = Format_frameBitShift(mFormat); + mFrameSize = Format_frameSize(mFormat); } } return NBAIO_Sink::negotiate(offers, numOffers, counterOffers, numCounterOffers); diff --git a/media/libnbaio/SourceAudioBufferProvider.cpp b/media/libnbaio/SourceAudioBufferProvider.cpp index 062fa0f..0e77795 100644 --- a/media/libnbaio/SourceAudioBufferProvider.cpp +++ b/media/libnbaio/SourceAudioBufferProvider.cpp @@ -24,7 +24,7 @@ namespace android { SourceAudioBufferProvider::SourceAudioBufferProvider(const sp& source) : mSource(source), - // mFrameBitShiftFormat below + // mFrameSize below mAllocated(NULL), mSize(0), mOffset(0), mRemaining(0), mGetCount(0), mFramesReleased(0) { ALOG_ASSERT(source != 0); @@ -38,6 +38,7 @@ SourceAudioBufferProvider::SourceAudioBufferProvider(const sp& sou index = source->negotiate(counterOffers, 1, NULL, numCounterOffers); ALOG_ASSERT(index == 0); mFrameBitShift = Format_frameBitShift(source->format()); + mFrameSize = Format_frameSize(source->format()); } SourceAudioBufferProvider::~SourceAudioBufferProvider() -- cgit v1.1 From 4d693d6b8cc1283f92f5301daf19a07abc772a2b Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 6 Mar 2014 07:53:11 -0800 Subject: Use mFrameSize instead of mBitShift Change-Id: Idac335ae70cc9300bb3325839fe8ef1e9e097245 --- media/libnbaio/AudioBufferProviderSource.cpp | 4 ++-- media/libnbaio/AudioStreamInSource.cpp | 4 ++-- media/libnbaio/AudioStreamOutSink.cpp | 4 ++-- media/libnbaio/MonoPipe.cpp | 6 +++--- media/libnbaio/MonoPipeReader.cpp | 4 ++-- media/libnbaio/Pipe.cpp | 4 ++-- media/libnbaio/PipeReader.cpp | 4 ++-- media/libnbaio/SourceAudioBufferProvider.cpp | 6 +++--- 8 files changed, 18 insertions(+), 18 deletions(-) (limited to 'media') diff --git a/media/libnbaio/AudioBufferProviderSource.cpp b/media/libnbaio/AudioBufferProviderSource.cpp index 4a69104..551f516 100644 --- a/media/libnbaio/AudioBufferProviderSource.cpp +++ b/media/libnbaio/AudioBufferProviderSource.cpp @@ -68,7 +68,7 @@ ssize_t AudioBufferProviderSource::read(void *buffer, } // count could be zero, either because count was zero on entry or // available is zero, but both are unlikely so don't check for that - memcpy(buffer, (char *) mBuffer.raw + (mConsumed << mBitShift), count << mBitShift); + memcpy(buffer, (char *) mBuffer.raw + (mConsumed * mFrameSize), count * mFrameSize); if (CC_UNLIKELY((mConsumed += count) >= mBuffer.frameCount)) { mProvider->releaseBuffer(&mBuffer); mBuffer.raw = NULL; @@ -120,7 +120,7 @@ ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *us count = available; } if (CC_LIKELY(count > 0)) { - char* readTgt = (char *) mBuffer.raw + (mConsumed << mBitShift); + char* readTgt = (char *) mBuffer.raw + (mConsumed * mFrameSize); ssize_t ret = via(user, readTgt, count, readPTS); if (CC_UNLIKELY(ret <= 0)) { if (CC_LIKELY(accumulator > 0)) { diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp index ca7b8e0..e2f4943 100644 --- a/media/libnbaio/AudioStreamInSource.cpp +++ b/media/libnbaio/AudioStreamInSource.cpp @@ -71,9 +71,9 @@ ssize_t AudioStreamInSource::read(void *buffer, size_t count) if (CC_UNLIKELY(!Format_isValid(mFormat))) { return NEGOTIATE; } - ssize_t bytesRead = mStream->read(mStream, buffer, count << mBitShift); + ssize_t bytesRead = mStream->read(mStream, buffer, count * mFrameSize); if (bytesRead > 0) { - size_t framesRead = bytesRead >> mBitShift; + size_t framesRead = bytesRead / mFrameSize; mFramesRead += framesRead; return framesRead; } else { diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp index 5158f01..442455b 100644 --- a/media/libnbaio/AudioStreamOutSink.cpp +++ b/media/libnbaio/AudioStreamOutSink.cpp @@ -58,9 +58,9 @@ ssize_t AudioStreamOutSink::write(const void *buffer, size_t count) return NEGOTIATE; } ALOG_ASSERT(Format_isValid(mFormat)); - ssize_t ret = mStream->write(mStream, buffer, count << mBitShift); + ssize_t ret = mStream->write(mStream, buffer, count * mFrameSize); if (ret > 0) { - ret >>= mBitShift; + ret /= mFrameSize; mFramesWritten += ret; } else { // FIXME verify HAL implementations are returning the correct error codes e.g. WOULD_BLOCK diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp index b23967b..9c8461c 100644 --- a/media/libnbaio/MonoPipe.cpp +++ b/media/libnbaio/MonoPipe.cpp @@ -115,11 +115,11 @@ ssize_t MonoPipe::write(const void *buffer, size_t count) part1 = written; } if (CC_LIKELY(part1 > 0)) { - memcpy((char *) mBuffer + (rear << mBitShift), buffer, part1 << mBitShift); + memcpy((char *) mBuffer + (rear * mFrameSize), buffer, part1 * mFrameSize); if (CC_UNLIKELY(rear + part1 == mMaxFrames)) { size_t part2 = written - part1; if (CC_LIKELY(part2 > 0)) { - memcpy(mBuffer, (char *) buffer + (part1 << mBitShift), part2 << mBitShift); + memcpy(mBuffer, (char *) buffer + (part1 * mFrameSize), part2 * mFrameSize); } } android_atomic_release_store(written + mRear, &mRear); @@ -129,7 +129,7 @@ ssize_t MonoPipe::write(const void *buffer, size_t count) break; } count -= written; - buffer = (char *) buffer + (written << mBitShift); + buffer = (char *) buffer + (written * mFrameSize); // Simulate blocking I/O by sleeping at different rates, depending on a throttle. // The throttle tries to keep the mean pipe depth near the setpoint, with a slight jitter. uint32_t ns; diff --git a/media/libnbaio/MonoPipeReader.cpp b/media/libnbaio/MonoPipeReader.cpp index 851341a..de82229 100644 --- a/media/libnbaio/MonoPipeReader.cpp +++ b/media/libnbaio/MonoPipeReader.cpp @@ -73,11 +73,11 @@ ssize_t MonoPipeReader::read(void *buffer, size_t count, int64_t readPTS) part1 = red; } if (CC_LIKELY(part1 > 0)) { - memcpy(buffer, (char *) mPipe->mBuffer + (front << mBitShift), part1 << mBitShift); + memcpy(buffer, (char *) mPipe->mBuffer + (front * mFrameSize), part1 * mFrameSize); if (CC_UNLIKELY(front + part1 == mPipe->mMaxFrames)) { size_t part2 = red - part1; if (CC_LIKELY(part2 > 0)) { - memcpy((char *) buffer + (part1 << mBitShift), mPipe->mBuffer, part2 << mBitShift); + memcpy((char *) buffer + (part1 * mFrameSize), mPipe->mBuffer, part2 * mFrameSize); } } mPipe->updateFrontAndNRPTS(red + mPipe->mFront, nextReadPTS); diff --git a/media/libnbaio/Pipe.cpp b/media/libnbaio/Pipe.cpp index 115f311..28a034c 100644 --- a/media/libnbaio/Pipe.cpp +++ b/media/libnbaio/Pipe.cpp @@ -52,13 +52,13 @@ ssize_t Pipe::write(const void *buffer, size_t count) if (CC_LIKELY(written > count)) { written = count; } - memcpy((char *) mBuffer + (rear << mBitShift), buffer, written << mBitShift); + memcpy((char *) mBuffer + (rear * mFrameSize), buffer, written * mFrameSize); if (CC_UNLIKELY(rear + written == mMaxFrames)) { if (CC_UNLIKELY((count -= written) > rear)) { count = rear; } if (CC_LIKELY(count > 0)) { - memcpy(mBuffer, (char *) buffer + (written << mBitShift), count << mBitShift); + memcpy(mBuffer, (char *) buffer + (written * mFrameSize), count * mFrameSize); written += count; } } diff --git a/media/libnbaio/PipeReader.cpp b/media/libnbaio/PipeReader.cpp index 24da1bd..c8e4953 100644 --- a/media/libnbaio/PipeReader.cpp +++ b/media/libnbaio/PipeReader.cpp @@ -76,14 +76,14 @@ ssize_t PipeReader::read(void *buffer, size_t count, int64_t readPTS __unused) red = count; } // In particular, an overrun during the memcpy will result in reading corrupt data - memcpy(buffer, (char *) mPipe.mBuffer + (front << mBitShift), red << mBitShift); + memcpy(buffer, (char *) mPipe.mBuffer + (front * mFrameSize), red * mFrameSize); // We could re-read the rear pointer here to detect the corruption, but why bother? if (CC_UNLIKELY(front + red == mPipe.mMaxFrames)) { if (CC_UNLIKELY((count -= red) > front)) { count = front; } if (CC_LIKELY(count > 0)) { - memcpy((char *) buffer + (red << mBitShift), mPipe.mBuffer, count << mBitShift); + memcpy((char *) buffer + (red * mFrameSize), mPipe.mBuffer, count * mFrameSize); red += count; } } diff --git a/media/libnbaio/SourceAudioBufferProvider.cpp b/media/libnbaio/SourceAudioBufferProvider.cpp index 0e77795..791fe7c 100644 --- a/media/libnbaio/SourceAudioBufferProvider.cpp +++ b/media/libnbaio/SourceAudioBufferProvider.cpp @@ -55,14 +55,14 @@ status_t SourceAudioBufferProvider::getNextBuffer(Buffer *buffer, int64_t pts) if (mRemaining < buffer->frameCount) { buffer->frameCount = mRemaining; } - buffer->raw = (char *) mAllocated + (mOffset << mFrameBitShift); + buffer->raw = (char *) mAllocated + (mOffset * mFrameSize); mGetCount = buffer->frameCount; return OK; } // do we need to reallocate? if (buffer->frameCount > mSize) { free(mAllocated); - mAllocated = malloc(buffer->frameCount << mFrameBitShift); + mAllocated = malloc(buffer->frameCount * mFrameSize); mSize = buffer->frameCount; } // read from source @@ -85,7 +85,7 @@ status_t SourceAudioBufferProvider::getNextBuffer(Buffer *buffer, int64_t pts) void SourceAudioBufferProvider::releaseBuffer(Buffer *buffer) { ALOG_ASSERT((buffer != NULL) && - (buffer->raw == (char *) mAllocated + (mOffset << mFrameBitShift)) && + (buffer->raw == (char *) mAllocated + (mOffset * mFrameSize)) && (buffer->frameCount <= mGetCount) && (mGetCount <= mRemaining) && (mOffset + mRemaining <= mSize)); -- cgit v1.1 From f95a3c4122d67273d930c7d83c3df99f136603ed Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 6 Mar 2014 07:59:49 -0800 Subject: Add format parameter to Format_from_SR_C Change-Id: I891138b7754342fe2a4f02de30ee616dbd078474 --- media/libnbaio/NBAIO.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index 51514de..a15d41c 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -98,7 +98,8 @@ unsigned Format_channelCount(const NBAIO_Format& format) } } -NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount) +NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount, + audio_format_t format_ __unused) { unsigned format; switch (sampleRate) { -- cgit v1.1 From 2b7b910f4b417ab3930379298f538d0dfc857e88 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 6 Mar 2014 08:02:51 -0800 Subject: Split mPacked into 4 separate fields Change-Id: I940324dce9b51fd8d7e2e362e12ad74b70e658dd --- media/libnbaio/NBAIO.cpp | 85 +++++++++--------------------------------------- 1 file changed, 15 insertions(+), 70 deletions(-) (limited to 'media') diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index a15d41c..cfcd8b4 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -36,7 +36,7 @@ int Format_frameBitShift(const NBAIO_Format& format) // FIXME must return -1 for non-power of 2 } -const NBAIO_Format Format_Invalid = { 0 }; +const NBAIO_Format Format_Invalid = { 0, 0, AUDIO_FORMAT_INVALID, 0 }; enum { Format_SR_8000, @@ -61,26 +61,7 @@ unsigned Format_sampleRate(const NBAIO_Format& format) if (!Format_isValid(format)) { return 0; } - switch (format.mPacked & Format_SR_Mask) { - case Format_SR_8000: - return 8000; - case Format_SR_11025: - return 11025; - case Format_SR_16000: - return 16000; - case Format_SR_22050: - return 22050; - case Format_SR_24000: - return 24000; - case Format_SR_32000: - return 32000; - case Format_SR_44100: - return 44100; - case Format_SR_48000: - return 48000; - default: - return 0; - } + return format.mSampleRate; } unsigned Format_channelCount(const NBAIO_Format& format) @@ -88,60 +69,21 @@ unsigned Format_channelCount(const NBAIO_Format& format) if (!Format_isValid(format)) { return 0; } - switch (format.mPacked & Format_C_Mask) { - case Format_C_1: - return 1; - case Format_C_2: - return 2; - default: - return 0; - } + return format.mChannelCount; } NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount, - audio_format_t format_ __unused) + audio_format_t format) { - unsigned format; - switch (sampleRate) { - case 8000: - format = Format_SR_8000; - break; - case 11025: - format = Format_SR_11025; - break; - case 16000: - format = Format_SR_16000; - break; - case 22050: - format = Format_SR_22050; - break; - case 24000: - format = Format_SR_24000; - break; - case 32000: - format = Format_SR_32000; - break; - case 44100: - format = Format_SR_44100; - break; - case 48000: - format = Format_SR_48000; - break; - default: - return Format_Invalid; - } - switch (channelCount) { - case 1: - format |= Format_C_1; - break; - case 2: - format |= Format_C_2; - break; - default: + if (sampleRate == 0 || channelCount == 0 || !audio_is_valid_format(format)) { return Format_Invalid; } NBAIO_Format ret; - ret.mPacked = format; + ret.mSampleRate = sampleRate; + ret.mChannelCount = channelCount; + ret.mFormat = format; + ret.mFrameSize = audio_is_linear_pcm(format) ? + channelCount * audio_bytes_per_sample(format) : sizeof(uint8_t); return ret; } @@ -243,12 +185,15 @@ ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers, bool Format_isValid(const NBAIO_Format& format) { - return format.mPacked != Format_Invalid.mPacked; + return format.mSampleRate != 0 && format.mChannelCount != 0 && + format.mFormat != AUDIO_FORMAT_INVALID && format.mFrameSize != 0; } bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2) { - return format1.mPacked == format2.mPacked; + return format1.mSampleRate == format2.mSampleRate && + format1.mChannelCount == format2.mChannelCount && format1.mFormat == format2.mFormat && + format1.mFrameSize == format2.mFrameSize; } } // namespace android -- cgit v1.1 From 983f0578ccd2928af40c9689f6fe90110d02b92e Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 6 Mar 2014 08:23:11 -0800 Subject: Re-implement Format_frameSize(), to support non-power-of-2 Change-Id: I671bd4f03ce70de685770fd7992e2e023133c9b4 --- media/libnbaio/NBAIO.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'media') diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index cfcd8b4..16e7df5 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -24,8 +24,7 @@ namespace android { size_t Format_frameSize(const NBAIO_Format& format) { - // FIXME The sample format is hard-coded to AUDIO_FORMAT_PCM_16_BIT - return Format_channelCount(format) * sizeof(short); + return format.mFrameSize; } int Format_frameBitShift(const NBAIO_Format& format) -- cgit v1.1 From c326e1c3d122917462f1cda4f03d9c639ad92902 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 6 Mar 2014 08:01:38 -0800 Subject: Remove Format_frameBitShift() Change-Id: Iae2e80a7330c5dd0f70a263051aa44c23cfe3541 --- media/libnbaio/AudioStreamInSource.cpp | 1 - media/libnbaio/AudioStreamOutSink.cpp | 1 - media/libnbaio/NBAIO.cpp | 2 ++ media/libnbaio/SourceAudioBufferProvider.cpp | 1 - 4 files changed, 2 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp index e2f4943..efbc1a7 100644 --- a/media/libnbaio/AudioStreamInSource.cpp +++ b/media/libnbaio/AudioStreamInSource.cpp @@ -48,7 +48,6 @@ ssize_t AudioStreamInSource::negotiate(const NBAIO_Format offers[], size_t numOf audio_channel_mask_t channelMask = (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); mFormat = Format_from_SR_C(sampleRate, popcount(channelMask)); - mBitShift = Format_frameBitShift(mFormat); mFrameSize = Format_frameSize(mFormat); } } diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp index 442455b..f7f764e 100644 --- a/media/libnbaio/AudioStreamOutSink.cpp +++ b/media/libnbaio/AudioStreamOutSink.cpp @@ -45,7 +45,6 @@ ssize_t AudioStreamOutSink::negotiate(const NBAIO_Format offers[], size_t numOff audio_channel_mask_t channelMask = (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); mFormat = Format_from_SR_C(sampleRate, popcount(channelMask)); - mBitShift = Format_frameBitShift(mFormat); mFrameSize = Format_frameSize(mFormat); } } diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index 16e7df5..4f6591d 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -27,6 +27,7 @@ size_t Format_frameSize(const NBAIO_Format& format) return format.mFrameSize; } +#if 0 int Format_frameBitShift(const NBAIO_Format& format) { // FIXME The sample format is hard-coded to AUDIO_FORMAT_PCM_16_BIT @@ -34,6 +35,7 @@ int Format_frameBitShift(const NBAIO_Format& format) return Format_channelCount(format); // FIXME must return -1 for non-power of 2 } +#endif const NBAIO_Format Format_Invalid = { 0, 0, AUDIO_FORMAT_INVALID, 0 }; diff --git a/media/libnbaio/SourceAudioBufferProvider.cpp b/media/libnbaio/SourceAudioBufferProvider.cpp index 791fe7c..e21ef48 100644 --- a/media/libnbaio/SourceAudioBufferProvider.cpp +++ b/media/libnbaio/SourceAudioBufferProvider.cpp @@ -37,7 +37,6 @@ SourceAudioBufferProvider::SourceAudioBufferProvider(const sp& sou numCounterOffers = 0; index = source->negotiate(counterOffers, 1, NULL, numCounterOffers); ALOG_ASSERT(index == 0); - mFrameBitShift = Format_frameBitShift(source->format()); mFrameSize = Format_frameSize(source->format()); } -- cgit v1.1 From 43d9b8706b3916ee0f1d745a2832f792c3406ca8 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 6 Mar 2014 09:03:34 -0800 Subject: Remove restriction for HAL streams of AUDIO_FORMAT_PCM_16_BIT Change-Id: I6b89a3ac4b77b9a5a84e3b623987186c3d2db89d --- media/libnbaio/AudioStreamInSource.cpp | 12 +++++------- media/libnbaio/AudioStreamOutSink.cpp | 12 +++++------- 2 files changed, 10 insertions(+), 14 deletions(-) (limited to 'media') diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp index efbc1a7..cee90dd 100644 --- a/media/libnbaio/AudioStreamInSource.cpp +++ b/media/libnbaio/AudioStreamInSource.cpp @@ -43,13 +43,11 @@ ssize_t AudioStreamInSource::negotiate(const NBAIO_Format offers[], size_t numOf if (!Format_isValid(mFormat)) { mStreamBufferSizeBytes = mStream->common.get_buffer_size(&mStream->common); audio_format_t streamFormat = mStream->common.get_format(&mStream->common); - if (streamFormat == AUDIO_FORMAT_PCM_16_BIT) { - uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common); - audio_channel_mask_t channelMask = - (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); - mFormat = Format_from_SR_C(sampleRate, popcount(channelMask)); - mFrameSize = Format_frameSize(mFormat); - } + uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common); + audio_channel_mask_t channelMask = + (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); + mFormat = Format_from_SR_C(sampleRate, popcount(channelMask)); + mFrameSize = Format_frameSize(mFormat); } return NBAIO_Source::negotiate(offers, numOffers, counterOffers, numCounterOffers); } diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp index f7f764e..bff06f3 100644 --- a/media/libnbaio/AudioStreamOutSink.cpp +++ b/media/libnbaio/AudioStreamOutSink.cpp @@ -40,13 +40,11 @@ ssize_t AudioStreamOutSink::negotiate(const NBAIO_Format offers[], size_t numOff if (!Format_isValid(mFormat)) { mStreamBufferSizeBytes = mStream->common.get_buffer_size(&mStream->common); audio_format_t streamFormat = mStream->common.get_format(&mStream->common); - if (streamFormat == AUDIO_FORMAT_PCM_16_BIT) { - uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common); - audio_channel_mask_t channelMask = - (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); - mFormat = Format_from_SR_C(sampleRate, popcount(channelMask)); - mFrameSize = Format_frameSize(mFormat); - } + uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common); + audio_channel_mask_t channelMask = + (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); + mFormat = Format_from_SR_C(sampleRate, popcount(channelMask)); + mFrameSize = Format_frameSize(mFormat); } return NBAIO_Sink::negotiate(offers, numOffers, counterOffers, numCounterOffers); } -- cgit v1.1 From d42bc56e5883274edf1f0b45cad5c324eceff9b8 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 6 Mar 2014 08:02:27 -0800 Subject: Remove checks for specific sample rates and channel counts Change-Id: Idadfe7c11dc831e82f95015f02dd9b9861b401c8 --- media/libnbaio/NBAIO.cpp | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'media') diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index 4f6591d..a669fbb 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -39,24 +39,6 @@ int Format_frameBitShift(const NBAIO_Format& format) const NBAIO_Format Format_Invalid = { 0, 0, AUDIO_FORMAT_INVALID, 0 }; -enum { - Format_SR_8000, - Format_SR_11025, - Format_SR_16000, - Format_SR_22050, - Format_SR_24000, - Format_SR_32000, - Format_SR_44100, - Format_SR_48000, - Format_SR_Mask = 7 -}; - -enum { - Format_C_1 = 0x08, - Format_C_2 = 0x10, - Format_C_Mask = 0x18 -}; - unsigned Format_sampleRate(const NBAIO_Format& format) { if (!Format_isValid(format)) { -- cgit v1.1 From 7064fd2dcdfeafea53cd5a992bb78c413542f29f Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Wed, 8 Jan 2014 13:59:53 -0800 Subject: AudioTrack: When paused, return cached playback position An offload output can be re-used between two audio tracks having the same configuration. A timestamp query for a paused track while the other is running would return an incorrect time. To fix this, cache the playback position on a pause() and return this time when requested until the track is resumed. Bug: 12826612. Change-Id: I324112ea9827e52fff53ef44cd8513c8d85a0bc4 --- media/libmedia/AudioTrack.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index d25c40b..f353fac 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -99,7 +99,8 @@ AudioTrack::AudioTrack() : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), - mPreviousSchedulingGroup(SP_DEFAULT) + mPreviousSchedulingGroup(SP_DEFAULT), + mPausedPosition(0) { } @@ -121,7 +122,8 @@ AudioTrack::AudioTrack( : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), - mPreviousSchedulingGroup(SP_DEFAULT) + mPreviousSchedulingGroup(SP_DEFAULT), + mPausedPosition(0) { mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, @@ -147,7 +149,8 @@ AudioTrack::AudioTrack( : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), - mPreviousSchedulingGroup(SP_DEFAULT) + mPreviousSchedulingGroup(SP_DEFAULT), + mPausedPosition(0) { mStatus = set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags, cbf, user, notificationFrames, @@ -551,6 +554,16 @@ void AudioTrack::pause() } mProxy->interrupt(); mAudioTrack->pause(); + + if (isOffloaded()) { + if (mOutput != 0) { + uint32_t halFrames; + // OffloadThread sends HAL pause in its threadLoop.. time saved + // here can be slightly off + AudioSystem::getRenderPosition(mOutput, &halFrames, &mPausedPosition); + ALOGV("AudioTrack::pause for offload, cache current position %u", mPausedPosition); + } + } } status_t AudioTrack::setVolume(float left, float right) @@ -770,6 +783,12 @@ status_t AudioTrack::getPosition(uint32_t *position) const if (isOffloaded_l()) { uint32_t dspFrames = 0; + if ((mState == STATE_PAUSED) || (mState == STATE_PAUSED_STOPPING)) { + ALOGV("getPosition called in paused state, return cached position %u", mPausedPosition); + *position = mPausedPosition; + return NO_ERROR; + } + if (mOutput != 0) { uint32_t halFrames; AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames); -- cgit v1.1 From 343947abc8b7c126f966fd32a0b18bff6c2cecd1 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 7 Feb 2014 16:59:35 -0800 Subject: Stagefright: added WebM muxer. Change-Id: I50bbf9c6f089b205d5ecef1371bfdd2028b3b358 --- media/libstagefright/Android.mk | 1 + media/libstagefright/MediaMuxer.cpp | 27 +- media/libstagefright/webm/Android.mk | 23 + media/libstagefright/webm/EbmlUtil.cpp | 108 +++++ media/libstagefright/webm/EbmlUtil.h | 50 +++ media/libstagefright/webm/LinkedBlockingQueue.h | 79 ++++ media/libstagefright/webm/WebmConstants.h | 133 ++++++ media/libstagefright/webm/WebmElement.cpp | 367 ++++++++++++++++ media/libstagefright/webm/WebmElement.h | 127 ++++++ media/libstagefright/webm/WebmFrame.cpp | 83 ++++ media/libstagefright/webm/WebmFrame.h | 46 ++ media/libstagefright/webm/WebmFrameThread.cpp | 399 +++++++++++++++++ media/libstagefright/webm/WebmFrameThread.h | 160 +++++++ media/libstagefright/webm/WebmWriter.cpp | 551 ++++++++++++++++++++++++ media/libstagefright/webm/WebmWriter.h | 130 ++++++ 15 files changed, 2280 insertions(+), 4 deletions(-) create mode 100644 media/libstagefright/webm/Android.mk create mode 100644 media/libstagefright/webm/EbmlUtil.cpp create mode 100644 media/libstagefright/webm/EbmlUtil.h create mode 100644 media/libstagefright/webm/LinkedBlockingQueue.h create mode 100644 media/libstagefright/webm/WebmConstants.h create mode 100644 media/libstagefright/webm/WebmElement.cpp create mode 100644 media/libstagefright/webm/WebmElement.h create mode 100644 media/libstagefright/webm/WebmFrame.cpp create mode 100644 media/libstagefright/webm/WebmFrame.h create mode 100644 media/libstagefright/webm/WebmFrameThread.cpp create mode 100644 media/libstagefright/webm/WebmFrameThread.h create mode 100644 media/libstagefright/webm/WebmWriter.cpp create mode 100644 media/libstagefright/webm/WebmWriter.h (limited to 'media') diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 0fd1e69..714b5e0 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -97,6 +97,7 @@ LOCAL_STATIC_LIBRARIES := \ libstagefright_color_conversion \ libstagefright_aacenc \ libstagefright_matroska \ + libstagefright_webm \ libstagefright_timedtext \ libvpx \ libwebm \ diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp index d87e910..90335ee 100644 --- a/media/libstagefright/MediaMuxer.cpp +++ b/media/libstagefright/MediaMuxer.cpp @@ -16,6 +16,9 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaMuxer" + +#include "webm/WebmWriter.h" + #include #include @@ -36,19 +39,30 @@ namespace android { MediaMuxer::MediaMuxer(const char *path, OutputFormat format) - : mState(UNINITIALIZED) { + : mFormat(format), + mState(UNINITIALIZED) { if (format == OUTPUT_FORMAT_MPEG_4) { mWriter = new MPEG4Writer(path); + } else if (format == OUTPUT_FORMAT_WEBM) { + mWriter = new WebmWriter(path); + } + + if (mWriter != NULL) { mFileMeta = new MetaData; mState = INITIALIZED; } - } MediaMuxer::MediaMuxer(int fd, OutputFormat format) - : mState(UNINITIALIZED) { + : mFormat(format), + mState(UNINITIALIZED) { if (format == OUTPUT_FORMAT_MPEG_4) { mWriter = new MPEG4Writer(fd); + } else if (format == OUTPUT_FORMAT_WEBM) { + mWriter = new WebmWriter(fd); + } + + if (mWriter != NULL) { mFileMeta = new MetaData; mState = INITIALIZED; } @@ -109,8 +123,13 @@ status_t MediaMuxer::setLocation(int latitude, int longitude) { ALOGE("setLocation() must be called before start()."); return INVALID_OPERATION; } + if (mFormat != OUTPUT_FORMAT_MPEG_4) { + ALOGE("setLocation() is only supported for .mp4 output."); + return INVALID_OPERATION; + } + ALOGV("Setting location: latitude = %d, longitude = %d", latitude, longitude); - return mWriter->setGeoData(latitude, longitude); + return static_cast(mWriter.get())->setGeoData(latitude, longitude); } status_t MediaMuxer::start() { diff --git a/media/libstagefright/webm/Android.mk b/media/libstagefright/webm/Android.mk new file mode 100644 index 0000000..7081463 --- /dev/null +++ b/media/libstagefright/webm/Android.mk @@ -0,0 +1,23 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_CPPFLAGS += -D__STDINT_LIMITS \ + -Werror + +LOCAL_SRC_FILES:= EbmlUtil.cpp \ + WebmElement.cpp \ + WebmFrame.cpp \ + WebmFrameThread.cpp \ + WebmWriter.cpp + + +LOCAL_C_INCLUDES += $(TOP)/frameworks/av/include + +LOCAL_SHARED_LIBRARIES += libstagefright_foundation \ + libstagefright \ + libutils \ + liblog + +LOCAL_MODULE:= libstagefright_webm + +include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/webm/EbmlUtil.cpp b/media/libstagefright/webm/EbmlUtil.cpp new file mode 100644 index 0000000..449fec6 --- /dev/null +++ b/media/libstagefright/webm/EbmlUtil.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2014 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 + +namespace { + +// Table for Seal's algorithm for Number of Trailing Zeros. Hacker's Delight +// online, Figure 5-18 (http://www.hackersdelight.org/revisions.pdf) +// The entries whose value is -1 are never referenced. +int NTZ_TABLE[] = { + 32, 0, 1, 12, 2, 6, -1, 13, 3, -1, 7, -1, -1, -1, -1, 14, + 10, 4, -1, -1, 8, -1, -1, 25, -1, -1, -1, -1, -1, 21, 27, 15, + 31, 11, 5, -1, -1, -1, -1, -1, 9, -1, -1, 24, -1, -1, 20, 26, + 30, -1, -1, -1, -1, 23, -1, 19, 29, -1, 22, 18, 28, 17, 16, -1 +}; + +int numberOfTrailingZeros32(int32_t i) { + uint32_t u = (i & -i) * 0x0450FBAF; + return NTZ_TABLE[(u) >> 26]; +} + +uint64_t highestOneBit(uint64_t n) { + n |= (n >> 1); + n |= (n >> 2); + n |= (n >> 4); + n |= (n >> 8); + n |= (n >> 16); + n |= (n >> 32); + return n - (n >> 1); +} + +uint64_t _powerOf2(uint64_t u) { + uint64_t powerOf2 = highestOneBit(u); + return powerOf2 ? powerOf2 : 1; +} + +// Based on Long.numberOfTrailingZeros in Long.java +int numberOfTrailingZeros(uint64_t u) { + int32_t low = u; + return low !=0 ? numberOfTrailingZeros32(low) + : 32 + numberOfTrailingZeros32((int32_t) (u >> 32)); +} +} + +namespace webm { + +// Encode the id and/or size of an EBML element bytes by setting a leading length descriptor bit: +// +// 1xxxxxxx - 1-byte values +// 01xxxxxx xxxxxxxx - +// 001xxxxx xxxxxxxx xxxxxxxx - +// 0001xxxx xxxxxxxx xxxxxxxx xxxxxxxx - ... +// 00001xxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - +// 000001xx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - +// 0000001x xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - +// 00000001 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - 8-byte values +// +// This function uses the least the number of bytes possible. +uint64_t encodeUnsigned(uint64_t u) { + uint64_t powerOf2 = _powerOf2(u); + if (u + 1 == powerOf2 << 1) + powerOf2 <<= 1; + int shiftWidth = (7 + numberOfTrailingZeros(powerOf2)) / 7 * 7; + long lengthDescriptor = 1 << shiftWidth; + return lengthDescriptor | u; +} + +// Like above but pads the input value with leading zeros up to the specified width. The length +// descriptor is calculated based on width. +uint64_t encodeUnsigned(uint64_t u, int width) { + int shiftWidth = 7 * width; + uint64_t lengthDescriptor = 1; + lengthDescriptor <<= shiftWidth; + return lengthDescriptor | u; +} + +// Calculate the length of an EBML coded id or size from its length descriptor. +int sizeOf(uint64_t u) { + uint64_t powerOf2 = _powerOf2(u); + int unsignedLength = numberOfTrailingZeros(powerOf2) / 8 + 1; + return unsignedLength; +} + +// Serialize an EBML coded id or size in big-endian order. +int serializeCodedUnsigned(uint64_t u, uint8_t* bary) { + int unsignedLength = sizeOf(u); + for (int i = unsignedLength - 1; i >= 0; i--) { + bary[i] = u & 0xff; + u >>= 8; + } + return unsignedLength; +} + +} diff --git a/media/libstagefright/webm/EbmlUtil.h b/media/libstagefright/webm/EbmlUtil.h new file mode 100644 index 0000000..eb9c37c --- /dev/null +++ b/media/libstagefright/webm/EbmlUtil.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014 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 EBMLUTIL_H_ +#define EBMLUTIL_H_ + +#include + +namespace webm { + +// Encode the id and/or size of an EBML element bytes by setting a leading length descriptor bit: +// +// 1xxxxxxx - 1-byte values +// 01xxxxxx xxxxxxxx - +// 001xxxxx xxxxxxxx xxxxxxxx - +// 0001xxxx xxxxxxxx xxxxxxxx xxxxxxxx - ... +// 00001xxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - +// 000001xx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - +// 0000001x xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - +// 00000001 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - 8-byte values +// +// This function uses the least the number of bytes possible. +uint64_t encodeUnsigned(uint64_t u); + +// Like above but pads the input value with leading zeros up to the specified width. The length +// descriptor is calculated based on width. +uint64_t encodeUnsigned(uint64_t u, int width); + +// Serialize an EBML coded id or size in big-endian order. +int serializeCodedUnsigned(uint64_t u, uint8_t* bary); + +// Calculate the length of an EBML coded id or size from its length descriptor. +int sizeOf(uint64_t u); + +} + +#endif /* EBMLUTIL_H_ */ diff --git a/media/libstagefright/webm/LinkedBlockingQueue.h b/media/libstagefright/webm/LinkedBlockingQueue.h new file mode 100644 index 0000000..0b6a9a1 --- /dev/null +++ b/media/libstagefright/webm/LinkedBlockingQueue.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014 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 LINKEDBLOCKINGQUEUE_H_ +#define LINKEDBLOCKINGQUEUE_H_ + +#include +#include +#include + +namespace android { + +template +class LinkedBlockingQueue { + List mList; + Mutex mLock; + Condition mContentAvailableCondition; + + T front(bool remove) { + Mutex::Autolock autolock(mLock); + while (mList.empty()) { + mContentAvailableCondition.wait(mLock); + } + T e = *(mList.begin()); + if (remove) { + mList.erase(mList.begin()); + } + return e; + } + + DISALLOW_EVIL_CONSTRUCTORS(LinkedBlockingQueue); + +public: + LinkedBlockingQueue() { + } + + ~LinkedBlockingQueue() { + } + + bool empty() { + Mutex::Autolock autolock(mLock); + return mList.empty(); + } + + void clear() { + Mutex::Autolock autolock(mLock); + mList.clear(); + } + + T peek() { + return front(false); + } + + T take() { + return front(true); + } + + void push(T e) { + Mutex::Autolock autolock(mLock); + mList.push_back(e); + mContentAvailableCondition.signal(); + } +}; + +} /* namespace android */ +#endif /* LINKEDBLOCKINGQUEUE_H_ */ diff --git a/media/libstagefright/webm/WebmConstants.h b/media/libstagefright/webm/WebmConstants.h new file mode 100644 index 0000000..c53f458 --- /dev/null +++ b/media/libstagefright/webm/WebmConstants.h @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2014 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 WEBMCONSTANTS_H_ +#define WEBMCONSTANTS_H_ + +#include + +namespace webm { + +const int kMinEbmlVoidSize = 2; +const int64_t kMaxMetaSeekSize = 64; +const int64_t kMkvUnknownLength = 0x01ffffffffffffffl; + +// EBML element id's from http://matroska.org/technical/specs/index.html +enum Mkv { + kMkvEbml = 0x1A45DFA3, + kMkvEbmlVersion = 0x4286, + kMkvEbmlReadVersion = 0x42F7, + kMkvEbmlMaxIdlength = 0x42F2, + kMkvEbmlMaxSizeLength = 0x42F3, + kMkvDocType = 0x4282, + kMkvDocTypeVersion = 0x4287, + kMkvDocTypeReadVersion = 0x4285, + kMkvVoid = 0xEC, + kMkvSignatureSlot = 0x1B538667, + kMkvSignatureAlgo = 0x7E8A, + kMkvSignatureHash = 0x7E9A, + kMkvSignaturePublicKey = 0x7EA5, + kMkvSignature = 0x7EB5, + kMkvSignatureElements = 0x7E5B, + kMkvSignatureElementList = 0x7E7B, + kMkvSignedElement = 0x6532, + kMkvSegment = 0x18538067, + kMkvSeekHead = 0x114D9B74, + kMkvSeek = 0x4DBB, + kMkvSeekId = 0x53AB, + kMkvSeekPosition = 0x53AC, + kMkvInfo = 0x1549A966, + kMkvTimecodeScale = 0x2AD7B1, + kMkvSegmentDuration = 0x4489, + kMkvDateUtc = 0x4461, + kMkvMuxingApp = 0x4D80, + kMkvWritingApp = 0x5741, + kMkvCluster = 0x1F43B675, + kMkvTimecode = 0xE7, + kMkvPrevSize = 0xAB, + kMkvBlockGroup = 0xA0, + kMkvBlock = 0xA1, + kMkvBlockAdditions = 0x75A1, + kMkvBlockMore = 0xA6, + kMkvBlockAddId = 0xEE, + kMkvBlockAdditional = 0xA5, + kMkvBlockDuration = 0x9B, + kMkvReferenceBlock = 0xFB, + kMkvLaceNumber = 0xCC, + kMkvSimpleBlock = 0xA3, + kMkvTracks = 0x1654AE6B, + kMkvTrackEntry = 0xAE, + kMkvTrackNumber = 0xD7, + kMkvTrackUid = 0x73C5, + kMkvTrackType = 0x83, + kMkvFlagEnabled = 0xB9, + kMkvFlagDefault = 0x88, + kMkvFlagForced = 0x55AA, + kMkvFlagLacing = 0x9C, + kMkvDefaultDuration = 0x23E383, + kMkvMaxBlockAdditionId = 0x55EE, + kMkvName = 0x536E, + kMkvLanguage = 0x22B59C, + kMkvCodecId = 0x86, + kMkvCodecPrivate = 0x63A2, + kMkvCodecName = 0x258688, + kMkvVideo = 0xE0, + kMkvFlagInterlaced = 0x9A, + kMkvStereoMode = 0x53B8, + kMkvAlphaMode = 0x53C0, + kMkvPixelWidth = 0xB0, + kMkvPixelHeight = 0xBA, + kMkvPixelCropBottom = 0x54AA, + kMkvPixelCropTop = 0x54BB, + kMkvPixelCropLeft = 0x54CC, + kMkvPixelCropRight = 0x54DD, + kMkvDisplayWidth = 0x54B0, + kMkvDisplayHeight = 0x54BA, + kMkvDisplayUnit = 0x54B2, + kMkvAspectRatioType = 0x54B3, + kMkvFrameRate = 0x2383E3, + kMkvAudio = 0xE1, + kMkvSamplingFrequency = 0xB5, + kMkvOutputSamplingFrequency = 0x78B5, + kMkvChannels = 0x9F, + kMkvBitDepth = 0x6264, + kMkvCues = 0x1C53BB6B, + kMkvCuePoint = 0xBB, + kMkvCueTime = 0xB3, + kMkvCueTrackPositions = 0xB7, + kMkvCueTrack = 0xF7, + kMkvCueClusterPosition = 0xF1, + kMkvCueBlockNumber = 0x5378 +}; + +enum TrackTypes { + kInvalidType = -1, + kVideoType = 0x1, + kAudioType = 0x2, + kComplexType = 0x3, + kLogoType = 0x10, + kSubtitleType = 0x11, + kButtonsType = 0x12, + kControlType = 0x20 +}; + +enum TrackNum { + kVideoTrackNum = 0x1, + kAudioTrackNum = 0x2 +}; +} + +#endif /* WEBMCONSTANTS_H_ */ diff --git a/media/libstagefright/webm/WebmElement.cpp b/media/libstagefright/webm/WebmElement.cpp new file mode 100644 index 0000000..c978966 --- /dev/null +++ b/media/libstagefright/webm/WebmElement.cpp @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #define LOG_NDEBUG 0 +#define LOG_TAG "WebmElement" + +#include "EbmlUtil.h" +#include "WebmElement.h" +#include "WebmConstants.h" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace android; +using namespace webm; + +namespace { + +int64_t voidSize(int64_t totalSize) { + if (totalSize < 2) { + return -1; + } + if (totalSize < 9) { + return totalSize - 2; + } + return totalSize - 9; +} + +uint64_t childrenSum(const List >& children) { + uint64_t total = 0; + for (List >::const_iterator it = children.begin(); + it != children.end(); ++it) { + total += (*it)->totalSize(); + } + return total; +} + +void populateCommonTrackEntries( + int num, + uint64_t uid, + bool lacing, + const char *lang, + const char *codec, + TrackTypes type, + List > &ls) { + ls.push_back(new WebmUnsigned(kMkvTrackNumber, num)); + ls.push_back(new WebmUnsigned(kMkvTrackUid, uid)); + ls.push_back(new WebmUnsigned(kMkvFlagLacing, lacing)); + ls.push_back(new WebmString(kMkvLanguage, lang)); + ls.push_back(new WebmString(kMkvCodecId, codec)); + ls.push_back(new WebmUnsigned(kMkvTrackType, type)); +} +} + +namespace android { + +WebmElement::WebmElement(uint64_t id, uint64_t size) + : mId(id), mSize(size) { +} + +WebmElement::~WebmElement() { +} + +int WebmElement::serializePayloadSize(uint8_t *buf) { + return serializeCodedUnsigned(encodeUnsigned(mSize), buf); +} + +uint64_t WebmElement::serializeInto(uint8_t *buf) { + uint8_t *cur = buf; + int head = serializeCodedUnsigned(mId, cur); + cur += head; + int neck = serializePayloadSize(cur); + cur += neck; + serializePayload(cur); + cur += mSize; + return cur - buf; +} + +uint64_t WebmElement::totalSize() { + uint8_t buf[8]; + //............... + sizeOf(encodeUnsigned(size)) + return sizeOf(mId) + serializePayloadSize(buf) + mSize; +} + +uint8_t *WebmElement::serialize(uint64_t& size) { + size = totalSize(); + uint8_t *buf = new uint8_t[size]; + serializeInto(buf); + return buf; +} + +int WebmElement::write(int fd, uint64_t& size) { + uint8_t buf[8]; + size = totalSize(); + off64_t off = ::lseek64(fd, (size - 1), SEEK_CUR) - (size - 1); + ::write(fd, buf, 1); // extend file + + off64_t curOff = off + size; + off64_t alignedOff = off & ~(::sysconf(_SC_PAGE_SIZE) - 1); + off64_t mapSize = curOff - alignedOff; + off64_t pageOff = off - alignedOff; + void *dst = ::mmap64(NULL, mapSize, PROT_WRITE, MAP_SHARED, fd, alignedOff); + if ((int) dst == -1) { + ALOGE("mmap64 failed; errno = %d", errno); + ALOGE("fd %d; flags: %o", fd, ::fcntl(fd, F_GETFL, 0)); + return errno; + } else { + serializeInto((uint8_t*) dst + pageOff); + ::msync(dst, mapSize, MS_SYNC); + return ::munmap(dst, mapSize); + } +} + +//================================================================================================= + +WebmUnsigned::WebmUnsigned(uint64_t id, uint64_t value) + : WebmElement(id, sizeOf(value)), mValue(value) { +} + +void WebmUnsigned::serializePayload(uint8_t *buf) { + serializeCodedUnsigned(mValue, buf); +} + +//================================================================================================= + +WebmFloat::WebmFloat(uint64_t id, double value) + : WebmElement(id, sizeof(double)), mValue(value) { +} + +WebmFloat::WebmFloat(uint64_t id, float value) + : WebmElement(id, sizeof(float)), mValue(value) { +} + +void WebmFloat::serializePayload(uint8_t *buf) { + uint64_t data; + if (mSize == sizeof(float)) { + float f = mValue; + data = *reinterpret_cast(&f); + } else { + data = *reinterpret_cast(&mValue); + } + for (int i = mSize - 1; i >= 0; --i) { + buf[i] = data & 0xff; + data >>= 8; + } +} + +//================================================================================================= + +WebmBinary::WebmBinary(uint64_t id, const sp &ref) + : WebmElement(id, ref->size()), mRef(ref) { +} + +void WebmBinary::serializePayload(uint8_t *buf) { + memcpy(buf, mRef->data(), mRef->size()); +} + +//================================================================================================= + +WebmString::WebmString(uint64_t id, const char *str) + : WebmElement(id, strlen(str)), mStr(str) { +} + +void WebmString::serializePayload(uint8_t *buf) { + memcpy(buf, mStr, strlen(mStr)); +} + +//================================================================================================= + +WebmSimpleBlock::WebmSimpleBlock( + int trackNum, + int16_t relTimecode, + bool key, + const sp& orig) + // ............................ trackNum*1 + timecode*2 + flags*1 + // ^^^ + // Only the least significant byte of trackNum is encoded + : WebmElement(kMkvSimpleBlock, orig->size() + 4), + mTrackNum(trackNum), + mRelTimecode(relTimecode), + mKey(key), + mRef(orig) { +} + +void WebmSimpleBlock::serializePayload(uint8_t *buf) { + serializeCodedUnsigned(encodeUnsigned(mTrackNum), buf); + buf[1] = (mRelTimecode & 0xff00) >> 8; + buf[2] = mRelTimecode & 0xff; + buf[3] = mKey ? 0x80 : 0; + memcpy(buf + 4, mRef->data(), mSize - 4); +} + +//================================================================================================= + +EbmlVoid::EbmlVoid(uint64_t totalSize) + : WebmElement(kMkvVoid, voidSize(totalSize)), + mSizeWidth(totalSize - sizeOf(kMkvVoid) - voidSize(totalSize)) { + CHECK_GE(voidSize(totalSize), 0); +} + +int EbmlVoid::serializePayloadSize(uint8_t *buf) { + return serializeCodedUnsigned(encodeUnsigned(mSize, mSizeWidth), buf); +} + +void EbmlVoid::serializePayload(uint8_t *buf) { + ::memset(buf, 0, mSize); + return; +} + +//================================================================================================= + +WebmMaster::WebmMaster(uint64_t id, const List >& children) + : WebmElement(id, childrenSum(children)), mChildren(children) { +} + +WebmMaster::WebmMaster(uint64_t id) + : WebmElement(id, 0) { +} + +int WebmMaster::serializePayloadSize(uint8_t *buf) { + if (mSize == 0){ + return serializeCodedUnsigned(kMkvUnknownLength, buf); + } + return WebmElement::serializePayloadSize(buf); +} + +void WebmMaster::serializePayload(uint8_t *buf) { + uint64_t off = 0; + for (List >::const_iterator it = mChildren.begin(); it != mChildren.end(); + ++it) { + sp child = (*it); + child->serializeInto(buf + off); + off += child->totalSize(); + } +} + +//================================================================================================= + +sp WebmElement::CuePointEntry(uint64_t time, int track, uint64_t off) { + List > cuePointEntryFields; + cuePointEntryFields.push_back(new WebmUnsigned(kMkvCueTrack, track)); + cuePointEntryFields.push_back(new WebmUnsigned(kMkvCueClusterPosition, off)); + WebmElement *cueTrackPositions = new WebmMaster(kMkvCueTrackPositions, cuePointEntryFields); + + cuePointEntryFields.clear(); + cuePointEntryFields.push_back(new WebmUnsigned(kMkvCueTime, time)); + cuePointEntryFields.push_back(cueTrackPositions); + return new WebmMaster(kMkvCuePoint, cuePointEntryFields); +} + +sp WebmElement::SeekEntry(uint64_t id, uint64_t off) { + List > seekEntryFields; + seekEntryFields.push_back(new WebmUnsigned(kMkvSeekId, id)); + seekEntryFields.push_back(new WebmUnsigned(kMkvSeekPosition, off)); + return new WebmMaster(kMkvSeek, seekEntryFields); +} + +sp WebmElement::EbmlHeader( + int ver, + int readVer, + int maxIdLen, + int maxSizeLen, + int docVer, + int docReadVer) { + List > headerFields; + headerFields.push_back(new WebmUnsigned(kMkvEbmlVersion, ver)); + headerFields.push_back(new WebmUnsigned(kMkvEbmlReadVersion, readVer)); + headerFields.push_back(new WebmUnsigned(kMkvEbmlMaxIdlength, maxIdLen)); + headerFields.push_back(new WebmUnsigned(kMkvEbmlMaxSizeLength, maxSizeLen)); + headerFields.push_back(new WebmString(kMkvDocType, "webm")); + headerFields.push_back(new WebmUnsigned(kMkvDocTypeVersion, docVer)); + headerFields.push_back(new WebmUnsigned(kMkvDocTypeReadVersion, docReadVer)); + return new WebmMaster(kMkvEbml, headerFields); +} + +sp WebmElement::SegmentInfo(uint64_t scale, double dur) { + List > segmentInfo; + // place duration first; easier to patch + segmentInfo.push_back(new WebmFloat(kMkvSegmentDuration, dur)); + segmentInfo.push_back(new WebmUnsigned(kMkvTimecodeScale, scale)); + segmentInfo.push_back(new WebmString(kMkvMuxingApp, "android")); + segmentInfo.push_back(new WebmString(kMkvWritingApp, "android")); + return new WebmMaster(kMkvInfo, segmentInfo); +} + +sp WebmElement::AudioTrackEntry( + int chans, + double rate, + const sp &buf, + int bps, + uint64_t uid, + bool lacing, + const char *lang) { + if (uid == 0) { + uid = kAudioTrackNum; + } + + List > trackEntryFields; + populateCommonTrackEntries( + kAudioTrackNum, + uid, + lacing, + lang, + "A_VORBIS", + kAudioType, + trackEntryFields); + + List > audioInfo; + audioInfo.push_back(new WebmUnsigned(kMkvChannels, chans)); + audioInfo.push_back(new WebmFloat(kMkvSamplingFrequency, rate)); + if (bps) { + WebmElement *bitDepth = new WebmUnsigned(kMkvBitDepth, bps); + audioInfo.push_back(bitDepth); + } + + trackEntryFields.push_back(new WebmMaster(kMkvAudio, audioInfo)); + trackEntryFields.push_back(new WebmBinary(kMkvCodecPrivate, buf)); + return new WebmMaster(kMkvTrackEntry, trackEntryFields); +} + +sp WebmElement::VideoTrackEntry( + uint64_t width, + uint64_t height, + uint64_t uid, + bool lacing, + const char *lang) { + if (uid == 0) { + uid = kVideoTrackNum; + } + + List > trackEntryFields; + populateCommonTrackEntries( + kVideoTrackNum, + uid, + lacing, + lang, + "V_VP8", + kVideoType, + trackEntryFields); + + List > videoInfo; + videoInfo.push_back(new WebmUnsigned(kMkvPixelWidth, width)); + videoInfo.push_back(new WebmUnsigned(kMkvPixelHeight, height)); + + trackEntryFields.push_back(new WebmMaster(kMkvVideo, videoInfo)); + return new WebmMaster(kMkvTrackEntry, trackEntryFields); +} +} /* namespace android */ diff --git a/media/libstagefright/webm/WebmElement.h b/media/libstagefright/webm/WebmElement.h new file mode 100644 index 0000000..f19933e --- /dev/null +++ b/media/libstagefright/webm/WebmElement.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2014 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 WEBMELEMENT_H_ +#define WEBMELEMENT_H_ + +#include +#include +#include +#include + +namespace android { + +struct WebmElement : public LightRefBase { + const uint64_t mId, mSize; + + WebmElement(uint64_t id, uint64_t size); + virtual ~WebmElement(); + + virtual int serializePayloadSize(uint8_t *buf); + virtual void serializePayload(uint8_t *buf)=0; + uint64_t totalSize(); + uint64_t serializeInto(uint8_t *buf); + uint8_t *serialize(uint64_t& size); + int write(int fd, uint64_t& size); + + static sp EbmlHeader( + int ver = 1, + int readVer = 1, + int maxIdLen = 4, + int maxSizeLen = 8, + int docVer = 2, + int docReadVer = 2); + + static sp SegmentInfo(uint64_t scale = 1000000, double dur = 0); + + static sp AudioTrackEntry( + int chans, + double rate, + const sp &buf, + int bps = 0, + uint64_t uid = 0, + bool lacing = false, + const char *lang = "und"); + + static sp VideoTrackEntry( + uint64_t width, + uint64_t height, + uint64_t uid = 0, + bool lacing = false, + const char *lang = "und"); + + static sp SeekEntry(uint64_t id, uint64_t off); + static sp CuePointEntry(uint64_t time, int track, uint64_t off); + static sp SimpleBlock( + int trackNum, + int16_t timecode, + bool key, + const uint8_t *data, + uint64_t dataSize); +}; + +struct WebmUnsigned : public WebmElement { + WebmUnsigned(uint64_t id, uint64_t value); + const uint64_t mValue; + void serializePayload(uint8_t *buf); +}; + +struct WebmFloat : public WebmElement { + const double mValue; + WebmFloat(uint64_t id, float value); + WebmFloat(uint64_t id, double value); + void serializePayload(uint8_t *buf); +}; + +struct WebmBinary : public WebmElement { + const sp mRef; + WebmBinary(uint64_t id, const sp &ref); + void serializePayload(uint8_t *buf); +}; + +struct WebmString : public WebmElement { + const char *const mStr; + WebmString(uint64_t id, const char *str); + void serializePayload(uint8_t *buf); +}; + +struct WebmSimpleBlock : public WebmElement { + const int mTrackNum; + const int16_t mRelTimecode; + const bool mKey; + const sp mRef; + + WebmSimpleBlock(int trackNum, int16_t timecode, bool key, const sp& orig); + void serializePayload(uint8_t *buf); +}; + +struct EbmlVoid : public WebmElement { + const uint64_t mSizeWidth; + EbmlVoid(uint64_t totalSize); + int serializePayloadSize(uint8_t *buf); + void serializePayload(uint8_t *buf); +}; + +struct WebmMaster : public WebmElement { + const List > mChildren; + WebmMaster(uint64_t id); + WebmMaster(uint64_t id, const List > &children); + int serializePayloadSize(uint8_t *buf); + void serializePayload(uint8_t *buf); +}; + +} /* namespace android */ +#endif /* WEBMELEMENT_H_ */ diff --git a/media/libstagefright/webm/WebmFrame.cpp b/media/libstagefright/webm/WebmFrame.cpp new file mode 100644 index 0000000..e5134ed --- /dev/null +++ b/media/libstagefright/webm/WebmFrame.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "WebmFrame" + +#include "WebmFrame.h" +#include "WebmConstants.h" + +#include +#include + +using namespace android; +using namespace webm; + +namespace { +sp toABuffer(MediaBuffer *mbuf) { + sp abuf = new ABuffer(mbuf->range_length()); + memcpy(abuf->data(), (uint8_t*) mbuf->data() + mbuf->range_offset(), mbuf->range_length()); + return abuf; +} +} + +namespace android { + +const sp WebmFrame::EOS = new WebmFrame(); + +WebmFrame::WebmFrame() + : mType(kInvalidType), + mKey(false), + mAbsTimecode(UINT64_MAX), + mData(new ABuffer(0)), + mEos(true) { +} + +WebmFrame::WebmFrame(int type, bool key, uint64_t absTimecode, MediaBuffer *mbuf) + : mType(type), + mKey(key), + mAbsTimecode(absTimecode), + mData(toABuffer(mbuf)), + mEos(false) { +} + +sp WebmFrame::SimpleBlock(uint64_t baseTimecode) const { + return new WebmSimpleBlock( + mType == kVideoType ? kVideoTrackNum : kAudioTrackNum, + mAbsTimecode - baseTimecode, + mKey, + mData); +} + +bool WebmFrame::operator<(const WebmFrame &other) const { + if (this->mEos) { + return false; + } + if (other.mEos) { + return true; + } + if (this->mAbsTimecode == other.mAbsTimecode) { + if (this->mType == kAudioType && other.mType == kVideoType) { + return true; + } + if (this->mType == kVideoType && other.mType == kAudioType) { + return false; + } + return false; + } + return this->mAbsTimecode < other.mAbsTimecode; +} +} /* namespace android */ diff --git a/media/libstagefright/webm/WebmFrame.h b/media/libstagefright/webm/WebmFrame.h new file mode 100644 index 0000000..4f0b055 --- /dev/null +++ b/media/libstagefright/webm/WebmFrame.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014 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 WEBMFRAME_H_ +#define WEBMFRAME_H_ + +#include "WebmElement.h" + +namespace android { + +struct WebmFrame : LightRefBase { +public: + const int mType; + const bool mKey; + const uint64_t mAbsTimecode; + const sp mData; + const bool mEos; + + WebmFrame(); + WebmFrame(int type, bool key, uint64_t absTimecode, MediaBuffer *buf); + ~WebmFrame() {} + + sp SimpleBlock(uint64_t baseTimecode) const; + + bool operator<(const WebmFrame &other) const; + + static const sp EOS; +private: + DISALLOW_EVIL_CONSTRUCTORS(WebmFrame); +}; + +} /* namespace android */ +#endif /* WEBMFRAME_H_ */ diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp new file mode 100644 index 0000000..5addd3c --- /dev/null +++ b/media/libstagefright/webm/WebmFrameThread.cpp @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "WebmFrameThread" + +#include "WebmConstants.h" +#include "WebmFrameThread.h" + +#include +#include + +#include +#include + +using namespace webm; + +namespace android { + +void *WebmFrameThread::wrap(void *arg) { + WebmFrameThread *worker = reinterpret_cast(arg); + worker->run(); + return NULL; +} + +status_t WebmFrameThread::start() { + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + pthread_create(&mThread, &attr, WebmFrameThread::wrap, this); + pthread_attr_destroy(&attr); + return OK; +} + +status_t WebmFrameThread::stop() { + void *status; + pthread_join(mThread, &status); + return (status_t) status; +} + +//================================================================================================= + +WebmFrameSourceThread::WebmFrameSourceThread( + int type, + LinkedBlockingQueue >& sink) + : mType(type), mSink(sink) { +} + +//================================================================================================= + +WebmFrameSinkThread::WebmFrameSinkThread( + const int& fd, + const uint64_t& off, + sp videoThread, + sp audioThread, + List >& cues) + : mFd(fd), + mSegmentDataStart(off), + mVideoFrames(videoThread->mSink), + mAudioFrames(audioThread->mSink), + mCues(cues), + mDone(true) { +} + +WebmFrameSinkThread::WebmFrameSinkThread( + const int& fd, + const uint64_t& off, + LinkedBlockingQueue >& videoSource, + LinkedBlockingQueue >& audioSource, + List >& cues) + : mFd(fd), + mSegmentDataStart(off), + mVideoFrames(videoSource), + mAudioFrames(audioSource), + mCues(cues), + mDone(true) { +} + +// Initializes a webm cluster with its starting timecode. +// +// frames: +// sequence of input audio/video frames received from the source. +// +// clusterTimecodeL: +// the starting timecode of the cluster; this is the timecode of the first +// frame since frames are ordered by timestamp. +// +// children: +// list to hold child elements in a webm cluster (start timecode and +// simple blocks). +// +// static +void WebmFrameSinkThread::initCluster( + List >& frames, + uint64_t& clusterTimecodeL, + List >& children) { + CHECK(!frames.empty() && children.empty()); + + const sp f = *(frames.begin()); + clusterTimecodeL = f->mAbsTimecode; + WebmUnsigned *clusterTimecode = new WebmUnsigned(kMkvTimecode, clusterTimecodeL); + children.clear(); + children.push_back(clusterTimecode); +} + +void WebmFrameSinkThread::writeCluster(List >& children) { + // children must contain at least one simpleblock and its timecode + CHECK_GE(children.size(), 2); + + uint64_t size; + sp cluster = new WebmMaster(kMkvCluster, children); + cluster->write(mFd, size); + children.clear(); +} + +// Write out (possibly multiple) webm cluster(s) from frames split on video key frames. +// +// last: +// current flush is triggered by EOS instead of a second outstanding video key frame. +void WebmFrameSinkThread::flushFrames(List >& frames, bool last) { + if (frames.empty()) { + return; + } + + uint64_t clusterTimecodeL; + List > children; + initCluster(frames, clusterTimecodeL, children); + + uint64_t cueTime = clusterTimecodeL; + off_t fpos = ::lseek(mFd, 0, SEEK_CUR); + size_t n = frames.size(); + if (!last) { + // If we are not flushing the last sequence of outstanding frames, flushFrames + // must have been called right after we have pushed a second outstanding video key + // frame (the last frame), which belongs to the next cluster; also hold back on + // flushing the second to last frame before we check its type. A audio frame + // should precede the aforementioned video key frame in the next sequence, a video + // frame should be the last frame in the current (to-be-flushed) sequence. + CHECK_GE(n, 2); + n -= 2; + } + + for (size_t i = 0; i < n; i++) { + const sp f = *(frames.begin()); + if (f->mType == kVideoType && f->mKey) { + cueTime = f->mAbsTimecode; + } + + if (f->mAbsTimecode - clusterTimecodeL > INT16_MAX) { + writeCluster(children); + initCluster(frames, clusterTimecodeL, children); + } + + frames.erase(frames.begin()); + children.push_back(f->SimpleBlock(clusterTimecodeL)); + } + + // equivalent to last==false + if (!frames.empty()) { + // decide whether to write out the second to last frame. + const sp secondLastFrame = *(frames.begin()); + if (secondLastFrame->mType == kVideoType) { + frames.erase(frames.begin()); + children.push_back(secondLastFrame->SimpleBlock(clusterTimecodeL)); + } + } + + writeCluster(children); + sp cuePoint = WebmElement::CuePointEntry(cueTime, 1, fpos - mSegmentDataStart); + mCues.push_back(cuePoint); +} + +status_t WebmFrameSinkThread::start() { + mDone = false; + return WebmFrameThread::start(); +} + +status_t WebmFrameSinkThread::stop() { + mDone = true; + mVideoFrames.push(WebmFrame::EOS); + mAudioFrames.push(WebmFrame::EOS); + return WebmFrameThread::stop(); +} + +void WebmFrameSinkThread::run() { + int numVideoKeyFrames = 0; + List > outstandingFrames; + while (!mDone) { + ALOGV("wait v frame"); + const sp videoFrame = mVideoFrames.peek(); + ALOGV("v frame: %p", videoFrame.get()); + + ALOGV("wait a frame"); + const sp audioFrame = mAudioFrames.peek(); + ALOGV("a frame: %p", audioFrame.get()); + + if (videoFrame->mEos && audioFrame->mEos) { + break; + } + + if (*audioFrame < *videoFrame) { + ALOGV("take a frame"); + mAudioFrames.take(); + outstandingFrames.push_back(audioFrame); + } else { + ALOGV("take v frame"); + mVideoFrames.take(); + outstandingFrames.push_back(videoFrame); + if (videoFrame->mKey) + numVideoKeyFrames++; + } + + if (numVideoKeyFrames == 2) { + flushFrames(outstandingFrames, /* last = */ false); + numVideoKeyFrames--; + } + } + ALOGV("flushing last cluster (size %zu)", outstandingFrames.size()); + flushFrames(outstandingFrames, /* last = */ true); + mDone = true; +} + +//================================================================================================= + +static const int64_t kInitialDelayTimeUs = 700000LL; + +void WebmFrameMediaSourceThread::clearFlags() { + mDone = false; + mPaused = false; + mResumed = false; + mStarted = false; + mReachedEOS = false; +} + +WebmFrameMediaSourceThread::WebmFrameMediaSourceThread( + const sp& source, + int type, + LinkedBlockingQueue >& sink, + uint64_t timeCodeScale, + int64_t startTimeRealUs, + int32_t startTimeOffsetMs, + int numTracks, + bool realTimeRecording) + : WebmFrameSourceThread(type, sink), + mSource(source), + mTimeCodeScale(timeCodeScale), + mTrackDurationUs(0) { + clearFlags(); + mStartTimeUs = startTimeRealUs; + if (realTimeRecording && numTracks > 1) { + /* + * Copied from MPEG4Writer + * + * This extra delay of accepting incoming audio/video signals + * helps to align a/v start time at the beginning of a recording + * session, and it also helps eliminate the "recording" sound for + * camcorder applications. + * + * If client does not set the start time offset, we fall back to + * use the default initial delay value. + */ + int64_t startTimeOffsetUs = startTimeOffsetMs * 1000LL; + if (startTimeOffsetUs < 0) { // Start time offset was not set + startTimeOffsetUs = kInitialDelayTimeUs; + } + mStartTimeUs += startTimeOffsetUs; + ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs); + } +} + +status_t WebmFrameMediaSourceThread::start() { + sp meta = new MetaData; + meta->setInt64(kKeyTime, mStartTimeUs); + status_t err = mSource->start(meta.get()); + if (err != OK) { + mDone = true; + mReachedEOS = true; + return err; + } else { + mStarted = true; + return WebmFrameThread::start(); + } +} + +status_t WebmFrameMediaSourceThread::resume() { + if (!mDone && mPaused) { + mPaused = false; + mResumed = true; + } + return OK; +} + +status_t WebmFrameMediaSourceThread::pause() { + if (mStarted) { + mPaused = true; + } + return OK; +} + +status_t WebmFrameMediaSourceThread::stop() { + if (mStarted) { + mStarted = false; + mDone = true; + mSource->stop(); + return WebmFrameThread::stop(); + } + return OK; +} + +void WebmFrameMediaSourceThread::run() { + int32_t count = 0; + int64_t timestampUs = 0xdeadbeef; + int64_t lastTimestampUs = 0; // Previous sample time stamp + int64_t lastDurationUs = 0; // Previous sample duration + int64_t previousPausedDurationUs = 0; + + const uint64_t kUninitialized = 0xffffffffffffffffL; + mStartTimeUs = kUninitialized; + + status_t err = OK; + MediaBuffer *buffer; + while (!mDone && (err = mSource->read(&buffer, NULL)) == OK) { + if (buffer->range_length() == 0) { + buffer->release(); + buffer = NULL; + continue; + } + + sp md = buffer->meta_data(); + CHECK(md->findInt64(kKeyTime, ×tampUs)); + if (mStartTimeUs == kUninitialized) { + mStartTimeUs = timestampUs; + } + timestampUs -= mStartTimeUs; + + if (mPaused && !mResumed) { + lastDurationUs = timestampUs - lastTimestampUs; + lastTimestampUs = timestampUs; + buffer->release(); + buffer = NULL; + continue; + } + ++count; + + // adjust time-stamps after pause/resume + if (mResumed) { + int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; + CHECK_GE(durExcludingEarlierPausesUs, 0ll); + int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; + CHECK_GE(pausedDurationUs, lastDurationUs); + previousPausedDurationUs += pausedDurationUs - lastDurationUs; + mResumed = false; + } + timestampUs -= previousPausedDurationUs; + CHECK_GE(timestampUs, 0ll); + + int32_t isSync = false; + md->findInt32(kKeyIsSyncFrame, &isSync); + const sp f = new WebmFrame( + mType, + isSync, + timestampUs * 1000 / mTimeCodeScale, + buffer); + mSink.push(f); + + ALOGV( + "%s %s frame at %" PRId64 " size %zu\n", + mType == kVideoType ? "video" : "audio", + isSync ? "I" : "P", + timestampUs * 1000 / mTimeCodeScale, + buffer->range_length()); + + buffer->release(); + buffer = NULL; + + if (timestampUs > mTrackDurationUs) { + mTrackDurationUs = timestampUs; + } + lastDurationUs = timestampUs - lastTimestampUs; + lastTimestampUs = timestampUs; + } + + mTrackDurationUs += lastDurationUs; + mSink.push(WebmFrame::EOS); +} +} diff --git a/media/libstagefright/webm/WebmFrameThread.h b/media/libstagefright/webm/WebmFrameThread.h new file mode 100644 index 0000000..d65d9b7 --- /dev/null +++ b/media/libstagefright/webm/WebmFrameThread.h @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2014 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 WEBMFRAMETHREAD_H_ +#define WEBMFRAMETHREAD_H_ + +#include "WebmFrame.h" +#include "LinkedBlockingQueue.h" + +#include +#include + +#include +#include + +#include + +namespace android { + +class WebmFrameThread : public LightRefBase { +public: + virtual void run() = 0; + virtual bool running() { return false; } + virtual status_t start(); + virtual status_t pause() { return OK; } + virtual status_t resume() { return OK; } + virtual status_t stop(); + virtual ~WebmFrameThread() { stop(); } + static void *wrap(void *arg); + +protected: + WebmFrameThread() + : mThread(0) { + } + +private: + pthread_t mThread; + DISALLOW_EVIL_CONSTRUCTORS(WebmFrameThread); +}; + +//================================================================================================= + +class WebmFrameSourceThread; +class WebmFrameSinkThread : public WebmFrameThread { +public: + WebmFrameSinkThread( + const int& fd, + const uint64_t& off, + sp videoThread, + sp audioThread, + List >& cues); + + WebmFrameSinkThread( + const int& fd, + const uint64_t& off, + LinkedBlockingQueue >& videoSource, + LinkedBlockingQueue >& audioSource, + List >& cues); + + void run(); + bool running() { + return !mDone; + } + status_t start(); + status_t stop(); + +private: + const int& mFd; + const uint64_t& mSegmentDataStart; + LinkedBlockingQueue >& mVideoFrames; + LinkedBlockingQueue >& mAudioFrames; + List >& mCues; + + volatile bool mDone; + + static void initCluster( + List >& frames, + uint64_t& clusterTimecodeL, + List >& children); + void writeCluster(List >& children); + void flushFrames(List >& frames, bool last); +}; + +//================================================================================================= + +class WebmFrameSourceThread : public WebmFrameThread { +public: + WebmFrameSourceThread(int type, LinkedBlockingQueue >& sink); + virtual int64_t getDurationUs() = 0; +protected: + const int mType; + LinkedBlockingQueue >& mSink; + + friend class WebmFrameSinkThread; +}; + +//================================================================================================= + +class WebmFrameEmptySourceThread : public WebmFrameSourceThread { +public: + WebmFrameEmptySourceThread(int type, LinkedBlockingQueue >& sink) + : WebmFrameSourceThread(type, sink) { + } + void run() { mSink.push(WebmFrame::EOS); } + int64_t getDurationUs() { return 0; } +}; + +//================================================================================================= + +class WebmFrameMediaSourceThread: public WebmFrameSourceThread { +public: + WebmFrameMediaSourceThread( + const sp& source, + int type, + LinkedBlockingQueue >& sink, + uint64_t timeCodeScale, + int64_t startTimeRealUs, + int32_t startTimeOffsetMs, + int numPeers, + bool realTimeRecording); + + void run(); + status_t start(); + status_t resume(); + status_t pause(); + status_t stop(); + int64_t getDurationUs() { + return mTrackDurationUs; + } + +private: + const sp mSource; + const uint64_t mTimeCodeScale; + uint64_t mStartTimeUs; + + volatile bool mDone; + volatile bool mPaused; + volatile bool mResumed; + volatile bool mStarted; + volatile bool mReachedEOS; + int64_t mTrackDurationUs; + + void clearFlags(); +}; +} /* namespace android */ + +#endif /* WEBMFRAMETHREAD_H_ */ diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp new file mode 100644 index 0000000..03cf92a --- /dev/null +++ b/media/libstagefright/webm/WebmWriter.cpp @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #define LOG_NDEBUG 0 +#define LOG_TAG "WebmWriter" + +#include "EbmlUtil.h" +#include "WebmWriter.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace webm; + +namespace { +size_t XiphLaceCodeLen(size_t size) { + return size / 0xff + 1; +} + +size_t XiphLaceEnc(uint8_t *buf, size_t size) { + size_t i; + for (i = 0; size >= 0xff; ++i, size -= 0xff) { + buf[i] = 0xff; + } + buf[i++] = size; + return i; +} +} + +namespace android { + +static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024; + +WebmWriter::WebmWriter(int fd) + : mFd(dup(fd)), + mInitCheck(mFd < 0 ? NO_INIT : OK), + mTimeCodeScale(1000000), + mStartTimestampUs(0), + mStartTimeOffsetMs(0), + mSegmentOffset(0), + mSegmentDataStart(0), + mInfoOffset(0), + mInfoSize(0), + mTracksOffset(0), + mCuesOffset(0), + mPaused(false), + mStarted(false), + mIsFileSizeLimitExplicitlyRequested(false), + mIsRealTimeRecording(false), + mStreamableFile(true), + mEstimatedCuesSize(0) { + mStreams[kAudioIndex] = WebmStream(kAudioType, "Audio", &WebmWriter::audioTrack); + mStreams[kVideoIndex] = WebmStream(kVideoType, "Video", &WebmWriter::videoTrack); + mSinkThread = new WebmFrameSinkThread( + mFd, + mSegmentDataStart, + mStreams[kVideoIndex].mSink, + mStreams[kAudioIndex].mSink, + mCuePoints); +} + +WebmWriter::WebmWriter(const char *filename) + : mInitCheck(NO_INIT), + mTimeCodeScale(1000000), + mStartTimestampUs(0), + mStartTimeOffsetMs(0), + mSegmentOffset(0), + mSegmentDataStart(0), + mInfoOffset(0), + mInfoSize(0), + mTracksOffset(0), + mCuesOffset(0), + mPaused(false), + mStarted(false), + mIsFileSizeLimitExplicitlyRequested(false), + mIsRealTimeRecording(false), + mStreamableFile(true), + mEstimatedCuesSize(0) { + mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR); + if (mFd >= 0) { + ALOGV("fd %d; flags: %o", mFd, fcntl(mFd, F_GETFL, 0)); + mInitCheck = OK; + } + mStreams[kAudioIndex] = WebmStream(kAudioType, "Audio", &WebmWriter::audioTrack); + mStreams[kVideoIndex] = WebmStream(kVideoType, "Video", &WebmWriter::videoTrack); + mSinkThread = new WebmFrameSinkThread( + mFd, + mSegmentDataStart, + mStreams[kVideoIndex].mSink, + mStreams[kAudioIndex].mSink, + mCuePoints); +} + +// static +sp WebmWriter::videoTrack(const sp& md) { + int32_t width, height; + CHECK(md->findInt32(kKeyWidth, &width)); + CHECK(md->findInt32(kKeyHeight, &height)); + return WebmElement::VideoTrackEntry(width, height); +} + +// static +sp WebmWriter::audioTrack(const sp& md) { + int32_t nChannels, samplerate; + uint32_t type; + const void *headerData1; + const char headerData2[] = { 3, 'v', 'o', 'r', 'b', 'i', 's', 7, 0, 0, 0, + 'a', 'n', 'd', 'r', 'o', 'i', 'd', 0, 0, 0, 0, 1 }; + const void *headerData3; + size_t headerSize1, headerSize2 = sizeof(headerData2), headerSize3; + + CHECK(md->findInt32(kKeyChannelCount, &nChannels)); + CHECK(md->findInt32(kKeySampleRate, &samplerate)); + CHECK(md->findData(kKeyVorbisInfo, &type, &headerData1, &headerSize1)); + CHECK(md->findData(kKeyVorbisBooks, &type, &headerData3, &headerSize3)); + + size_t codecPrivateSize = 1; + codecPrivateSize += XiphLaceCodeLen(headerSize1); + codecPrivateSize += XiphLaceCodeLen(headerSize2); + codecPrivateSize += headerSize1 + headerSize2 + headerSize3; + + off_t off = 0; + sp codecPrivateBuf = new ABuffer(codecPrivateSize); + uint8_t *codecPrivateData = codecPrivateBuf->data(); + codecPrivateData[off++] = 2; + + off += XiphLaceEnc(codecPrivateData + off, headerSize1); + off += XiphLaceEnc(codecPrivateData + off, headerSize2); + + memcpy(codecPrivateData + off, headerData1, headerSize1); + off += headerSize1; + memcpy(codecPrivateData + off, headerData2, headerSize2); + off += headerSize2; + memcpy(codecPrivateData + off, headerData3, headerSize3); + + sp entry = WebmElement::AudioTrackEntry( + nChannels, + samplerate, + codecPrivateBuf); + return entry; +} + +size_t WebmWriter::numTracks() { + Mutex::Autolock autolock(mLock); + + size_t numTracks = 0; + for (size_t i = 0; i < kMaxStreams; ++i) { + if (mStreams[i].mTrackEntry != NULL) { + numTracks++; + } + } + + return numTracks; +} + +uint64_t WebmWriter::estimateCuesSize(int32_t bitRate) { + // This implementation is based on estimateMoovBoxSize in MPEG4Writer. + // + // Statistical analysis shows that metadata usually accounts + // for a small portion of the total file size, usually < 0.6%. + + // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2, + // where 1MB is the common file size limit for MMS application. + // The default MAX _MOOV_BOX_SIZE value is based on about 3 + // minute video recording with a bit rate about 3 Mbps, because + // statistics also show that most of the video captured are going + // to be less than 3 minutes. + + // If the estimation is wrong, we will pay the price of wasting + // some reserved space. This should not happen so often statistically. + static const int32_t factor = 2; + static const int64_t MIN_CUES_SIZE = 3 * 1024; // 3 KB + static const int64_t MAX_CUES_SIZE = (180 * 3000000 * 6LL / 8000); + int64_t size = MIN_CUES_SIZE; + + // Max file size limit is set + if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { + size = mMaxFileSizeLimitBytes * 6 / 1000; + } + + // Max file duration limit is set + if (mMaxFileDurationLimitUs != 0) { + if (bitRate > 0) { + int64_t size2 = ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000); + if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { + // When both file size and duration limits are set, + // we use the smaller limit of the two. + if (size > size2) { + size = size2; + } + } else { + // Only max file duration limit is set + size = size2; + } + } + } + + if (size < MIN_CUES_SIZE) { + size = MIN_CUES_SIZE; + } + + // Any long duration recording will be probably end up with + // non-streamable webm file. + if (size > MAX_CUES_SIZE) { + size = MAX_CUES_SIZE; + } + + ALOGV("limits: %" PRId64 "/%" PRId64 " bytes/us," + " bit rate: %d bps and the estimated cues size %" PRId64 " bytes", + mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); + return factor * size; +} + +void WebmWriter::initStream(size_t idx) { + if (mStreams[idx].mThread != NULL) { + return; + } + if (mStreams[idx].mSource == NULL) { + ALOGV("adding dummy source ... "); + mStreams[idx].mThread = new WebmFrameEmptySourceThread( + mStreams[idx].mType, mStreams[idx].mSink); + } else { + ALOGV("adding source %p", mStreams[idx].mSource.get()); + mStreams[idx].mThread = new WebmFrameMediaSourceThread( + mStreams[idx].mSource, + mStreams[idx].mType, + mStreams[idx].mSink, + mTimeCodeScale, + mStartTimestampUs, + mStartTimeOffsetMs, + numTracks(), + mIsRealTimeRecording); + } +} + +void WebmWriter::release() { + close(mFd); + mFd = -1; + mInitCheck = NO_INIT; + mStarted = false; +} + +status_t WebmWriter::reset() { + if (mInitCheck != OK) { + return OK; + } else { + if (!mStarted) { + release(); + return OK; + } + } + + status_t err = OK; + int64_t maxDurationUs = 0; + int64_t minDurationUs = 0x7fffffffffffffffLL; + for (int i = 0; i < kMaxStreams; ++i) { + if (mStreams[i].mThread == NULL) { + continue; + } + + status_t status = mStreams[i].mThread->stop(); + if (err == OK && status != OK) { + err = status; + } + + int64_t durationUs = mStreams[i].mThread->getDurationUs(); + if (durationUs > maxDurationUs) { + maxDurationUs = durationUs; + } + if (durationUs < minDurationUs) { + minDurationUs = durationUs; + } + } + + if (numTracks() > 1) { + ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", minDurationUs, maxDurationUs); + } + + mSinkThread->stop(); + + // Do not write out movie header on error. + if (err != OK) { + release(); + return err; + } + + sp cues = new WebmMaster(kMkvCues, mCuePoints); + uint64_t cuesSize = cues->totalSize(); + // TRICKY Even when the cues do fit in the space we reserved, if they do not fit + // perfectly, we still need to check if there is enough "extra space" to write an + // EBML void element. + if (cuesSize != mEstimatedCuesSize && cuesSize > mEstimatedCuesSize - kMinEbmlVoidSize) { + mCuesOffset = ::lseek(mFd, 0, SEEK_CUR); + cues->write(mFd, cuesSize); + } else { + uint64_t spaceSize; + ::lseek(mFd, mCuesOffset, SEEK_SET); + cues->write(mFd, cuesSize); + sp space = new EbmlVoid(mEstimatedCuesSize - cuesSize); + space->write(mFd, spaceSize); + } + + mCuePoints.clear(); + mStreams[kVideoIndex].mSink.clear(); + mStreams[kAudioIndex].mSink.clear(); + + uint8_t bary[sizeof(uint64_t)]; + uint64_t totalSize = ::lseek(mFd, 0, SEEK_END); + uint64_t segmentSize = totalSize - mSegmentDataStart; + ::lseek(mFd, mSegmentOffset + sizeOf(kMkvSegment), SEEK_SET); + uint64_t segmentSizeCoded = encodeUnsigned(segmentSize, sizeOf(kMkvUnknownLength)); + serializeCodedUnsigned(segmentSizeCoded, bary); + ::write(mFd, bary, sizeOf(kMkvUnknownLength)); + + uint64_t size; + uint64_t durationOffset = mInfoOffset + sizeOf(kMkvInfo) + sizeOf(mInfoSize) + + sizeOf(kMkvSegmentDuration) + sizeOf(sizeof(double)); + sp duration = new WebmFloat( + kMkvSegmentDuration, + (double) (maxDurationUs * 1000 / mTimeCodeScale)); + duration->serializePayload(bary); + ::lseek(mFd, durationOffset, SEEK_SET); + ::write(mFd, bary, sizeof(double)); + + List > seekEntries; + seekEntries.push_back(WebmElement::SeekEntry(kMkvInfo, mInfoOffset - mSegmentDataStart)); + seekEntries.push_back(WebmElement::SeekEntry(kMkvTracks, mTracksOffset - mSegmentDataStart)); + seekEntries.push_back(WebmElement::SeekEntry(kMkvCues, mCuesOffset - mSegmentDataStart)); + sp seekHead = new WebmMaster(kMkvSeekHead, seekEntries); + + uint64_t metaSeekSize; + ::lseek(mFd, mSegmentDataStart, SEEK_SET); + seekHead->write(mFd, metaSeekSize); + + uint64_t spaceSize; + sp space = new EbmlVoid(kMaxMetaSeekSize - metaSeekSize); + space->write(mFd, spaceSize); + + release(); + return err; +} + +status_t WebmWriter::addSource(const sp &source) { + Mutex::Autolock l(mLock); + if (mStarted) { + ALOGE("Attempt to add source AFTER recording is started"); + return UNKNOWN_ERROR; + } + + // At most 2 tracks can be supported. + if (mStreams[kVideoIndex].mTrackEntry != NULL + && mStreams[kAudioIndex].mTrackEntry != NULL) { + ALOGE("Too many tracks (2) to add"); + return ERROR_UNSUPPORTED; + } + + CHECK(source != NULL); + + // A track of type other than video or audio is not supported. + const char *mime; + source->getFormat()->findCString(kKeyMIMEType, &mime); + const char *vp8 = MEDIA_MIMETYPE_VIDEO_VP8; + const char *vorbis = MEDIA_MIMETYPE_AUDIO_VORBIS; + + size_t streamIndex; + if (!strncasecmp(mime, vp8, strlen(vp8))) { + streamIndex = kVideoIndex; + } else if (!strncasecmp(mime, vorbis, strlen(vorbis))) { + streamIndex = kAudioIndex; + } else { + ALOGE("Track (%s) other than %s or %s is not supported", mime, vp8, vorbis); + return ERROR_UNSUPPORTED; + } + + // No more than one video or one audio track is supported. + if (mStreams[streamIndex].mTrackEntry != NULL) { + ALOGE("%s track already exists", mStreams[streamIndex].mName); + return ERROR_UNSUPPORTED; + } + + // This is the first track of either audio or video. + // Go ahead to add the track. + mStreams[streamIndex].mSource = source; + mStreams[streamIndex].mTrackEntry = mStreams[streamIndex].mMakeTrack(source->getFormat()); + + return OK; +} + +status_t WebmWriter::start(MetaData *params) { + if (mInitCheck != OK) { + return UNKNOWN_ERROR; + } + + if (mStreams[kVideoIndex].mTrackEntry == NULL + && mStreams[kAudioIndex].mTrackEntry == NULL) { + ALOGE("No source added"); + return INVALID_OPERATION; + } + + if (mMaxFileSizeLimitBytes != 0) { + mIsFileSizeLimitExplicitlyRequested = true; + } + + if (params) { + int32_t isRealTimeRecording; + params->findInt32(kKeyRealTimeRecording, &isRealTimeRecording); + mIsRealTimeRecording = isRealTimeRecording; + } + + if (mStarted) { + if (mPaused) { + mPaused = false; + mStreams[kAudioIndex].mThread->resume(); + mStreams[kVideoIndex].mThread->resume(); + } + return OK; + } + + if (params) { + int32_t tcsl; + if (params->findInt32(kKeyTimeScale, &tcsl)) { + mTimeCodeScale = tcsl; + } + } + CHECK_GT(mTimeCodeScale, 0); + ALOGV("movie time scale: %" PRIu64, mTimeCodeScale); + + /* + * When the requested file size limit is small, the priority + * is to meet the file size limit requirement, rather than + * to make the file streamable. mStreamableFile does not tell + * whether the actual recorded file is streamable or not. + */ + mStreamableFile = (!mMaxFileSizeLimitBytes) + || (mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes); + + /* + * Write various metadata. + */ + sp ebml, segment, info, seekHead, tracks, cues; + ebml = WebmElement::EbmlHeader(); + segment = new WebmMaster(kMkvSegment); + seekHead = new EbmlVoid(kMaxMetaSeekSize); + info = WebmElement::SegmentInfo(mTimeCodeScale, 0); + + List > children; + for (size_t i = 0; i < kMaxStreams; ++i) { + if (mStreams[i].mTrackEntry != NULL) { + children.push_back(mStreams[i].mTrackEntry); + } + } + tracks = new WebmMaster(kMkvTracks, children); + + if (!mStreamableFile) { + cues = NULL; + } else { + int32_t bitRate = -1; + if (params) { + params->findInt32(kKeyBitRate, &bitRate); + } + mEstimatedCuesSize = estimateCuesSize(bitRate); + CHECK_GE(mEstimatedCuesSize, 8); + cues = new EbmlVoid(mEstimatedCuesSize); + } + + sp elems[] = { ebml, segment, seekHead, info, tracks, cues }; + size_t nElems = sizeof(elems) / sizeof(elems[0]); + uint64_t offsets[nElems]; + uint64_t sizes[nElems]; + for (uint32_t i = 0; i < nElems; i++) { + WebmElement *e = elems[i].get(); + if (!e) { + continue; + } + + uint64_t size; + offsets[i] = ::lseek(mFd, 0, SEEK_CUR); + sizes[i] = e->mSize; + e->write(mFd, size); + } + + mSegmentOffset = offsets[1]; + mSegmentDataStart = offsets[2]; + mInfoOffset = offsets[3]; + mInfoSize = sizes[3]; + mTracksOffset = offsets[4]; + mCuesOffset = offsets[5]; + + // start threads + if (params) { + params->findInt64(kKeyTime, &mStartTimestampUs); + } + + initStream(kAudioIndex); + initStream(kVideoIndex); + + mStreams[kAudioIndex].mThread->start(); + mStreams[kVideoIndex].mThread->start(); + mSinkThread->start(); + + mStarted = true; + return OK; +} + +status_t WebmWriter::pause() { + if (mInitCheck != OK) { + return OK; + } + mPaused = true; + status_t err = OK; + for (int i = 0; i < kMaxStreams; ++i) { + if (mStreams[i].mThread == NULL) { + continue; + } + status_t status = mStreams[i].mThread->pause(); + if (status != OK) { + err = status; + } + } + return err; +} + +status_t WebmWriter::stop() { + return reset(); +} + +bool WebmWriter::reachedEOS() { + return !mSinkThread->running(); +} +} /* namespace android */ diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/WebmWriter.h new file mode 100644 index 0000000..529dec8 --- /dev/null +++ b/media/libstagefright/webm/WebmWriter.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2014 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 WEBMWRITER_H_ +#define WEBMWRITER_H_ + +#include "WebmConstants.h" +#include "WebmFrameThread.h" +#include "LinkedBlockingQueue.h" + +#include +#include + +#include +#include +#include + +#include + +using namespace webm; + +namespace android { + +class WebmWriter : public MediaWriter { +public: + WebmWriter(int fd); + WebmWriter(const char *filename); + ~WebmWriter() { reset(); } + + + status_t addSource(const sp &source); + status_t start(MetaData *param = NULL); + status_t stop(); + status_t pause(); + bool reachedEOS(); + + void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; } + int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; } + +private: + int mFd; + status_t mInitCheck; + + uint64_t mTimeCodeScale; + int64_t mStartTimestampUs; + int32_t mStartTimeOffsetMs; + + uint64_t mSegmentOffset; + uint64_t mSegmentDataStart; + uint64_t mInfoOffset; + uint64_t mInfoSize; + uint64_t mTracksOffset; + uint64_t mCuesOffset; + + bool mPaused; + bool mStarted; + bool mIsFileSizeLimitExplicitlyRequested; + bool mIsRealTimeRecording; + bool mStreamableFile; + uint64_t mEstimatedCuesSize; + + Mutex mLock; + List > mCuePoints; + + enum { + kAudioIndex = 0, + kVideoIndex = 1, + kMaxStreams = 2, + }; + + struct WebmStream { + int mType; + const char *mName; + sp (*mMakeTrack)(const sp&); + + sp mSource; + sp mTrackEntry; + sp mThread; + LinkedBlockingQueue > mSink; + + WebmStream() + : mType(kInvalidType), + mName("Invalid"), + mMakeTrack(NULL) { + } + + WebmStream(int type, const char *name, sp (*makeTrack)(const sp&)) + : mType(type), + mName(name), + mMakeTrack(makeTrack) { + } + + WebmStream &operator=(const WebmStream &other) { + mType = other.mType; + mName = other.mName; + mMakeTrack = other.mMakeTrack; + return *this; + } + }; + WebmStream mStreams[kMaxStreams]; + + sp mSinkThread; + + size_t numTracks(); + uint64_t estimateCuesSize(int32_t bitRate); + void initStream(size_t idx); + void release(); + status_t reset(); + + static sp videoTrack(const sp& md); + static sp audioTrack(const sp& md); + + DISALLOW_EVIL_CONSTRUCTORS(WebmWriter); +}; + +} /* namespace android */ +#endif /* WEBMWRITER_H_ */ -- cgit v1.1 From f69f9869514730aebe5724c461768507084dfff7 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 7 Mar 2014 08:37:57 -0800 Subject: NBAIO::Format_from_SR_C requires audio_format_t parameter Change-Id: I4b65f6ed2f6ca3608b3a5f88f52a93af0b9b1f4a --- media/libnbaio/AudioStreamInSource.cpp | 2 +- media/libnbaio/AudioStreamOutSink.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp index cee90dd..80bf61a 100644 --- a/media/libnbaio/AudioStreamInSource.cpp +++ b/media/libnbaio/AudioStreamInSource.cpp @@ -46,7 +46,7 @@ ssize_t AudioStreamInSource::negotiate(const NBAIO_Format offers[], size_t numOf uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common); audio_channel_mask_t channelMask = (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); - mFormat = Format_from_SR_C(sampleRate, popcount(channelMask)); + mFormat = Format_from_SR_C(sampleRate, popcount(channelMask), streamFormat); mFrameSize = Format_frameSize(mFormat); } return NBAIO_Source::negotiate(offers, numOffers, counterOffers, numCounterOffers); diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp index bff06f3..c28d34d 100644 --- a/media/libnbaio/AudioStreamOutSink.cpp +++ b/media/libnbaio/AudioStreamOutSink.cpp @@ -43,7 +43,7 @@ ssize_t AudioStreamOutSink::negotiate(const NBAIO_Format offers[], size_t numOff uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common); audio_channel_mask_t channelMask = (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); - mFormat = Format_from_SR_C(sampleRate, popcount(channelMask)); + mFormat = Format_from_SR_C(sampleRate, popcount(channelMask), streamFormat); mFrameSize = Format_frameSize(mFormat); } return NBAIO_Sink::negotiate(offers, numOffers, counterOffers, numCounterOffers); -- cgit v1.1 From 55e599daff7712142095f546b7e5bf2dcda807a8 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 6 Mar 2014 10:54:55 -0800 Subject: Miscellaneous cleanup for NBAIO Finish removing Format_frameBitShift Fix type of mFrameSize Add FIXME Change-Id: I02039b97cb93af1a180e88f6575210bd752faf20 --- media/libnbaio/NBAIO.cpp | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'media') diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index a669fbb..ff3284c 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -27,16 +27,6 @@ size_t Format_frameSize(const NBAIO_Format& format) return format.mFrameSize; } -#if 0 -int Format_frameBitShift(const NBAIO_Format& format) -{ - // FIXME The sample format is hard-coded to AUDIO_FORMAT_PCM_16_BIT - // sizeof(short) == 2, so frame size == 1 << channels - return Format_channelCount(format); - // FIXME must return -1 for non-power of 2 -} -#endif - const NBAIO_Format Format_Invalid = { 0, 0, AUDIO_FORMAT_INVALID, 0 }; unsigned Format_sampleRate(const NBAIO_Format& format) -- cgit v1.1 From 8dcc81a2fdb35905347cf7ef46d198afa7ae79cd Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Mon, 3 Mar 2014 15:35:36 -0800 Subject: Add empty onSidebandChanged callbacks to BufferQueue::ConsumerListeners Change-Id: I94384aefd47b3a581cbdc3905ba9fdbc88d3d06c --- media/libstagefright/SurfaceMediaSource.cpp | 4 ++++ media/libstagefright/omx/GraphicBufferSource.cpp | 5 +++++ media/libstagefright/omx/GraphicBufferSource.h | 5 +++++ 3 files changed, 14 insertions(+) (limited to 'media') diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index 10c00f4..e7cc46d 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -477,4 +477,8 @@ void SurfaceMediaSource::onBuffersReleased() { } } +void SurfaceMediaSource::onSidebandStreamChanged() { + ALOG_ASSERT(false, "SurfaceMediaSource can't consume sideband streams"); +} + } // end of namespace android diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index b81b116..5bea7a6 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -777,6 +777,11 @@ void GraphicBufferSource::onBuffersReleased() { } } +// BufferQueue::ConsumerListener callback +void GraphicBufferSource::onSidebandStreamChanged() { + ALOG_ASSERT(false, "GraphicBufferSource can't consume sideband streams"); +} + status_t GraphicBufferSource::setRepeatPreviousFrameDelayUs( int64_t repeatAfterUs) { Mutex::Autolock autoLock(mMutex); diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index fba42b7..757edc8 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -143,6 +143,11 @@ protected: // set of mBufferSlot entries. virtual void onBuffersReleased(); + // BufferQueue::ConsumerListener interface, called when the client has + // changed the sideband stream. GraphicBufferSource doesn't handle sideband + // streams so this is a no-op (and should never be called). + virtual void onSidebandStreamChanged(); + private: // Keep track of codec input buffers. They may either be available // (mGraphicBuffer == NULL) or in use by the codec. -- cgit v1.1 From 5ce50c1931e1e3d8f113394bbe2c9f99354f4c5f Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Mon, 3 Mar 2014 15:08:27 -0800 Subject: httplive: clear access units before returning from seekTo. Change-Id: I6a69a718c082501003ee9b78a948a2f8bbfbb14e --- media/libstagefright/httplive/LiveSession.cpp | 26 +++++++++++++++++------ media/libstagefright/httplive/LiveSession.h | 2 ++ media/libstagefright/httplive/PlaylistFetcher.cpp | 25 ++++++++++++++++------ media/libstagefright/httplive/PlaylistFetcher.h | 4 ++-- 4 files changed, 42 insertions(+), 15 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 2af4682..ceb3c8f 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -66,7 +66,8 @@ LiveSession::LiveSession( mRealTimeBaseUs(0ll), mReconfigurationInProgress(false), mSwitchInProgress(false), - mDisconnectReplyID(0) { + mDisconnectReplyID(0), + mSeekReplyID(0) { mStreams[kAudioIndex] = StreamItem("audio"); mStreams[kVideoIndex] = StreamItem("video"); @@ -230,6 +231,10 @@ status_t LiveSession::seekTo(int64_t timeUs) { sp response; status_t err = msg->postAndAwaitResponse(&response); + uint32_t replyID; + CHECK(response == mSeekReply && 0 != mSeekReplyID); + mSeekReply.clear(); + mSeekReplyID = 0; return err; } @@ -255,15 +260,12 @@ void LiveSession::onMessageReceived(const sp &msg) { case kWhatSeek: { - uint32_t replyID; - CHECK(msg->senderAwaitsResponse(&replyID)); + CHECK(msg->senderAwaitsResponse(&mSeekReplyID)); status_t err = onSeek(msg); - sp response = new AMessage; - response->setInt32("err", err); - - response->postReply(replyID); + mSeekReply = new AMessage; + mSeekReply->setInt32("err", err); break; } @@ -293,6 +295,11 @@ void LiveSession::onMessageReceived(const sp &msg) { CHECK_GT(mContinuationCounter, 0); if (--mContinuationCounter == 0) { mContinuation->post(); + + if (mSeekReplyID != 0) { + CHECK(mSeekReply != NULL); + mSeekReply->postReply(mSeekReplyID); + } } } break; @@ -1028,6 +1035,11 @@ void LiveSession::changeConfiguration( if (mContinuationCounter == 0) { msg->post(); + + if (mSeekReplyID != 0) { + CHECK(mSeekReply != NULL); + mSeekReply->postReply(mSeekReplyID); + } } } diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 91bbcea..f489ec4 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -176,6 +176,7 @@ private: size_t mContinuationCounter; sp mContinuation; + sp mSeekReply; int64_t mLastDequeuedTimeUs; int64_t mRealTimeBaseUs; @@ -183,6 +184,7 @@ private: bool mReconfigurationInProgress; bool mSwitchInProgress; uint32_t mDisconnectReplyID; + uint32_t mSeekReplyID; sp addFetcher(const char *uri); diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 1a02e85..b221c0c 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -364,8 +364,10 @@ void PlaylistFetcher::pauseAsync() { (new AMessage(kWhatPause, id()))->post(); } -void PlaylistFetcher::stopAsync() { - (new AMessage(kWhatStop, id()))->post(); +void PlaylistFetcher::stopAsync(bool selfTriggered) { + sp msg = new AMessage(kWhatStop, id()); + msg->setInt32("selfTriggered", selfTriggered); + msg->post(); } void PlaylistFetcher::resumeUntilAsync(const sp ¶ms) { @@ -399,7 +401,7 @@ void PlaylistFetcher::onMessageReceived(const sp &msg) { case kWhatStop: { - onStop(); + onStop(msg); sp notify = mNotify->dup(); notify->setInt32("what", kWhatStopped); @@ -498,9 +500,20 @@ void PlaylistFetcher::onPause() { cancelMonitorQueue(); } -void PlaylistFetcher::onStop() { +void PlaylistFetcher::onStop(const sp &msg) { cancelMonitorQueue(); + int32_t selfTriggered; + CHECK(msg->findInt32("selfTriggered", &selfTriggered)); + if (!selfTriggered) { + // Self triggered stops only happen during switching, in which case we do not want + // to clear the discontinuities queued at the end of packet sources. + for (size_t i = 0; i < mPacketSources.size(); i++) { + sp packetSource = mPacketSources.valueAt(i); + packetSource->clear(); + } + } + mPacketSources.clear(); mStreamTypeMask = 0; } @@ -552,7 +565,7 @@ status_t PlaylistFetcher::onResumeUntil(const sp &msg) { for (size_t i = 0; i < mPacketSources.size(); i++) { mPacketSources.valueAt(i)->queueAccessUnit(mSession->createFormatChangeBuffer()); } - stopAsync(); + stopAsync(/* selfTriggered = */ true); return OK; } @@ -867,7 +880,7 @@ void PlaylistFetcher::onDownloadNext() { if (err == ERROR_OUT_OF_RANGE) { // reached stopping point - stopAsync(); + stopAsync(/* selfTriggered = */ true); return; } diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index 2e0349f..8404b8d 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -63,7 +63,7 @@ struct PlaylistFetcher : public AHandler { void pauseAsync(); - void stopAsync(); + void stopAsync(bool selfTriggered = false); void resumeUntilAsync(const sp ¶ms); @@ -162,7 +162,7 @@ private: status_t onStart(const sp &msg); void onPause(); - void onStop(); + void onStop(const sp &msg); void onMonitorQueue(); void onDownloadNext(); -- cgit v1.1 From 3a90f2849d49bf65f2d6257fd6da30ae46d745fa Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 10 Mar 2014 11:21:43 -0700 Subject: Fix freeze on pause isOffloaded() tries to lock mLock again. We should be calling isOffloaded_l() b/13394633 Change-Id: I155be6fee937f894d8e6c974e593223ab6014ade --- media/libmedia/AudioTrack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 3217171..ae47201 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -555,7 +555,7 @@ void AudioTrack::pause() mProxy->interrupt(); mAudioTrack->pause(); - if (isOffloaded()) { + if (isOffloaded_l()) { if (mOutput != 0) { uint32_t halFrames; // OffloadThread sends HAL pause in its threadLoop.. time saved -- cgit v1.1 From 259f1624cf7b93ba831af10a616267487601c27f Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 21 Feb 2014 15:39:01 -0800 Subject: Revert "NuPlayer: Use a software renderer when using software codecs" Remove software renderer support from NuPlayer because it is included in MediaCodec. Change-Id: I06e001df76df2e18ea8169620ff33aeec57e5ca2 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 27 ++-------------------- media/libmediaplayerservice/nuplayer/NuPlayer.h | 1 - .../nuplayer/NuPlayerRenderer.cpp | 12 ---------- .../nuplayer/NuPlayerRenderer.h | 4 ---- 4 files changed, 2 insertions(+), 42 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index a750ad0..9329f5b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -31,8 +31,6 @@ #include "ATSParser.h" -#include "SoftwareRenderer.h" - #include #include #include @@ -146,7 +144,6 @@ NuPlayer::NuPlayer() : mUIDValid(false), mSourceFlags(0), mVideoIsAVC(false), - mNeedsSwRenderer(false), mAudioEOS(false), mVideoEOS(false), mScanSourcesPending(false), @@ -442,7 +439,6 @@ void NuPlayer::onMessageReceived(const sp &msg) { ALOGV("kWhatStart"); mVideoIsAVC = false; - mNeedsSwRenderer = false; mAudioEOS = false; mVideoEOS = false; mSkipRenderingAudioUntilMediaTimeUs = -1; @@ -679,20 +675,6 @@ void NuPlayer::onMessageReceived(const sp &msg) { notifyListener( MEDIA_SET_VIDEO_SIZE, displayWidth, displayHeight); - - if (mNeedsSwRenderer && mNativeWindow != NULL) { - int32_t colorFormat; - CHECK(codecRequest->findInt32("color-format", &colorFormat)); - - sp meta = new MetaData; - meta->setInt32(kKeyWidth, width); - meta->setInt32(kKeyHeight, height); - meta->setRect(kKeyCropRect, cropLeft, cropTop, cropRight, cropBottom); - meta->setInt32(kKeyColorFormat, colorFormat); - - mRenderer->setSoftRenderer( - new SoftwareRenderer(mNativeWindow->getNativeWindow(), meta)); - } } } else if (what == ACodec::kWhatShutdownCompleted) { ALOGV("%s shutdown completed", audio ? "audio" : "video"); @@ -716,13 +698,8 @@ void NuPlayer::onMessageReceived(const sp &msg) { mRenderer->queueEOS(audio, UNKNOWN_ERROR); } else if (what == ACodec::kWhatDrainThisBuffer) { renderBuffer(audio, codecRequest); - } else if (what == ACodec::kWhatComponentAllocated) { - if (!audio) { - AString name; - CHECK(codecRequest->findString("componentName", &name)); - mNeedsSwRenderer = name.startsWith("OMX.google."); - } - } else if (what != ACodec::kWhatComponentConfigured + } else if (what != ACodec::kWhatComponentAllocated + && what != ACodec::kWhatComponentConfigured && what != ACodec::kWhatBuffersAllocated) { ALOGV("Unhandled codec notification %d '%c%c%c%c'.", what, diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 9dfe4a0..24d746e 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -118,7 +118,6 @@ private: sp mAudioSink; sp mVideoDecoder; bool mVideoIsAVC; - bool mNeedsSwRenderer; sp mAudioDecoder; sp mRenderer; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index bf5271e..a070c1a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -20,8 +20,6 @@ #include "NuPlayerRenderer.h" -#include "SoftwareRenderer.h" - #include #include #include @@ -36,7 +34,6 @@ NuPlayer::Renderer::Renderer( const sp ¬ify, uint32_t flags) : mAudioSink(sink), - mSoftRenderer(NULL), mNotify(notify), mFlags(flags), mNumFramesWritten(0), @@ -60,12 +57,6 @@ NuPlayer::Renderer::Renderer( } NuPlayer::Renderer::~Renderer() { - delete mSoftRenderer; -} - -void NuPlayer::Renderer::setSoftRenderer(SoftwareRenderer *softRenderer) { - delete mSoftRenderer; - mSoftRenderer = softRenderer; } void NuPlayer::Renderer::queueBuffer( @@ -425,9 +416,6 @@ void NuPlayer::Renderer::onDrainVideoQueue() { ALOGV("rendering video at media time %.2f secs", (mFlags & FLAG_REAL_TIME ? realTimeUs : (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6); - if (mSoftRenderer != NULL) { - mSoftRenderer->render(entry->mBuffer->data(), entry->mBuffer->size(), NULL); - } } entry->mNotifyConsumed->setInt32("render", !tooLate); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 9124e03..94a05ea 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -23,7 +23,6 @@ namespace android { struct ABuffer; -class SoftwareRenderer; struct NuPlayer::Renderer : public AHandler { enum Flags { @@ -57,8 +56,6 @@ struct NuPlayer::Renderer : public AHandler { kWhatMediaRenderingStart = 'mdrd', }; - void setSoftRenderer(SoftwareRenderer *softRenderer); - protected: virtual ~Renderer(); @@ -86,7 +83,6 @@ private: static const int64_t kMinPositionUpdateDelayUs; sp mAudioSink; - SoftwareRenderer *mSoftRenderer; sp mNotify; uint32_t mFlags; List mAudioQueue; -- cgit v1.1 From e0381245dff04aa823a59aa8b85869eddab0f39f Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 24 Feb 2014 16:37:24 -0800 Subject: MediaCodec: add getInputFormat() method Additional input-port format item: int32: "adaptive-playback" video decoders only whether codec is configured for adaptive playback. In this case, if codec has max-width/height limits, those limits are also exposed (int32: "max-width", "max-height") Also, getInput/OutputFormat() is now callable in CONFIGURED and STARTING states, although output format may be missing CSD fields until INFO_OUTPUT_FORMAT_CHANGED message. Includes missing OMX support for MP3 software decoder. Bug: 11785204 Change-Id: I90c7e34ba81c7b81c43641599f3f496e838958c6 --- media/libstagefright/ACodec.cpp | 230 ++++++++++++++++--------- media/libstagefright/MediaCodec.cpp | 28 ++- media/libstagefright/codecs/mp3dec/SoftMP3.cpp | 17 ++ 3 files changed, 194 insertions(+), 81 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 9c48587..96c8906 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -365,7 +365,6 @@ ACodec::ACodec() mIsEncoder(false), mUseMetadataOnEncoderOutput(false), mShutdownInProgress(false), - mIsConfiguredForAdaptivePlayback(false), mEncoderDelay(0), mEncoderPadding(0), mChannelMaskPresent(false), @@ -1041,6 +1040,9 @@ status_t ACodec::configureCodec( encoder = false; } + sp inputFormat = new AMessage(); + sp outputFormat = new AMessage(); + mIsEncoder = encoder; status_t err = setComponentRole(encoder /* isEncoder */, mime); @@ -1142,7 +1144,9 @@ status_t ACodec::configureCodec( int32_t haveNativeWindow = msg->findObject("native-window", &obj) && obj != NULL; mStoreMetaDataInOutputBuffers = false; - mIsConfiguredForAdaptivePlayback = false; + if (video && !encoder) { + inputFormat->setInt32("adaptive-playback", false); + } if (!encoder && video && haveNativeWindow) { err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_TRUE); if (err != OK) { @@ -1187,14 +1191,19 @@ status_t ACodec::configureCodec( ALOGW_IF(err != OK, "[%s] prepareForAdaptivePlayback failed w/ err %d", mComponentName.c_str(), err); - mIsConfiguredForAdaptivePlayback = (err == OK); + + if (err == OK) { + inputFormat->setInt32("max-width", maxWidth); + inputFormat->setInt32("max-height", maxHeight); + inputFormat->setInt32("adaptive-playback", true); + } } // allow failure err = OK; } else { ALOGV("[%s] storeMetaDataInBuffers succeeded", mComponentName.c_str()); mStoreMetaDataInOutputBuffers = true; - mIsConfiguredForAdaptivePlayback = true; + inputFormat->setInt32("adaptive-playback", true); } int32_t push; @@ -1334,6 +1343,11 @@ status_t ACodec::configureCodec( err = setMinBufferSize(kPortIndexInput, 8192); // XXX } + CHECK_EQ(getPortFormat(kPortIndexInput, inputFormat), (status_t)OK); + CHECK_EQ(getPortFormat(kPortIndexOutput, outputFormat), (status_t)OK); + mInputFormat = inputFormat; + mOutputFormat = outputFormat; + return err; } @@ -2556,79 +2570,78 @@ void ACodec::processDeferredMessages() { } } -void ACodec::sendFormatChange(const sp &reply) { - sp notify = mNotify->dup(); - notify->setInt32("what", kWhatOutputFormatChanged); - +status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { + // TODO: catch errors an return them instead of using CHECK OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); - def.nPortIndex = kPortIndexOutput; + def.nPortIndex = portIndex; CHECK_EQ(mOMX->getParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)), (status_t)OK); - CHECK_EQ((int)def.eDir, (int)OMX_DirOutput); + CHECK_EQ((int)def.eDir, + (int)(portIndex == kPortIndexOutput ? OMX_DirOutput : OMX_DirInput)); switch (def.eDomain) { case OMX_PortDomainVideo: { OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video; + switch ((int)videoDef->eCompressionFormat) { + case OMX_VIDEO_CodingUnused: + { + CHECK(mIsEncoder ^ (portIndex == kPortIndexOutput)); + notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RAW); + + notify->setInt32("stride", videoDef->nStride); + notify->setInt32("slice-height", videoDef->nSliceHeight); + notify->setInt32("color-format", videoDef->eColorFormat); + + OMX_CONFIG_RECTTYPE rect; + InitOMXParams(&rect); + rect.nPortIndex = kPortIndexOutput; + + if (mOMX->getConfig( + mNode, OMX_IndexConfigCommonOutputCrop, + &rect, sizeof(rect)) != OK) { + rect.nLeft = 0; + rect.nTop = 0; + rect.nWidth = videoDef->nFrameWidth; + rect.nHeight = videoDef->nFrameHeight; + } - AString mime; - if (!mIsEncoder) { - notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RAW); - } else if (GetMimeTypeForVideoCoding( - videoDef->eCompressionFormat, &mime) != OK) { - notify->setString("mime", "application/octet-stream"); - } else { - notify->setString("mime", mime.c_str()); - } - - notify->setInt32("width", videoDef->nFrameWidth); - notify->setInt32("height", videoDef->nFrameHeight); - - if (!mIsEncoder) { - notify->setInt32("stride", videoDef->nStride); - notify->setInt32("slice-height", videoDef->nSliceHeight); - notify->setInt32("color-format", videoDef->eColorFormat); - - OMX_CONFIG_RECTTYPE rect; - InitOMXParams(&rect); - rect.nPortIndex = kPortIndexOutput; - - if (mOMX->getConfig( - mNode, OMX_IndexConfigCommonOutputCrop, - &rect, sizeof(rect)) != OK) { - rect.nLeft = 0; - rect.nTop = 0; - rect.nWidth = videoDef->nFrameWidth; - rect.nHeight = videoDef->nFrameHeight; - } + CHECK_GE(rect.nLeft, 0); + CHECK_GE(rect.nTop, 0); + CHECK_GE(rect.nWidth, 0u); + CHECK_GE(rect.nHeight, 0u); + CHECK_LE(rect.nLeft + rect.nWidth - 1, videoDef->nFrameWidth); + CHECK_LE(rect.nTop + rect.nHeight - 1, videoDef->nFrameHeight); - CHECK_GE(rect.nLeft, 0); - CHECK_GE(rect.nTop, 0); - CHECK_GE(rect.nWidth, 0u); - CHECK_GE(rect.nHeight, 0u); - CHECK_LE(rect.nLeft + rect.nWidth - 1, videoDef->nFrameWidth); - CHECK_LE(rect.nTop + rect.nHeight - 1, videoDef->nFrameHeight); - - notify->setRect( - "crop", - rect.nLeft, - rect.nTop, - rect.nLeft + rect.nWidth - 1, - rect.nTop + rect.nHeight - 1); - - if (mNativeWindow != NULL) { - reply->setRect( + notify->setRect( "crop", rect.nLeft, rect.nTop, - rect.nLeft + rect.nWidth, - rect.nTop + rect.nHeight); + rect.nLeft + rect.nWidth - 1, + rect.nTop + rect.nHeight - 1); + + break; + } + default: + { + CHECK(mIsEncoder ^ (portIndex == kPortIndexInput)); + AString mime; + if (GetMimeTypeForVideoCoding( + videoDef->eCompressionFormat, &mime) != OK) { + notify->setString("mime", "application/octet-stream"); + } else { + notify->setString("mime", mime.c_str()); + } + break; } } + + notify->setInt32("width", videoDef->nFrameWidth); + notify->setInt32("height", videoDef->nFrameHeight); break; } @@ -2641,7 +2654,7 @@ void ACodec::sendFormatChange(const sp &reply) { { OMX_AUDIO_PARAM_PCMMODETYPE params; InitOMXParams(¶ms); - params.nPortIndex = kPortIndexOutput; + params.nPortIndex = portIndex; CHECK_EQ(mOMX->getParameter( mNode, OMX_IndexParamAudioPcm, @@ -2661,20 +2674,6 @@ void ACodec::sendFormatChange(const sp &reply) { notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RAW); notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSamplingRate); - if (mEncoderDelay + mEncoderPadding) { - size_t frameSize = params.nChannels * sizeof(int16_t); - if (mSkipCutBuffer != NULL) { - size_t prevbufsize = mSkipCutBuffer->size(); - if (prevbufsize != 0) { - ALOGW("Replacing SkipCutBuffer holding %d " - "bytes", - prevbufsize); - } - } - mSkipCutBuffer = new SkipCutBuffer( - mEncoderDelay * frameSize, - mEncoderPadding * frameSize); - } if (mChannelMaskPresent) { notify->setInt32("channel-mask", mChannelMask); @@ -2686,7 +2685,7 @@ void ACodec::sendFormatChange(const sp &reply) { { OMX_AUDIO_PARAM_AACPROFILETYPE params; InitOMXParams(¶ms); - params.nPortIndex = kPortIndexOutput; + params.nPortIndex = portIndex; CHECK_EQ(mOMX->getParameter( mNode, OMX_IndexParamAudioAac, @@ -2703,7 +2702,7 @@ void ACodec::sendFormatChange(const sp &reply) { { OMX_AUDIO_PARAM_AMRTYPE params; InitOMXParams(¶ms); - params.nPortIndex = kPortIndexOutput; + params.nPortIndex = portIndex; CHECK_EQ(mOMX->getParameter( mNode, OMX_IndexParamAudioAmr, @@ -2729,7 +2728,7 @@ void ACodec::sendFormatChange(const sp &reply) { { OMX_AUDIO_PARAM_FLACTYPE params; InitOMXParams(¶ms); - params.nPortIndex = kPortIndexOutput; + params.nPortIndex = portIndex; CHECK_EQ(mOMX->getParameter( mNode, OMX_IndexParamAudioFlac, @@ -2742,11 +2741,45 @@ void ACodec::sendFormatChange(const sp &reply) { break; } + case OMX_AUDIO_CodingMP3: + { + OMX_AUDIO_PARAM_MP3TYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + CHECK_EQ(mOMX->getParameter( + mNode, OMX_IndexParamAudioMp3, + ¶ms, sizeof(params)), + (status_t)OK); + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_MPEG); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSampleRate); + break; + } + + case OMX_AUDIO_CodingVORBIS: + { + OMX_AUDIO_PARAM_VORBISTYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + CHECK_EQ(mOMX->getParameter( + mNode, OMX_IndexParamAudioVorbis, + ¶ms, sizeof(params)), + (status_t)OK); + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_VORBIS); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSampleRate); + break; + } + case OMX_AUDIO_CodingAndroidAC3: { OMX_AUDIO_PARAM_ANDROID_AC3TYPE params; InitOMXParams(¶ms); - params.nPortIndex = kPortIndexOutput; + params.nPortIndex = portIndex; CHECK_EQ((status_t)OK, mOMX->getParameter( mNode, @@ -2761,6 +2794,7 @@ void ACodec::sendFormatChange(const sp &reply) { } default: + ALOGE("UNKNOWN AUDIO CODING: %d\n", audioDef->eEncoding); TRESPASS(); } break; @@ -2770,6 +2804,43 @@ void ACodec::sendFormatChange(const sp &reply) { TRESPASS(); } + return OK; +} + +void ACodec::sendFormatChange(const sp &reply) { + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatOutputFormatChanged); + + CHECK_EQ(getPortFormat(kPortIndexOutput, notify), (status_t)OK); + + AString mime; + CHECK(notify->findString("mime", &mime)); + + int32_t left, top, right, bottom; + if (mime == MEDIA_MIMETYPE_VIDEO_RAW && + mNativeWindow != NULL && + notify->findRect("crop", &left, &top, &right, &bottom)) { + // notify renderer of the crop change + // NOTE: native window uses extended right-bottom coordinate + reply->setRect("crop", left, top, right + 1, bottom + 1); + } else if (mime == MEDIA_MIMETYPE_AUDIO_RAW && + (mEncoderDelay || mEncoderPadding)) { + int32_t channelCount; + CHECK(notify->findInt32("channel-count", &channelCount)); + size_t frameSize = channelCount * sizeof(int16_t); + if (mSkipCutBuffer != NULL) { + size_t prevbufsize = mSkipCutBuffer->size(); + if (prevbufsize != 0) { + ALOGW("Replacing SkipCutBuffer holding %d " + "bytes", + prevbufsize); + } + } + mSkipCutBuffer = new SkipCutBuffer( + mEncoderDelay * frameSize, + mEncoderPadding * frameSize); + } + notify->post(); mSentFormat = true; @@ -3799,7 +3870,8 @@ void ACodec::LoadedState::stateEntered() { mCodec->mDequeueCounter = 0; mCodec->mMetaDataBuffersToSubmit = 0; mCodec->mRepeatFrameDelayUs = -1ll; - mCodec->mIsConfiguredForAdaptivePlayback = false; + mCodec->mInputFormat.clear(); + mCodec->mOutputFormat.clear(); if (mCodec->mShutdownInProgress) { bool keepComponentAllocated = mCodec->mKeepComponentAllocated; @@ -3913,6 +3985,8 @@ bool ACodec::LoadedState::onConfigureComponent( { sp notify = mCodec->mNotify->dup(); notify->setInt32("what", ACodec::kWhatComponentConfigured); + notify->setMessage("input-format", mCodec->mInputFormat); + notify->setMessage("output-format", mCodec->mOutputFormat); notify->post(); } diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index fe21296..e0419ca 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -352,6 +352,20 @@ status_t MediaCodec::getOutputFormat(sp *format) const { return OK; } +status_t MediaCodec::getInputFormat(sp *format) const { + sp msg = new AMessage(kWhatGetInputFormat, id()); + + sp response; + status_t err; + if ((err = PostAndAwaitResponse(msg, &response)) != OK) { + return err; + } + + CHECK(response->findMessage("format", format)); + + return OK; +} + status_t MediaCodec::getName(AString *name) const { sp msg = new AMessage(kWhatGetName, id()); @@ -642,6 +656,9 @@ void MediaCodec::onMessageReceived(const sp &msg) { // reset input surface flag mHaveInputSurface = false; + CHECK(msg->findMessage("input-format", &mInputFormat)); + CHECK(msg->findMessage("output-format", &mOutputFormat)); + (new AMessage)->postReply(mReplyID); break; } @@ -1330,14 +1347,19 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } + case kWhatGetInputFormat: case kWhatGetOutputFormat: { + sp format = + (msg->what() == kWhatGetOutputFormat ? mOutputFormat : mInputFormat); + uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if ((mState != STARTED && mState != FLUSHING) + if ((mState != CONFIGURED && mState != STARTING && + mState != STARTED && mState != FLUSHING) || (mFlags & kFlagStickyError) - || mOutputFormat == NULL) { + || format == NULL) { sp response = new AMessage; response->setInt32("err", INVALID_OPERATION); @@ -1346,7 +1368,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { } sp response = new AMessage; - response->setMessage("format", mOutputFormat); + response->setMessage("format", format); response->postReply(replyID); break; } diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp index a09ab7c..5396022 100644 --- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp +++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp @@ -146,6 +146,23 @@ OMX_ERRORTYPE SoftMP3::internalGetParameter( return OMX_ErrorNone; } + case OMX_IndexParamAudioMp3: + { + OMX_AUDIO_PARAM_MP3TYPE *mp3Params = + (OMX_AUDIO_PARAM_MP3TYPE *)params; + + if (mp3Params->nPortIndex > 1) { + return OMX_ErrorUndefined; + } + + mp3Params->nChannels = mNumChannels; + mp3Params->nBitRate = 0 /* unknown */; + mp3Params->nSampleRate = mSamplingRate; + // other fields are encoder-only + + return OMX_ErrorNone; + } + default: return SimpleSoftOMXComponent::internalGetParameter(index, params); } -- cgit v1.1 From 1cd139824b2e6832f239cd27d8962d3239053c02 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 17 Jan 2014 15:12:51 -0800 Subject: NuPlayer: use MediaCodec instead of ACodec Bug: 11785204 Change-Id: I1455bfc683469c7a69e565b179aceacbc5c459f5 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 50 ++- media/libmediaplayerservice/nuplayer/NuPlayer.h | 1 - .../nuplayer/NuPlayerDecoder.cpp | 459 +++++++++++++++++---- .../nuplayer/NuPlayerDecoder.h | 44 +- 4 files changed, 446 insertions(+), 108 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 9329f5b..d8d939a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -529,24 +528,21 @@ void NuPlayer::onMessageReceived(const sp &msg) { { bool audio = msg->what() == kWhatAudioNotify; - sp codecRequest; - CHECK(msg->findMessage("codec-request", &codecRequest)); - int32_t what; - CHECK(codecRequest->findInt32("what", &what)); + CHECK(msg->findInt32("what", &what)); - if (what == ACodec::kWhatFillThisBuffer) { + if (what == Decoder::kWhatFillThisBuffer) { status_t err = feedDecoderInputData( - audio, codecRequest); + audio, msg); if (err == -EWOULDBLOCK) { if (mSource->feedMoreTSData() == OK) { msg->post(10000ll); } } - } else if (what == ACodec::kWhatEOS) { + } else if (what == Decoder::kWhatEOS) { int32_t err; - CHECK(codecRequest->findInt32("err", &err)); + CHECK(msg->findInt32("err", &err)); if (err == ERROR_END_OF_STREAM) { ALOGV("got %s decoder EOS", audio ? "audio" : "video"); @@ -557,7 +553,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { } mRenderer->queueEOS(audio, err); - } else if (what == ACodec::kWhatFlushCompleted) { + } else if (what == Decoder::kWhatFlushCompleted) { bool needShutdown; if (audio) { @@ -586,14 +582,17 @@ void NuPlayer::onMessageReceived(const sp &msg) { } finishFlushIfPossible(); - } else if (what == ACodec::kWhatOutputFormatChanged) { + } else if (what == Decoder::kWhatOutputFormatChanged) { + sp format; + CHECK(msg->findMessage("format", &format)); + if (audio) { int32_t numChannels; - CHECK(codecRequest->findInt32( + CHECK(format->findInt32( "channel-count", &numChannels)); int32_t sampleRate; - CHECK(codecRequest->findInt32("sample-rate", &sampleRate)); + CHECK(format->findInt32("sample-rate", &sampleRate)); ALOGV("Audio output format changed to %d Hz, %d channels", sampleRate, numChannels); @@ -617,7 +616,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { } int32_t channelMask; - if (!codecRequest->findInt32("channel-mask", &channelMask)) { + if (!format->findInt32("channel-mask", &channelMask)) { channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; } @@ -638,11 +637,11 @@ void NuPlayer::onMessageReceived(const sp &msg) { // video int32_t width, height; - CHECK(codecRequest->findInt32("width", &width)); - CHECK(codecRequest->findInt32("height", &height)); + CHECK(format->findInt32("width", &width)); + CHECK(format->findInt32("height", &height)); int32_t cropLeft, cropTop, cropRight, cropBottom; - CHECK(codecRequest->findRect( + CHECK(format->findRect( "crop", &cropLeft, &cropTop, &cropRight, &cropBottom)); @@ -676,7 +675,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { notifyListener( MEDIA_SET_VIDEO_SIZE, displayWidth, displayHeight); } - } else if (what == ACodec::kWhatShutdownCompleted) { + } else if (what == Decoder::kWhatShutdownCompleted) { ALOGV("%s shutdown completed", audio ? "audio" : "video"); if (audio) { mAudioDecoder.clear(); @@ -691,17 +690,15 @@ void NuPlayer::onMessageReceived(const sp &msg) { } finishFlushIfPossible(); - } else if (what == ACodec::kWhatError) { + } else if (what == Decoder::kWhatError) { ALOGE("Received error from %s decoder, aborting playback.", audio ? "audio" : "video"); mRenderer->queueEOS(audio, UNKNOWN_ERROR); - } else if (what == ACodec::kWhatDrainThisBuffer) { - renderBuffer(audio, codecRequest); - } else if (what != ACodec::kWhatComponentAllocated - && what != ACodec::kWhatComponentConfigured - && what != ACodec::kWhatBuffersAllocated) { - ALOGV("Unhandled codec notification %d '%c%c%c%c'.", + } else if (what == Decoder::kWhatDrainThisBuffer) { + renderBuffer(audio, msg); + } else { + ALOGV("Unhandled decoder notification %d '%c%c%c%c'.", what, what >> 24, (what >> 16) & 0xff, @@ -902,8 +899,7 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp *decoder) { *decoder = audio ? new Decoder(notify) : new Decoder(notify, mNativeWindow); - looper()->registerHandler(*decoder); - + (*decoder)->init(); (*decoder)->configure(format); return OK; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 24d746e..f1d3d55 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -24,7 +24,6 @@ namespace android { -struct ACodec; struct MetaData; struct NuPlayerDriver; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 2423fd5..469c9ca 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -17,14 +17,17 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "NuPlayerDecoder" #include +#include #include "NuPlayerDecoder.h" +#include #include #include #include -#include +#include #include +#include namespace android { @@ -32,122 +35,425 @@ NuPlayer::Decoder::Decoder( const sp ¬ify, const sp &nativeWindow) : mNotify(notify), - mNativeWindow(nativeWindow) { + mNativeWindow(nativeWindow), + mBufferGeneration(0), + mComponentName("decoder") { + // Every decoder has its own looper because MediaCodec operations + // are blocking, but NuPlayer needs asynchronous operations. + mDecoderLooper = new ALooper; + mDecoderLooper->setName("NuPlayerDecoder"); + mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO); + + mCodecLooper = new ALooper; + mCodecLooper->setName("NuPlayerDecoder-MC"); + mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO); } NuPlayer::Decoder::~Decoder() { } -void NuPlayer::Decoder::configure(const sp &format) { +void NuPlayer::Decoder::onConfigure(const sp &format) { CHECK(mCodec == NULL); + ++mBufferGeneration; + AString mime; CHECK(format->findString("mime", &mime)); - sp notifyMsg = - new AMessage(kWhatCodecNotify, id()); + sp surface = NULL; + if (mNativeWindow != NULL) { + surface = mNativeWindow->getSurfaceTextureClient(); + } - mCSDIndex = 0; - for (size_t i = 0;; ++i) { - sp csd; - if (!format->findBuffer(StringPrintf("csd-%d", i).c_str(), &csd)) { - break; - } + mComponentName = mime; + mComponentName.append(" decoder"); + ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get()); - mCSD.push(csd); + mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */); + if (mCodec == NULL) { + ALOGE("Failed to create %s decoder", mime.c_str()); + handleError(UNKNOWN_ERROR); + return; } + mCodec->getName(&mComponentName); + if (mNativeWindow != NULL) { - format->setObject("native-window", mNativeWindow); + // disconnect from surface as MediaCodec will reconnect + CHECK_EQ((int)NO_ERROR, + native_window_api_disconnect( + surface.get(), + NATIVE_WINDOW_API_MEDIA)); + } + status_t err = mCodec->configure( + format, surface, NULL /* crypto */, 0 /* flags */); + if (err != OK) { + ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err); + handleError(err); + return; + } + // the following should work in configured state + CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat)); + CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat)); + + err = mCodec->start(); + if (err != OK) { + ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err); + handleError(err); + return; } - // Current video decoders do not return from OMX_FillThisBuffer - // quickly, violating the OpenMAX specs, until that is remedied - // we need to invest in an extra looper to free the main event - // queue. - bool needDedicatedLooper = !strncasecmp(mime.c_str(), "video/", 6); + // the following should work after start + CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers)); + CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers)); + ALOGV("[%s] got %zu input and %zu output buffers", + mComponentName.c_str(), + mInputBuffers.size(), + mOutputBuffers.size()); - mFormat = format; - mCodec = new ACodec; + requestCodecNotification(); +} - if (needDedicatedLooper && mCodecLooper == NULL) { - mCodecLooper = new ALooper; - mCodecLooper->setName("NuPlayerDecoder"); - mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO); +void NuPlayer::Decoder::requestCodecNotification() { + if (mCodec != NULL) { + sp reply = new AMessage(kWhatCodecNotify, id()); + reply->setInt32("generation", mBufferGeneration); + mCodec->requestActivityNotification(reply); } +} - (needDedicatedLooper ? mCodecLooper : looper())->registerHandler(mCodec); +bool NuPlayer::Decoder::isStaleReply(const sp &msg) { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + return generation != mBufferGeneration; +} - mCodec->setNotificationMessage(notifyMsg); - mCodec->initiateSetup(format); +void NuPlayer::Decoder::init() { + mDecoderLooper->registerHandler(this); } -void NuPlayer::Decoder::onMessageReceived(const sp &msg) { - switch (msg->what()) { - case kWhatCodecNotify: - { - int32_t what; - CHECK(msg->findInt32("what", &what)); - - if (what == ACodec::kWhatFillThisBuffer) { - onFillThisBuffer(msg); - } else { - sp notify = mNotify->dup(); - notify->setMessage("codec-request", msg); - notify->post(); - } - break; +void NuPlayer::Decoder::configure(const sp &format) { + sp msg = new AMessage(kWhatConfigure, id()); + msg->setMessage("format", format); + msg->post(); +} + +void NuPlayer::Decoder::handleError(int32_t err) +{ + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatError); + notify->setInt32("err", err); + notify->post(); +} + +bool NuPlayer::Decoder::handleAnInputBuffer() { + size_t bufferIx = -1; + status_t res = mCodec->dequeueInputBuffer(&bufferIx); + ALOGV("[%s] dequeued input: %d", + mComponentName.c_str(), res == OK ? (int)bufferIx : res); + if (res != OK) { + if (res != -EAGAIN) { + handleError(res); } + return false; + } - default: - TRESPASS(); - break; + CHECK_LT(bufferIx, mInputBuffers.size()); + + sp reply = new AMessage(kWhatInputBufferFilled, id()); + reply->setSize("buffer-ix", bufferIx); + reply->setInt32("generation", mBufferGeneration); + + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatFillThisBuffer); + notify->setBuffer("buffer", mInputBuffers[bufferIx]); + notify->setMessage("reply", reply); + notify->post(); + return true; +} + +void android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { + size_t bufferIx; + CHECK(msg->findSize("buffer-ix", &bufferIx)); + CHECK_LT(bufferIx, mInputBuffers.size()); + sp codecBuffer = mInputBuffers[bufferIx]; + + sp buffer; + bool hasBuffer = msg->findBuffer("buffer", &buffer); + if (buffer == NULL /* includes !hasBuffer */) { + int32_t streamErr = ERROR_END_OF_STREAM; + CHECK(msg->findInt32("err", &streamErr) || !hasBuffer); + + if (streamErr == OK) { + /* buffers are returned to hold on to */ + return; + } + + // attempt to queue EOS + status_t err = mCodec->queueInputBuffer( + bufferIx, + 0, + 0, + 0, + MediaCodec::BUFFER_FLAG_EOS); + if (streamErr == ERROR_END_OF_STREAM && err != OK) { + streamErr = err; + // err will not be ERROR_END_OF_STREAM + } + + if (streamErr != ERROR_END_OF_STREAM) { + handleError(streamErr); + } + } else { + int64_t timeUs = 0; + uint32_t flags = 0; + CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); + + int32_t eos; + // we do not expect CODECCONFIG or SYNCFRAME for decoder + if (buffer->meta()->findInt32("eos", &eos) && eos) { + flags |= MediaCodec::BUFFER_FLAG_EOS; + } + + // copy into codec buffer + if (buffer != codecBuffer) { + CHECK_LE(buffer->size(), codecBuffer->capacity()); + codecBuffer->setRange(0, buffer->size()); + memcpy(codecBuffer->data(), buffer->data(), buffer->size()); + } + + status_t err = mCodec->queueInputBuffer( + bufferIx, + codecBuffer->offset(), + codecBuffer->size(), + timeUs, + flags); + if (err != OK) { + ALOGE("Failed to queue input buffer for %s (err=%d)", + mComponentName.c_str(), err); + handleError(err); + } } } -void NuPlayer::Decoder::onFillThisBuffer(const sp &msg) { - sp reply; - CHECK(msg->findMessage("reply", &reply)); +bool NuPlayer::Decoder::handleAnOutputBuffer() { + size_t bufferIx = -1; + size_t offset; + size_t size; + int64_t timeUs; + uint32_t flags; + status_t res = mCodec->dequeueOutputBuffer( + &bufferIx, &offset, &size, &timeUs, &flags); + + if (res != OK) { + ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res); + } else { + ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")", + mComponentName.c_str(), (int)bufferIx, timeUs, flags); + } -#if 0 - sp outBuffer; - CHECK(msg->findBuffer("buffer", &outBuffer)); -#else - sp outBuffer; -#endif + if (res == INFO_OUTPUT_BUFFERS_CHANGED) { + res = mCodec->getOutputBuffers(&mOutputBuffers); + if (res != OK) { + ALOGE("Failed to get output buffers for %s after INFO event (err=%d)", + mComponentName.c_str(), res); + handleError(res); + return false; + } + // NuPlayer ignores this + return true; + } else if (res == INFO_FORMAT_CHANGED) { + sp format = new AMessage(); + res = mCodec->getOutputFormat(&format); + if (res != OK) { + ALOGE("Failed to get output format for %s after INFO event (err=%d)", + mComponentName.c_str(), res); + handleError(res); + return false; + } - if (mCSDIndex < mCSD.size()) { - outBuffer = mCSD.editItemAt(mCSDIndex++); - outBuffer->meta()->setInt64("timeUs", 0); + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatOutputFormatChanged); + notify->setMessage("format", format); + notify->post(); + return true; + } else if (res == INFO_DISCONTINUITY) { + // nothing to do + return true; + } else if (res != OK) { + if (res != -EAGAIN) { + handleError(res); + } + return false; + } - reply->setBuffer("buffer", outBuffer); - reply->post(); - return; + CHECK_LT(bufferIx, mOutputBuffers.size()); + sp buffer = mOutputBuffers[bufferIx]; + buffer->setRange(offset, size); + buffer->meta()->clear(); + buffer->meta()->setInt64("timeUs", timeUs); + if (flags & MediaCodec::BUFFER_FLAG_EOS) { + buffer->meta()->setInt32("eos", true); } + // we do not expect CODECCONFIG or SYNCFRAME for decoder + + sp reply = new AMessage(kWhatRenderBuffer, id()); + reply->setSize("buffer-ix", bufferIx); + reply->setInt32("generation", mBufferGeneration); sp notify = mNotify->dup(); - notify->setMessage("codec-request", msg); + notify->setInt32("what", kWhatDrainThisBuffer); + notify->setBuffer("buffer", buffer); + notify->setMessage("reply", reply); notify->post(); + + // FIXME: This should be handled after rendering is complete, + // but Renderer needs it now + if (flags & MediaCodec::BUFFER_FLAG_EOS) { + ALOGV("queueing eos [%s]", mComponentName.c_str()); + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatEOS); + notify->setInt32("err", ERROR_END_OF_STREAM); + notify->post(); + } + return true; } -void NuPlayer::Decoder::signalFlush() { - if (mCodec != NULL) { - mCodec->signalFlush(); +void NuPlayer::Decoder::onRenderBuffer(const sp &msg) { + status_t err; + int32_t render; + size_t bufferIx; + CHECK(msg->findSize("buffer-ix", &bufferIx)); + if (msg->findInt32("render", &render) && render) { + err = mCodec->renderOutputBufferAndRelease(bufferIx); + } else { + err = mCodec->releaseOutputBuffer(bufferIx); + } + if (err != OK) { + ALOGE("failed to release output buffer for %s (err=%d)", + mComponentName.c_str(), err); + handleError(err); } } -void NuPlayer::Decoder::signalResume() { +void NuPlayer::Decoder::onFlush() { + status_t err = OK; if (mCodec != NULL) { - mCodec->signalResume(); + err = mCodec->flush(); + ++mBufferGeneration; } + + if (err != OK) { + ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err); + handleError(err); + return; + } + + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatFlushCompleted); + notify->post(); } -void NuPlayer::Decoder::initiateShutdown() { +void NuPlayer::Decoder::onShutdown() { + status_t err = OK; if (mCodec != NULL) { - mCodec->initiateShutdown(); + err = mCodec->release(); + mCodec = NULL; + ++mBufferGeneration; + + if (mNativeWindow != NULL) { + // reconnect to surface as MediaCodec disconnected from it + CHECK_EQ((int)NO_ERROR, + native_window_api_connect( + mNativeWindow->getNativeWindow().get(), + NATIVE_WINDOW_API_MEDIA)); + } + mComponentName = "decoder"; + } + + if (err != OK) { + ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err); + handleError(err); + return; + } + + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatShutdownCompleted); + notify->post(); +} + +void NuPlayer::Decoder::onMessageReceived(const sp &msg) { + ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str()); + + switch (msg->what()) { + case kWhatConfigure: + { + sp format; + CHECK(msg->findMessage("format", &format)); + onConfigure(format); + break; + } + + case kWhatCodecNotify: + { + if (!isStaleReply(msg)) { + while (handleAnInputBuffer()) { + } + + while (handleAnOutputBuffer()) { + } + } + + requestCodecNotification(); + break; + } + + case kWhatInputBufferFilled: + { + if (!isStaleReply(msg)) { + onInputBufferFilled(msg); + } + break; + } + + case kWhatRenderBuffer: + { + if (!isStaleReply(msg)) { + onRenderBuffer(msg); + } + break; + } + + case kWhatFlush: + { + onFlush(); + break; + } + + case kWhatShutdown: + { + onShutdown(); + break; + } + + default: + TRESPASS(); + break; } } +void NuPlayer::Decoder::signalFlush() { + (new AMessage(kWhatFlush, id()))->post(); +} + +void NuPlayer::Decoder::signalResume() { + // nothing to do +} + +void NuPlayer::Decoder::initiateShutdown() { + (new AMessage(kWhatShutdown, id()))->post(); +} + bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp &targetFormat) const { if (targetFormat == NULL) { return true; @@ -163,14 +469,16 @@ bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp &ta const char * keys[] = { "channel-count", "sample-rate", "is-adts" }; for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) { int32_t oldVal, newVal; - if (!mFormat->findInt32(keys[i], &oldVal) || !targetFormat->findInt32(keys[i], &newVal) - || oldVal != newVal) { + if (!mOutputFormat->findInt32(keys[i], &oldVal) || + !targetFormat->findInt32(keys[i], &newVal) || + oldVal != newVal) { return false; } } sp oldBuf, newBuf; - if (mFormat->findBuffer("csd-0", &oldBuf) && targetFormat->findBuffer("csd-0", &newBuf)) { + if (mOutputFormat->findBuffer("csd-0", &oldBuf) && + targetFormat->findBuffer("csd-0", &newBuf)) { if (oldBuf->size() != newBuf->size()) { return false; } @@ -181,7 +489,7 @@ bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp &ta } bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp &targetFormat) const { - if (mFormat == NULL) { + if (mOutputFormat == NULL) { return false; } @@ -190,7 +498,7 @@ bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp &targetF } AString oldMime, newMime; - if (!mFormat->findString("mime", &oldMime) + if (!mOutputFormat->findString("mime", &oldMime) || !targetFormat->findString("mime", &newMime) || !(oldMime == newMime)) { return false; @@ -201,7 +509,10 @@ bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp &targetF if (audio) { seamless = supportsSeamlessAudioFormatChange(targetFormat); } else { - seamless = mCodec != NULL && mCodec->isConfiguredForAdaptivePlayback(); + int32_t isAdaptive; + seamless = (mCodec != NULL && + mInputFormat->findInt32("adaptive-playback", &isAdaptive) && + isAdaptive); } ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str()); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index 78ea74a..94243fc 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -25,12 +25,14 @@ namespace android { struct ABuffer; +struct MediaCodec; struct NuPlayer::Decoder : public AHandler { Decoder(const sp ¬ify, const sp &nativeWindow = NULL); void configure(const sp &format); + void init(); void signalFlush(); void signalResume(); @@ -38,7 +40,18 @@ struct NuPlayer::Decoder : public AHandler { bool supportsSeamlessFormatChange(const sp &to) const; + enum { + kWhatFillThisBuffer = 'flTB', + kWhatDrainThisBuffer = 'drTB', + kWhatOutputFormatChanged = 'fmtC', + kWhatFlushCompleted = 'flsC', + kWhatShutdownCompleted = 'shDC', + kWhatEOS = 'eos ', + kWhatError = 'err ', + }; + protected: + virtual ~Decoder(); virtual void onMessageReceived(const sp &msg); @@ -46,21 +59,40 @@ protected: private: enum { kWhatCodecNotify = 'cdcN', + kWhatConfigure = 'conf', + kWhatInputBufferFilled = 'inpF', + kWhatRenderBuffer = 'rndr', + kWhatFlush = 'flus', + kWhatShutdown = 'shuD', }; sp mNotify; sp mNativeWindow; - sp mFormat; - sp mCodec; + sp mInputFormat; + sp mOutputFormat; + sp mCodec; sp mCodecLooper; + sp mDecoderLooper; + + Vector > mInputBuffers; + Vector > mOutputBuffers; + + void handleError(int32_t err); + bool handleAnInputBuffer(); + bool handleAnOutputBuffer(); - Vector > mCSD; - size_t mCSDIndex; + void requestCodecNotification(); + bool isStaleReply(const sp &msg); - sp makeFormat(const sp &meta); + void onConfigure(const sp &format); + void onFlush(); + void onInputBufferFilled(const sp &msg); + void onRenderBuffer(const sp &msg); + void onShutdown(); - void onFillThisBuffer(const sp &msg); + int32_t mBufferGeneration; + AString mComponentName; bool supportsSeamlessAudioFormatChange(const sp &targetFormat) const; -- cgit v1.1 From 1ac1638077277de52d1dd4c54db71e67753f1960 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Mon, 10 Mar 2014 17:05:01 -0700 Subject: M3UParser: trim spaces when parsing comma separated codecs. Bug: 13402087 Change-Id: Idc92716bfefd6d1b0cb371d0d97d990d53288090 --- media/libstagefright/httplive/M3UParser.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'media') diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 587a6d5..87918c8 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -365,6 +365,7 @@ bool M3UParser::getTypeURI(size_t index, const char *key, AString *uri) const { codecs.append(','); while ((commaPos = codecs.find(",", offset)) >= 0) { AString codec(codecs, offset, commaPos - offset); + codec.trim(); // return true only if a codec of type `key` ("audio"/"video") // is found. if (codecIsType(codec, key)) { -- cgit v1.1 From e4f25c280a8f1655c31a745978e0fcbc61f91dee Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Mon, 10 Mar 2014 17:27:15 -0700 Subject: LiveSession: fix incorrect stream key (subtitle"s") Bug: 13402087 Change-Id: Ic46e3069c6e41f90ead47cae84cbe0123d11002a --- media/libstagefright/httplive/LiveSession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index ceb3c8f..dd396e7 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -71,7 +71,7 @@ LiveSession::LiveSession( mStreams[kAudioIndex] = StreamItem("audio"); mStreams[kVideoIndex] = StreamItem("video"); - mStreams[kSubtitleIndex] = StreamItem("subtitle"); + mStreams[kSubtitleIndex] = StreamItem("subtitles"); for (size_t i = 0; i < kMaxStreams; ++i) { mPacketSources.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); -- cgit v1.1 From c7e5040aa8b8e4da86814bf560346c7571e48087 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 6 Mar 2014 14:35:55 -0800 Subject: move audio policy service to a separate library Change-Id: Ibc3ef07aa9860b7fd4f9aaff27b0dbe0dcbf1cbf --- media/mediaserver/Android.mk | 2 ++ 1 file changed, 2 insertions(+) (limited to 'media') diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk index f848054..9335a84 100644 --- a/media/mediaserver/Android.mk +++ b/media/mediaserver/Android.mk @@ -15,6 +15,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libaudioflinger \ + libaudiopolicy \ libcamera_metadata\ libcameraservice \ libmedialogservice \ @@ -33,6 +34,7 @@ LOCAL_C_INCLUDES := \ frameworks/av/media/libmediaplayerservice \ frameworks/av/services/medialog \ frameworks/av/services/audioflinger \ + frameworks/av/services/audiopolicy \ frameworks/av/services/camera/libcameraservice LOCAL_MODULE:= mediaserver -- cgit v1.1 From e257e5ebefdd50f808ee3b4d1596db261c9b62dd Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 13 Feb 2014 15:29:49 -0800 Subject: mediaplayer: keep more buffers with the BufferQueue Change OMX buffer allocation policy to allocate nBufferCountMin + what is required for the BQ. For the BQ, try to allocate 2 additional buffers than the minimum undequeued count. Also account for the fact that BQ may return one less than the actual minimum undequeued count. In most cases the resulting number of buffers ends up being the same as with the previous policy, but we keep more buffers with the BQ. Change-Id: I826db8bf7dd333b620299dba60bf1b81b228275d Bug: 12080418 --- media/libstagefright/ACodec.cpp | 47 ++++++++++++++++++++++----------------- media/libstagefright/OMXCodec.cpp | 38 +++++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 30 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 9c48587..72c5da5 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -643,18 +643,33 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( return err; } - // XXX: Is this the right logic to use? It's not clear to me what the OMX - // buffer counts refer to - how do they account for the renderer holding on - // to buffers? - if (def.nBufferCountActual < def.nBufferCountMin + *minUndequeuedBuffers) { - OMX_U32 newBufferCount = def.nBufferCountMin + *minUndequeuedBuffers; + // FIXME: assume that surface is controlled by app (native window + // returns the number for the case when surface is not controlled by app) + (*minUndequeuedBuffers)++; + + + // Use conservative allocation while also trying to reduce starvation + // + // 1. allocate at least nBufferCountMin + minUndequeuedBuffers - that is the + // minimum needed for the consumer to be able to work + // 2. try to allocate two (2) additional buffers to reduce starvation from + // the consumer + for (OMX_U32 extraBuffers = 2; /* condition inside loop */; extraBuffers--) { + OMX_U32 newBufferCount = + def.nBufferCountMin + *minUndequeuedBuffers + extraBuffers; def.nBufferCountActual = newBufferCount; err = mOMX->setParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - if (err != OK) { - ALOGE("[%s] setting nBufferCountActual to %lu failed: %d", - mComponentName.c_str(), newBufferCount, err); + if (err == OK) { + *minUndequeuedBuffers += extraBuffers; + break; + } + + ALOGW("[%s] setting nBufferCountActual to %lu failed: %d", + mComponentName.c_str(), newBufferCount, err); + /* exit condition */ + if (extraBuffers == 0) { return err; } } @@ -679,6 +694,7 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { &bufferCount, &bufferSize, &minUndequeuedBuffers); if (err != 0) return err; + mNumUndequeuedBuffers = minUndequeuedBuffers; ALOGV("[%s] Allocating %lu buffers from a native window of size %lu on " "output port", @@ -744,6 +760,7 @@ status_t ACodec::allocateOutputMetaDataBuffers() { &bufferCount, &bufferSize, &minUndequeuedBuffers); if (err != 0) return err; + mNumUndequeuedBuffers = minUndequeuedBuffers; ALOGV("[%s] Allocating %lu meta buffers on output port", mComponentName.c_str(), bufferCount); @@ -2498,19 +2515,7 @@ void ACodec::waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs() { return; } - int minUndequeuedBufs = 0; - status_t err = mNativeWindow->query( - mNativeWindow.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - &minUndequeuedBufs); - - if (err != OK) { - ALOGE("[%s] NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)", - mComponentName.c_str(), strerror(-err), -err); - - minUndequeuedBufs = 0; - } - - while (countBuffersOwnedByNativeWindow() > (size_t)minUndequeuedBufs + while (countBuffersOwnedByNativeWindow() > mNumUndequeuedBuffers && dequeueBufferFromNativeWindow() != NULL) { // these buffers will be submitted as regular buffers; account for this if (mStoreMetaDataInOutputBuffers && mMetaDataBuffersToSubmit > 0) { diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 4d3b5bd..545ca9d 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -94,6 +94,7 @@ static sp InstantiateSoftwareEncoder( #define CODEC_LOGI(x, ...) ALOGI("[%s] "x, mComponentName, ##__VA_ARGS__) #define CODEC_LOGV(x, ...) ALOGV("[%s] "x, mComponentName, ##__VA_ARGS__) +#define CODEC_LOGW(x, ...) ALOGW("[%s] "x, mComponentName, ##__VA_ARGS__) #define CODEC_LOGE(x, ...) ALOGE("[%s] "x, mComponentName, ##__VA_ARGS__) struct OMXCodecObserver : public BnOMXObserver { @@ -1803,21 +1804,40 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { strerror(-err), -err); return err; } - - // XXX: Is this the right logic to use? It's not clear to me what the OMX - // buffer counts refer to - how do they account for the renderer holding on - // to buffers? - if (def.nBufferCountActual < def.nBufferCountMin + minUndequeuedBufs) { - OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs; + // FIXME: assume that surface is controlled by app (native window + // returns the number for the case when surface is not controlled by app) + minUndequeuedBufs++; + + // Use conservative allocation while also trying to reduce starvation + // + // 1. allocate at least nBufferCountMin + minUndequeuedBuffers - that is the + // minimum needed for the consumer to be able to work + // 2. try to allocate two (2) additional buffers to reduce starvation from + // the consumer + CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d", + def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs); + + for (OMX_U32 extraBuffers = 2; /* condition inside loop */; extraBuffers--) { + OMX_U32 newBufferCount = + def.nBufferCountMin + minUndequeuedBufs + extraBuffers; def.nBufferCountActual = newBufferCount; err = mOMX->setParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - if (err != OK) { - CODEC_LOGE("setting nBufferCountActual to %lu failed: %d", - newBufferCount, err); + + if (err == OK) { + minUndequeuedBufs += extraBuffers; + break; + } + + CODEC_LOGW("setting nBufferCountActual to %lu failed: %d", + newBufferCount, err); + /* exit condition */ + if (extraBuffers == 0) { return err; } } + CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d", + def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs); err = native_window_set_buffer_count( mNativeWindow.get(), def.nBufferCountActual); -- cgit v1.1 From 0fa848d780cf990a2860637f40432d28594c85a3 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Fri, 7 Mar 2014 13:29:59 -0800 Subject: MTP: Add support for device property changed events Also fixed bug in MtpProperty::write() for device properties Bug: 7342482 Change-Id: If0099095d101409d131564e55b1939895c69c202 --- media/mtp/MtpProperty.cpp | 4 ++-- media/mtp/MtpServer.cpp | 6 ++++++ media/mtp/MtpServer.h | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/mtp/MtpProperty.cpp b/media/mtp/MtpProperty.cpp index 375ed9a..3838ce8 100644 --- a/media/mtp/MtpProperty.cpp +++ b/media/mtp/MtpProperty.cpp @@ -190,9 +190,9 @@ void MtpProperty::write(MtpDataPacket& packet) { if (deviceProp) writeValue(packet, mCurrentValue); } - packet.putUInt32(mGroupCode); if (!deviceProp) - packet.putUInt8(mFormFlag); + packet.putUInt32(mGroupCode); + packet.putUInt8(mFormFlag); if (mFormFlag == kFormRange) { writeValue(packet, mMinimumValue); writeValue(packet, mMaximumValue); diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp index df87db4..dadfb54 100644 --- a/media/mtp/MtpServer.cpp +++ b/media/mtp/MtpServer.cpp @@ -93,6 +93,7 @@ static const MtpEventCode kSupportedEventCodes[] = { MTP_EVENT_OBJECT_REMOVED, MTP_EVENT_STORE_ADDED, MTP_EVENT_STORE_REMOVED, + MTP_EVENT_DEVICE_PROP_CHANGED, }; MtpServer::MtpServer(int fd, MtpDatabase* database, bool ptp, @@ -261,6 +262,11 @@ void MtpServer::sendStoreRemoved(MtpStorageID id) { sendEvent(MTP_EVENT_STORE_REMOVED, id); } +void MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) { + ALOGV("sendDevicePropertyChanged %d\n", property); + sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property); +} + void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) { if (mSessionOpen) { mEvent.setEventCode(code); diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h index dfa8258..b3a11e0 100644 --- a/media/mtp/MtpServer.h +++ b/media/mtp/MtpServer.h @@ -104,6 +104,7 @@ public: void sendObjectAdded(MtpObjectHandle handle); void sendObjectRemoved(MtpObjectHandle handle); + void sendDevicePropertyChanged(MtpDeviceProperty property); private: void sendStoreAdded(MtpStorageID id); -- cgit v1.1 From 5205977929c8a63d3bba026c6bd7b4cc1e236627 Mon Sep 17 00:00:00 2001 From: Dan Stoza Date: Wed, 12 Mar 2014 15:07:30 -0700 Subject: Remove deprecated BufferQueue constructor Bug: 13415624 Change-Id: I1a824d09ce582ee54753683d30cdc23813c13b6b --- media/libstagefright/SurfaceMediaSource.cpp | 20 ++++++------ media/libstagefright/omx/GraphicBufferSource.cpp | 36 +++++++++++----------- media/libstagefright/omx/GraphicBufferSource.h | 9 ++++-- .../tests/SurfaceMediaSource_test.cpp | 10 +++--- .../wifi-display/source/PlaybackSession.cpp | 4 +-- .../wifi-display/source/PlaybackSession.h | 3 +- 6 files changed, 41 insertions(+), 41 deletions(-) (limited to 'media') diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index e7cc46d..62aea36 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -54,9 +54,9 @@ SurfaceMediaSource::SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeig ALOGE("Invalid dimensions %dx%d", bufferWidth, bufferHeight); } - mBufferQueue = new BufferQueue(); - mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight); - mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER | + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + mConsumer->setDefaultBufferSize(bufferWidth, bufferHeight); + mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_HW_TEXTURE); sp composer(ComposerService::getComposerService()); @@ -68,7 +68,7 @@ SurfaceMediaSource::SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeig wp listener = static_cast(this); sp proxy = new BufferQueue::ProxyConsumerListener(listener); - status_t err = mBufferQueue->consumerConnect(proxy, false); + status_t err = mConsumer->consumerConnect(proxy, false); if (err != NO_ERROR) { ALOGE("SurfaceMediaSource: error connecting to BufferQueue: %s (%d)", strerror(-err), err); @@ -108,7 +108,7 @@ void SurfaceMediaSource::dump( Mutex::Autolock lock(mMutex); result.append(buffer); - mBufferQueue->dump(result, ""); + mConsumer->dump(result, ""); } status_t SurfaceMediaSource::setFrameRate(int32_t fps) @@ -166,7 +166,7 @@ status_t SurfaceMediaSource::start(MetaData *params) CHECK_GT(mMaxAcquiredBufferCount, 1); status_t err = - mBufferQueue->setMaxAcquiredBufferCount(mMaxAcquiredBufferCount); + mConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBufferCount); if (err != OK) { return err; @@ -223,7 +223,7 @@ status_t SurfaceMediaSource::stop() mMediaBuffersAvailableCondition.signal(); - return mBufferQueue->consumerDisconnect(); + return mConsumer->consumerDisconnect(); } sp SurfaceMediaSource::getFormat() @@ -293,7 +293,7 @@ status_t SurfaceMediaSource::read( // wait here till the frames come in from the client side while (mStarted) { - status_t err = mBufferQueue->acquireBuffer(&item, 0); + status_t err = mConsumer->acquireBuffer(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { // wait for a buffer to be queued mFrameAvailableCondition.wait(mMutex); @@ -316,7 +316,7 @@ status_t SurfaceMediaSource::read( if (mStartTimeNs > 0) { if (item.mTimestamp < mStartTimeNs) { // This frame predates start of record, discard - mBufferQueue->releaseBuffer( + mConsumer->releaseBuffer( item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); continue; @@ -416,7 +416,7 @@ void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) { ALOGV("Slot %d returned, matches handle = %p", id, mSlots[id].mGraphicBuffer->handle); - mBufferQueue->releaseBuffer(id, mSlots[id].mFrameNumber, + mConsumer->releaseBuffer(id, mSlots[id].mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 5bea7a6..1be76b3 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -68,13 +68,13 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, String8 name("GraphicBufferSource"); - mBufferQueue = new BufferQueue(); - mBufferQueue->setConsumerName(name); - mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight); - mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER | + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + mConsumer->setConsumerName(name); + mConsumer->setDefaultBufferSize(bufferWidth, bufferHeight); + mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_HW_TEXTURE); - mInitCheck = mBufferQueue->setMaxAcquiredBufferCount(bufferCount); + mInitCheck = mConsumer->setMaxAcquiredBufferCount(bufferCount); if (mInitCheck != NO_ERROR) { ALOGE("Unable to set BQ max acquired buffer count to %u: %d", bufferCount, mInitCheck); @@ -88,7 +88,7 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, wp listener = static_cast(this); sp proxy = new BufferQueue::ProxyConsumerListener(listener); - mInitCheck = mBufferQueue->consumerConnect(proxy, false); + mInitCheck = mConsumer->consumerConnect(proxy, false); if (mInitCheck != NO_ERROR) { ALOGE("Error connecting to BufferQueue: %s (%d)", strerror(-mInitCheck), mInitCheck); @@ -100,8 +100,8 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, GraphicBufferSource::~GraphicBufferSource() { ALOGV("~GraphicBufferSource"); - if (mBufferQueue != NULL) { - status_t err = mBufferQueue->consumerDisconnect(); + if (mConsumer != NULL) { + status_t err = mConsumer->consumerDisconnect(); if (err != NO_ERROR) { ALOGW("consumerDisconnect failed: %d", err); } @@ -273,7 +273,7 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { if (id == mLatestSubmittedBufferId) { CHECK_GT(mLatestSubmittedBufferUseCount--, 0); } else { - mBufferQueue->releaseBuffer(id, codecBuffer.mFrameNumber, + mConsumer->releaseBuffer(id, codecBuffer.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); } } else { @@ -342,7 +342,7 @@ void GraphicBufferSource::suspend(bool suspend) { while (mNumFramesAvailable > 0) { BufferQueue::BufferItem item; - status_t err = mBufferQueue->acquireBuffer(&item, 0); + status_t err = mConsumer->acquireBuffer(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { // shouldn't happen. @@ -355,7 +355,7 @@ void GraphicBufferSource::suspend(bool suspend) { --mNumFramesAvailable; - mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, + mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); } return; @@ -392,7 +392,7 @@ bool GraphicBufferSource::fillCodecBuffer_l() { ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%d", mNumFramesAvailable); BufferQueue::BufferItem item; - status_t err = mBufferQueue->acquireBuffer(&item, 0); + status_t err = mConsumer->acquireBuffer(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { // shouldn't happen ALOGW("fillCodecBuffer_l: frame was not available"); @@ -433,7 +433,7 @@ bool GraphicBufferSource::fillCodecBuffer_l() { if (err != OK) { ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf); - mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, + mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); } else { ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi); @@ -456,7 +456,7 @@ bool GraphicBufferSource::repeatLatestSubmittedBuffer_l() { // // To be on the safe side we try to release the buffer. ALOGD("repeatLatestSubmittedBuffer_l: slot was NULL"); - mBufferQueue->releaseBuffer( + mConsumer->releaseBuffer( mLatestSubmittedBufferId, mLatestSubmittedBufferFrameNum, EGL_NO_DISPLAY, @@ -510,7 +510,7 @@ void GraphicBufferSource::setLatestSubmittedBuffer_l( if (mLatestSubmittedBufferId >= 0) { if (mLatestSubmittedBufferUseCount == 0) { - mBufferQueue->releaseBuffer( + mConsumer->releaseBuffer( mLatestSubmittedBufferId, mLatestSubmittedBufferFrameNum, EGL_NO_DISPLAY, @@ -733,7 +733,7 @@ void GraphicBufferSource::onFrameAvailable() { } BufferQueue::BufferItem item; - status_t err = mBufferQueue->acquireBuffer(&item, 0); + status_t err = mConsumer->acquireBuffer(&item, 0); if (err == OK) { // If this is the first time we're seeing this buffer, add it to our // slot table. @@ -741,7 +741,7 @@ void GraphicBufferSource::onFrameAvailable() { ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mBuf); mBufferSlot[item.mBuf] = item.mGraphicBuffer; } - mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, + mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); } return; @@ -762,7 +762,7 @@ void GraphicBufferSource::onBuffersReleased() { Mutex::Autolock lock(mMutex); uint32_t slotMask; - if (mBufferQueue->getReleasedBuffers(&slotMask) != NO_ERROR) { + if (mConsumer->getReleasedBuffers(&slotMask) != NO_ERROR) { ALOGW("onBuffersReleased: unable to get released buffer set"); slotMask = 0xffffffff; } diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index 757edc8..a70cc1a 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -61,7 +61,7 @@ public: // Returns the handle to the producer side of the BufferQueue. Buffers // queued on this will be received by GraphicBufferSource. sp getIGraphicBufferProducer() const { - return mBufferQueue; + return mProducer; } // This is called when OMX transitions to OMX_StateExecuting, which means @@ -210,8 +210,11 @@ private: bool mSuspended; - // We consume graphic buffers from this. - sp mBufferQueue; + // Our BufferQueue interfaces. mProducer is passed to the producer through + // getIGraphicBufferProducer, and mConsumer is used internally to retrieve + // the buffers queued by the producer. + sp mProducer; + sp mConsumer; // Number of frames pending in BufferQueue that haven't yet been // forwarded to the codec. diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp index a3093d0..fd889f9 100644 --- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp +++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp @@ -109,7 +109,7 @@ protected: } else { ALOGV("No actual display. Choosing EGLSurface based on SurfaceMediaSource"); sp sms = (new SurfaceMediaSource( - getSurfaceWidth(), getSurfaceHeight()))->getBufferQueue(); + getSurfaceWidth(), getSurfaceHeight()))->getProducer(); sp stc = new Surface(sms); sp window = stc; @@ -360,9 +360,7 @@ protected: virtual void SetUp() { android::ProcessState::self()->startThreadPool(); mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight); - - // Manual cast is required to avoid constructor ambiguity - mSTC = new Surface(static_cast >( mSMS->getBufferQueue())); + mSTC = new Surface(mSMS->getProducer()); mANW = mSTC; } @@ -397,7 +395,7 @@ protected: ALOGV("SMS-GLTest::SetUp()"); android::ProcessState::self()->startThreadPool(); mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight); - mSTC = new Surface(static_cast >( mSMS->getBufferQueue())); + mSTC = new Surface(mSMS->getProducer()); mANW = mSTC; // Doing the setup related to the GL Side @@ -782,7 +780,7 @@ TEST_F(SurfaceMediaSourceGLTest, ChooseAndroidRecordableEGLConfigDummyWriter) { ALOGV("Verify creating a surface w/ right config + dummy writer*********"); mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight); - mSTC = new Surface(static_cast >( mSMS->getBufferQueue())); + mSTC = new Surface(mSMS->getProducer()); mANW = mSTC; DummyRecorder writer(mSMS); diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp index 1a5acba..2cb4786 100644 --- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp +++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp @@ -1055,7 +1055,7 @@ status_t WifiDisplaySource::PlaybackSession::addVideoSource( err = source->setMaxAcquiredBufferCount(numInputBuffers); CHECK_EQ(err, (status_t)OK); - mBufferQueue = source->getBufferQueue(); + mProducer = source->getProducer(); return OK; } @@ -1079,7 +1079,7 @@ status_t WifiDisplaySource::PlaybackSession::addAudioSource(bool usePCMAudio) { } sp WifiDisplaySource::PlaybackSession::getSurfaceTexture() { - return mBufferQueue; + return mProducer; } void WifiDisplaySource::PlaybackSession::requestIDRFrame() { diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.h b/media/libstagefright/wifi-display/source/PlaybackSession.h index 5c8ee94..2824143 100644 --- a/media/libstagefright/wifi-display/source/PlaybackSession.h +++ b/media/libstagefright/wifi-display/source/PlaybackSession.h @@ -25,7 +25,6 @@ namespace android { struct ABuffer; -struct BufferQueue; struct IHDCP; struct IGraphicBufferProducer; struct MediaPuller; @@ -111,7 +110,7 @@ private: int64_t mLastLifesignUs; - sp mBufferQueue; + sp mProducer; KeyedVector > mTracks; ssize_t mVideoTrackIndex; -- cgit v1.1 From c5a17425986b4ce3384e6956762c86018b49c4a0 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 13 Mar 2014 14:59:59 -0700 Subject: Remove name output parameter from createTrack It was only used for one log. A better solution will be a per-track unique ID. Change-Id: Ia440e02ae4a5a4019a9a2d08970e1ee93ac4c3a3 --- media/libmedia/AudioTrack.cpp | 4 +--- media/libmedia/IAudioFlinger.cpp | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 60ed626..20c1cdb 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1024,7 +1024,6 @@ status_t AudioTrack::createTrack_l(size_t epoch) output, tid, &mSessionId, - mName, mClientUid, &status); @@ -1281,8 +1280,7 @@ void AudioTrack::releaseBuffer(Buffer* audioBuffer) if (mState == STATE_ACTIVE) { audio_track_cblk_t* cblk = mCblk; if (android_atomic_and(~CBLK_DISABLED, &cblk->mFlags) & CBLK_DISABLED) { - ALOGW("releaseBuffer() track %p name=%s disabled due to previous underrun, restarting", - this, mName.string()); + ALOGW("releaseBuffer() track %p disabled due to previous underrun, restarting", this); // FIXME ignoring status mAudioTrack->start(); } diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index a9a9f1a..762681e 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -95,7 +95,6 @@ public: audio_io_handle_t output, pid_t tid, int *sessionId, - String8& name, int clientUid, status_t *status) { @@ -140,7 +139,6 @@ public: if (sessionId != NULL) { *sessionId = lSessionId; } - name = reply.readString8(); lStatus = reply.readInt32(); track = interface_cast(reply.readStrongBinder()); if (lStatus == NO_ERROR) { @@ -808,7 +806,6 @@ status_t BnAudioFlinger::onTransact( pid_t tid = (pid_t) data.readInt32(); int sessionId = data.readInt32(); int clientUid = data.readInt32(); - String8 name; status_t status; sp track; if ((haveSharedBuffer && (buffer == 0)) || @@ -819,13 +816,12 @@ status_t BnAudioFlinger::onTransact( track = createTrack( (audio_stream_type_t) streamType, sampleRate, format, channelMask, &frameCount, &flags, buffer, output, tid, - &sessionId, name, clientUid, &status); + &sessionId, clientUid, &status); LOG_ALWAYS_FATAL_IF((track != 0) != (status == NO_ERROR)); } reply->writeInt32(frameCount); reply->writeInt32(flags); reply->writeInt32(sessionId); - reply->writeString8(name); reply->writeInt32(status); reply->writeStrongBinder(track->asBinder()); return NO_ERROR; -- cgit v1.1 From bfd55f243feb3f04e26ad07aae035475768ada8a Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 18 Mar 2014 14:00:39 -0700 Subject: Use more tags to help the ICU detector. The detector only gave non-ascii data to ICU. In some cases that could result in very short data, for which ICU would issue a low confidence level for the actual encoding. By padding the data with additional (ascii) tags, we improve accuracy for such files. Becauses this can reduce accuracy in other cases, only do this when the initial confidence is low. b/13473604 Change-Id: I63d932043155c310b0e358cdf2d37787961e94b7 --- media/libmedia/CharacterEncodingDetector.cpp | 115 ++++++++++++++++++++++----- media/libmedia/CharacterEncodingDetector.h | 4 +- 2 files changed, 99 insertions(+), 20 deletions(-) (limited to 'media') diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp index eb091ac..5a3bf9d 100644 --- a/media/libmedia/CharacterEncodingDetector.cpp +++ b/media/libmedia/CharacterEncodingDetector.cpp @@ -90,6 +90,7 @@ void CharacterEncodingDetector::detectAndConvert() { char buf[1024]; buf[0] = 0; int idx; + bool allprintable = true; for (int i = 0; i < size; i++) { const char *name = mNames.getEntry(i); const char *value = mValues.getEntry(i); @@ -103,18 +104,60 @@ void CharacterEncodingDetector::detectAndConvert() { strlcat(buf, value, sizeof(buf)); // separate tags by space so ICU's ngram detector can do its job strlcat(buf, " ", sizeof(buf)); + allprintable = false; } } - ucsdet_setText(csd, buf, strlen(buf), &status); - int32_t matches; - const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status); - const char *combinedenc = "???"; - - const UCharsetMatch* bestCombinedMatch = getPreferred(buf, strlen(buf), ucma, matches); + const char *combinedenc = "UTF-8"; + if (allprintable) { + // since 'buf' is empty, ICU would return a UTF-8 matcher with low confidence, so + // no need to even call it + ALOGV("all tags are printable, assuming ascii (%d)", strlen(buf)); + } else { + ucsdet_setText(csd, buf, strlen(buf), &status); + int32_t matches; + const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status); + bool goodmatch = true; + const UCharsetMatch* bestCombinedMatch = getPreferred(buf, strlen(buf), + ucma, matches, &goodmatch); + + if (!goodmatch && strlen(buf) < 20) { + ALOGV("not a good match, trying with more data"); + // This string might be too short for ICU to do anything useful with. + // (real world example: "Björk" in ISO-8859-1 might be detected as GB18030, because + // the ISO detector reports a confidence of 0, while the GB18030 detector reports + // a confidence of 10 with no invalid characters) + // Append artist, album and title if they were previously omitted because they + // were printable ascii. + bool added = false; + for (int i = 0; i < size; i++) { + const char *name = mNames.getEntry(i); + const char *value = mValues.getEntry(i); + if (isPrintableAscii(value, strlen(value)) && ( + !strcmp(name, "artist") || + !strcmp(name, "album") || + !strcmp(name, "title"))) { + strlcat(buf, value, sizeof(buf)); + strlcat(buf, " ", sizeof(buf)); + added = true; + } + } + if (added) { + ucsdet_setText(csd, buf, strlen(buf), &status); + ucma = ucsdet_detectAll(csd, &matches, &status); + bestCombinedMatch = getPreferred(buf, strlen(buf), + ucma, matches, &goodmatch); + if (!goodmatch) { + ALOGV("still not a good match after adding printable tags"); + } + } else { + ALOGV("no printable tags to add"); + } + } - if (bestCombinedMatch != NULL) { - combinedenc = ucsdet_getName(bestCombinedMatch, &status); + if (bestCombinedMatch != NULL) { + combinedenc = ucsdet_getName(bestCombinedMatch, &status); + } } for (int i = 0; i < size; i++) { @@ -128,7 +171,7 @@ void CharacterEncodingDetector::detectAndConvert() { int32_t inputLength = strlen(s); const char *enc; - if (!strcmp(name, "artist") || + if (!allprintable && !strcmp(name, "artist") || !strcmp(name, "albumartist") || !strcmp(name, "composer") || !strcmp(name, "genre") || @@ -137,15 +180,20 @@ void CharacterEncodingDetector::detectAndConvert() { // use encoding determined from the combination of artist/album/title etc. enc = combinedenc; } else { - ucsdet_setText(csd, s, inputLength, &status); - ucm = ucsdet_detect(csd, &status); - if (!ucm) { - mValues.setEntry(i, "???"); - continue; + if (isPrintableAscii(s, inputLength)) { + enc = "UTF-8"; + ALOGV("@@@@ %s is ascii", mNames.getEntry(i)); + } else { + ucsdet_setText(csd, s, inputLength, &status); + ucm = ucsdet_detect(csd, &status); + if (!ucm) { + mValues.setEntry(i, "???"); + continue; + } + enc = ucsdet_getName(ucm, &status); + ALOGV("@@@@ recognized charset: %s for %s confidence %d", + enc, mNames.getEntry(i), ucsdet_getConfidence(ucm, &status)); } - enc = ucsdet_getName(ucm, &status); - ALOGV("@@@@ recognized charset: %s for %s confidence %d", - enc, mNames.getEntry(i), ucsdet_getConfidence(ucm, &status)); } if (strcmp(enc,"UTF-8") != 0) { @@ -207,10 +255,15 @@ void CharacterEncodingDetector::detectAndConvert() { * algorithm and larger frequent character lists than ICU * - devalue encoding where the conversion contains unlikely characters (symbols, reserved, etc) * - pick the highest match + * - signal to the caller whether this match is considered good: confidence > 15, and confidence + * delta with the next runner up > 15 */ const UCharsetMatch *CharacterEncodingDetector::getPreferred( - const char *input, size_t len, const UCharsetMatch** ucma, size_t nummatches) { + const char *input, size_t len, + const UCharsetMatch** ucma, size_t nummatches, + bool *goodmatch) { + *goodmatch = false; Vector matches; UErrorCode status = U_ZERO_ERROR; @@ -227,6 +280,10 @@ const UCharsetMatch *CharacterEncodingDetector::getPreferred( return NULL; } if (num == 1) { + int confidence = ucsdet_getConfidence(matches[0], &status); + if (confidence > 15) { + *goodmatch = true; + } return matches[0]; } @@ -326,15 +383,35 @@ const UCharsetMatch *CharacterEncodingDetector::getPreferred( // find match with highest confidence after adjusting for unlikely characters int highest = newconfidence[0]; size_t highestidx = 0; + int runnerup = -10000; + int runnerupidx = -10000; num = newconfidence.size(); for (size_t i = 1; i < num; i++) { if (newconfidence[i] > highest) { + runnerup = highest; + runnerupidx = highestidx; highest = newconfidence[i]; highestidx = i; + } else if (newconfidence[i] > runnerup){ + runnerup = newconfidence[i]; + runnerupidx = i; } } status = U_ZERO_ERROR; - ALOGV("selecting '%s' w/ %d confidence", ucsdet_getName(matches[highestidx], &status), highest); + ALOGV("selecting: '%s' w/ %d confidence", + ucsdet_getName(matches[highestidx], &status), highest); + if (runnerupidx < 0) { + ALOGV("no runner up"); + if (highest > 15) { + *goodmatch = true; + } + } else { + ALOGV("runner up: '%s' w/ %d confidence", + ucsdet_getName(matches[runnerupidx], &status), runnerup); + if ((highest - runnerup) > 15) { + *goodmatch = true; + } + } return matches[highestidx]; } diff --git a/media/libmedia/CharacterEncodingDetector.h b/media/libmedia/CharacterEncodingDetector.h index 3655a91..7b5ed86 100644 --- a/media/libmedia/CharacterEncodingDetector.h +++ b/media/libmedia/CharacterEncodingDetector.h @@ -41,7 +41,9 @@ class CharacterEncodingDetector { private: const UCharsetMatch *getPreferred( - const char *input, size_t len, const UCharsetMatch** ucma, size_t matches); + const char *input, size_t len, + const UCharsetMatch** ucma, size_t matches, + bool *goodmatch); bool isFrequent(const uint16_t *values, uint32_t c); -- cgit v1.1 From d74110cdef2becd4f7fd2334c34c3ca73f56b355 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Tue, 18 Mar 2014 19:46:52 -0700 Subject: stagefright: add include support for MediaCodecList xml parser One can include full-formed XML files using . For security/simplicity, file names must be in the form of "media_codecs_.*\.xml" Change-Id: Id039a4fd0ade390224485fcf5ecc1d107b2bdb9a --- media/libstagefright/MediaCodecList.cpp | 142 +++++++++++++++++++++++--------- 1 file changed, 104 insertions(+), 38 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index 6248e90..8a451c8 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -48,22 +48,43 @@ const MediaCodecList *MediaCodecList::getInstance() { MediaCodecList::MediaCodecList() : mInitCheck(NO_INIT) { - FILE *file = fopen("/etc/media_codecs.xml", "r"); + parseTopLevelXMLFile("/etc/media_codecs.xml"); +} - if (file == NULL) { - ALOGW("unable to open media codecs configuration xml file."); +void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml) { + // get href_base + char *href_base_end = strrchr(codecs_xml, '/'); + if (href_base_end != NULL) { + mHrefBase = AString(codecs_xml, href_base_end - codecs_xml + 1); + } + + mInitCheck = OK; + mCurrentSection = SECTION_TOPLEVEL; + mDepth = 0; + + parseXMLFile(codecs_xml); + + if (mInitCheck != OK) { + mCodecInfos.clear(); + mCodecQuirks.clear(); return; } - parseXMLFile(file); + // These are currently still used by the video editing suite. + addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm"); + addMediaCodec( + false /* encoder */, "OMX.google.raw.decoder", "audio/raw"); - if (mInitCheck == OK) { - // These are currently still used by the video editing suite. + for (size_t i = mCodecInfos.size(); i-- > 0;) { + CodecInfo *info = &mCodecInfos.editItemAt(i); - addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm"); + if (info->mTypes == 0) { + // No types supported by this component??? + ALOGW("Component %s does not support any type of media?", + info->mName.c_str()); - addMediaCodec( - false /* encoder */, "OMX.google.raw.decoder", "audio/raw"); + mCodecInfos.removeAt(i); + } } #if 0 @@ -84,9 +105,6 @@ MediaCodecList::MediaCodecList() ALOGI("%s", line.c_str()); } #endif - - fclose(file); - file = NULL; } MediaCodecList::~MediaCodecList() { @@ -96,10 +114,14 @@ status_t MediaCodecList::initCheck() const { return mInitCheck; } -void MediaCodecList::parseXMLFile(FILE *file) { - mInitCheck = OK; - mCurrentSection = SECTION_TOPLEVEL; - mDepth = 0; +void MediaCodecList::parseXMLFile(const char *path) { + FILE *file = fopen(path, "r"); + + if (file == NULL) { + ALOGW("unable to open media codecs configuration xml file: %s", path); + mInitCheck = NAME_NOT_FOUND; + return; + } XML_Parser parser = ::XML_ParserCreate(NULL); CHECK(parser != NULL); @@ -112,7 +134,7 @@ void MediaCodecList::parseXMLFile(FILE *file) { while (mInitCheck == OK) { void *buff = ::XML_GetBuffer(parser, BUFF_SIZE); if (buff == NULL) { - ALOGE("failed to in call to XML_GetBuffer()"); + ALOGE("failed in call to XML_GetBuffer()"); mInitCheck = UNKNOWN_ERROR; break; } @@ -124,8 +146,9 @@ void MediaCodecList::parseXMLFile(FILE *file) { break; } - if (::XML_ParseBuffer(parser, bytes_read, bytes_read == 0) - != XML_STATUS_OK) { + XML_Status status = ::XML_ParseBuffer(parser, bytes_read, bytes_read == 0); + if (status != XML_STATUS_OK) { + ALOGE("malformed (%s)", ::XML_ErrorString(::XML_GetErrorCode(parser))); mInitCheck = ERROR_MALFORMED; break; } @@ -137,25 +160,8 @@ void MediaCodecList::parseXMLFile(FILE *file) { ::XML_ParserFree(parser); - if (mInitCheck == OK) { - for (size_t i = mCodecInfos.size(); i-- > 0;) { - CodecInfo *info = &mCodecInfos.editItemAt(i); - - if (info->mTypes == 0) { - // No types supported by this component??? - - ALOGW("Component %s does not support any type of media?", - info->mName.c_str()); - - mCodecInfos.removeAt(i); - } - } - } - - if (mInitCheck != OK) { - mCodecInfos.clear(); - mCodecQuirks.clear(); - } + fclose(file); + file = NULL; } // static @@ -169,12 +175,63 @@ void MediaCodecList::EndElementHandlerWrapper(void *me, const char *name) { static_cast(me)->endElementHandler(name); } +status_t MediaCodecList::includeXMLFile(const char **attrs) { + const char *href = NULL; + size_t i = 0; + while (attrs[i] != NULL) { + if (!strcmp(attrs[i], "href")) { + if (attrs[i + 1] == NULL) { + return -EINVAL; + } + href = attrs[i + 1]; + ++i; + } else { + return -EINVAL; + } + ++i; + } + + // For security reasons and for simplicity, file names can only contain + // [a-zA-Z0-9_.] and must start with media_codecs_ and end with .xml + for (i = 0; href[i] != '\0'; i++) { + if (href[i] == '.' || href[i] == '_' || + (href[i] >= '0' && href[i] <= '9') || + (href[i] >= 'A' && href[i] <= 'Z') || + (href[i] >= 'a' && href[i] <= 'z')) { + continue; + } + ALOGE("invalid include file name: %s", href); + return -EINVAL; + } + + AString filename = href; + if (!filename.startsWith("media_codecs_") || + !filename.endsWith(".xml")) { + ALOGE("invalid include file name: %s", href); + return -EINVAL; + } + filename.insert(mHrefBase, 0); + + parseXMLFile(filename.c_str()); + return mInitCheck; +} + void MediaCodecList::startElementHandler( const char *name, const char **attrs) { if (mInitCheck != OK) { return; } + if (!strcmp(name, "Include")) { + mInitCheck = includeXMLFile(attrs); + if (mInitCheck == OK) { + mPastSections.push(mCurrentSection); + mCurrentSection = SECTION_INCLUDE; + } + ++mDepth; + return; + } + switch (mCurrentSection) { case SECTION_TOPLEVEL: { @@ -264,6 +321,15 @@ void MediaCodecList::endElementHandler(const char *name) { break; } + case SECTION_INCLUDE: + { + if (!strcmp(name, "Include") && mPastSections.size() > 0) { + mCurrentSection = mPastSections.top(); + mPastSections.pop(); + } + break; + } + default: break; } -- cgit v1.1 From de9453fb5cbc9cd69fd1ea45d577851e3aa3b8c9 Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Wed, 19 Mar 2014 13:05:45 -0400 Subject: Add MediaPlayer::getAudioStreamType. Change-Id: I9cd8a718d2873543609aa651fd85749478f4f89f --- media/libmedia/mediaplayer.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'media') diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index d94c7c5..0be01a9 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -531,6 +531,14 @@ status_t MediaPlayer::setAudioStreamType(audio_stream_type_t type) return OK; } +status_t MediaPlayer::getAudioStreamType(audio_stream_type_t *type) +{ + ALOGV("getAudioStreamType"); + Mutex::Autolock _l(mLock); + *type = mStreamType; + return OK; +} + status_t MediaPlayer::setLooping(int loop) { ALOGV("MediaPlayer::setLooping"); -- cgit v1.1 From 0d6abe8cdadde6f9ad7ac989042f725668233bdb Mon Sep 17 00:00:00 2001 From: Alex Glaznev Date: Tue, 25 Feb 2014 13:50:39 -0800 Subject: A few fixes in SW VP8 encoder: - Increase encoder output buffer size to 1 Mb to avoid buffer overrun when encoding high complexity HD frames. - Store output port format parameters. - Use same VP8 encoder settings as in WebRTC when encoder is configured to run in CBR mode. Bug: b/12924516 Bug: b/12908952 Change-Id: Ida884efd0cd1a7272998f5835abd290bfb19b2ac --- .../codecs/on2/enc/SoftVPXEncoder.cpp | 87 ++++++++++++++++++---- .../libstagefright/codecs/on2/enc/SoftVPXEncoder.h | 7 +- 2 files changed, 77 insertions(+), 17 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp index 5efe022..b3a6bcc 100644 --- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp +++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp @@ -141,9 +141,9 @@ SoftVPXEncoder::SoftVPXEncoder(const char *name, mWidth(176), mHeight(144), mBitrate(192000), // in bps + mFramerate(30 << 16), // in Q16 format mBitrateUpdated(false), mBitrateControlMode(VPX_VBR), // variable bitrate - mFrameDurationUs(33333), // Defaults to 30 fps mDCTPartitions(0), mErrorResilience(OMX_FALSE), mColorFormat(OMX_COLOR_FormatYUV420Planar), @@ -180,9 +180,8 @@ void SoftVPXEncoder::initPorts() { inputPort.format.video.nStride = inputPort.format.video.nFrameWidth; inputPort.format.video.nSliceHeight = inputPort.format.video.nFrameHeight; inputPort.format.video.nBitrate = 0; - // frameRate is reciprocal of frameDuration, which is - // in microseconds. It is also in Q16 format. - inputPort.format.video.xFramerate = (1000000/mFrameDurationUs) << 16; + // frameRate is in Q16 format. + inputPort.format.video.xFramerate = mFramerate; inputPort.format.video.bFlagErrorConcealment = OMX_FALSE; inputPort.nPortIndex = kInputPortIndex; inputPort.eDir = OMX_DirInput; @@ -220,7 +219,7 @@ void SoftVPXEncoder::initPorts() { outputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingVP8; outputPort.format.video.eColorFormat = OMX_COLOR_FormatUnused; outputPort.format.video.pNativeWindow = NULL; - outputPort.nBufferSize = 256 * 1024; // arbitrary + outputPort.nBufferSize = 1024 * 1024; // arbitrary addPort(outputPort); } @@ -277,8 +276,39 @@ status_t SoftVPXEncoder::initEncoder() { mCodecConfiguration->g_timebase.num = 1; mCodecConfiguration->g_timebase.den = 1000000; // rc_target_bitrate is in kbps, mBitrate in bps - mCodecConfiguration->rc_target_bitrate = mBitrate/1000; + mCodecConfiguration->rc_target_bitrate = mBitrate / 1000; mCodecConfiguration->rc_end_usage = mBitrateControlMode; + // Disable frame drop - not allowed in MediaCodec now. + mCodecConfiguration->rc_dropframe_thresh = 0; + if (mBitrateControlMode == VPX_CBR) { + // Disable spatial resizing. + mCodecConfiguration->rc_resize_allowed = 0; + // Single-pass mode. + mCodecConfiguration->g_pass = VPX_RC_ONE_PASS; + // Minimum quantization level. + mCodecConfiguration->rc_min_quantizer = 2; + // Maximum quantization level. + mCodecConfiguration->rc_max_quantizer = 63; + // Maximum amount of bits that can be subtracted from the target + // bitrate - expressed as percentage of the target bitrate. + mCodecConfiguration->rc_undershoot_pct = 100; + // Maximum amount of bits that can be added to the target + // bitrate - expressed as percentage of the target bitrate. + mCodecConfiguration->rc_overshoot_pct = 15; + // Initial value of the buffer level in ms. + mCodecConfiguration->rc_buf_initial_sz = 500; + // Amount of data that the encoder should try to maintain in ms. + mCodecConfiguration->rc_buf_optimal_sz = 600; + // The amount of data that may be buffered by the decoding + // application in ms. + mCodecConfiguration->rc_buf_sz = 1000; + // Enable error resilience - needed for packet loss. + mCodecConfiguration->g_error_resilient = 1; + // Disable lagged encoding. + mCodecConfiguration->g_lag_in_frames = 0; + // Encoder determines optimal key frame placement automatically. + mCodecConfiguration->kf_mode = VPX_KF_AUTO; + } codec_return = vpx_codec_enc_init(mCodecContext, mCodecInterface, @@ -298,6 +328,33 @@ status_t SoftVPXEncoder::initEncoder() { return UNKNOWN_ERROR; } + // Extra CBR settings + if (mBitrateControlMode == VPX_CBR) { + codec_return = vpx_codec_control(mCodecContext, + VP8E_SET_STATIC_THRESHOLD, + 1); + if (codec_return == VPX_CODEC_OK) { + uint32_t rc_max_intra_target = + mCodecConfiguration->rc_buf_optimal_sz * (mFramerate >> 17) / 10; + // Don't go below 3 times per frame bandwidth. + if (rc_max_intra_target < 300) { + rc_max_intra_target = 300; + } + codec_return = vpx_codec_control(mCodecContext, + VP8E_SET_MAX_INTRA_BITRATE_PCT, + rc_max_intra_target); + } + if (codec_return == VPX_CODEC_OK) { + codec_return = vpx_codec_control(mCodecContext, + VP8E_SET_CPUUSED, + -8); + } + if (codec_return != VPX_CODEC_OK) { + ALOGE("Error setting cbr parameters for vpx encoder."); + return UNKNOWN_ERROR; + } + } + if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || mInputDataIsMeta) { if (mConversionBuffer == NULL) { mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2); @@ -361,9 +418,7 @@ OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index, } formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused; - // Converting from microseconds - // Also converting to Q16 format - formatParams->xFramerate = (1000000/mFrameDurationUs) << 16; + formatParams->xFramerate = mFramerate; return OMX_ErrorNone; } else if (formatParams->nPortIndex == kOutputPortIndex) { formatParams->eCompressionFormat = OMX_VIDEO_CodingVP8; @@ -660,9 +715,7 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams( mHeight = port->format.video.nFrameHeight; // xFramerate comes in Q16 format, in frames per second unit - const uint32_t framerate = port->format.video.xFramerate >> 16; - // frame duration is in microseconds - mFrameDurationUs = (1000000/framerate); + mFramerate = port->format.video.xFramerate; if (port->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar || port->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || @@ -684,6 +737,13 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams( return OMX_ErrorNone; } else if (port->nPortIndex == kOutputPortIndex) { mBitrate = port->format.video.nBitrate; + mWidth = port->format.video.nFrameWidth; + mHeight = port->format.video.nFrameHeight; + + OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef; + def->format.video.nFrameWidth = mWidth; + def->format.video.nFrameHeight = mHeight; + def->format.video.nBitrate = mBitrate; return OMX_ErrorNone; } else { return OMX_ErrorBadPortIndex; @@ -814,11 +874,12 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { mBitrateUpdated = false; } + uint32_t frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate); codec_return = vpx_codec_encode( mCodecContext, &raw_frame, inputBufferHeader->nTimeStamp, // in timebase units - mFrameDurationUs, // frame duration in timebase units + frameDuration, // frame duration in timebase units flags, // frame flags VPX_DL_REALTIME); // encoding deadline if (codec_return != VPX_CODEC_OK) { diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h index 076830f..1c983ab 100644 --- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h +++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h @@ -130,16 +130,15 @@ private: // Target bitrate set for the encoder, in bits per second. uint32_t mBitrate; + // Target framerate set for the encoder. + uint32_t mFramerate; + // If a request for a change it bitrate has been received. bool mBitrateUpdated; // Bitrate control mode, either constant or variable vpx_rc_mode mBitrateControlMode; - // Frame duration is the reciprocal of framerate, denoted - // in microseconds - uint64_t mFrameDurationUs; - // vp8 specific configuration parameter // that enables token partitioning of // the stream into substreams -- cgit v1.1 From b4a7a2df4c28c3f32b5d877b54831d2cc5d78f81 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 19 Mar 2014 16:59:00 -0700 Subject: libstagefright: fix 64-bit warnings %lld -> %" PRId64 " for int64_t %d -> %zu for size_t Also fixes some casts from void* to integer types, and some comparisons between signed and unsigned. Change-Id: I9c52f76240e39399da252c66459042a6fc626a90 --- .../codecs/flac/enc/SoftFlacEncoder.cpp | 12 ++++++------ .../codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp | 4 +++- media/libstagefright/httplive/LiveSession.cpp | 11 ++++++----- media/libstagefright/httplive/M3UParser.cpp | 10 +++++----- media/libstagefright/httplive/PlaylistFetcher.cpp | 17 +++++++++-------- media/libstagefright/id3/ID3.cpp | 14 +++++++------- media/libstagefright/matroska/MatroskaExtractor.cpp | 14 ++++++++------ media/libstagefright/mpeg2ts/ATSParser.cpp | 20 +++++++++++--------- media/libstagefright/mpeg2ts/AnotherPacketSource.cpp | 4 +++- media/libstagefright/mpeg2ts/ESQueue.cpp | 19 ++++++++++--------- media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp | 10 ++++++---- media/libstagefright/rtsp/AAVCAssembler.cpp | 10 +++++----- .../rtsp/AMPEG4ElementaryAssembler.cpp | 2 +- media/libstagefright/rtsp/ARTPConnection.cpp | 2 +- media/libstagefright/rtsp/ARTPWriter.cpp | 2 +- media/libstagefright/rtsp/SDPLoader.cpp | 2 +- media/libstagefright/timedtext/TimedTextPlayer.cpp | 3 ++- media/libstagefright/webm/WebmElement.cpp | 2 +- media/libstagefright/webm/WebmFrameThread.cpp | 2 +- 19 files changed, 87 insertions(+), 73 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp index 40661e7..0c62ec0 100644 --- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp +++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp @@ -247,7 +247,7 @@ OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter( if (defParams->nPortIndex == 0) { if (defParams->nBufferSize > kMaxInputBufferSize) { - ALOGE("Input buffer size must be at most %zu bytes", + ALOGE("Input buffer size must be at most %d bytes", kMaxInputBufferSize); return OMX_ErrorUnsupportedSetting; } @@ -354,12 +354,12 @@ FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable( size_t bytes, unsigned samples, unsigned current_frame) { UNUSED_UNLESS_VERBOSE(current_frame); - ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%d, samples=%d, curr_frame=%d)", + ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%zu, samples=%u, curr_frame=%u)", bytes, samples, current_frame); #ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER if (samples == 0) { - ALOGI(" saving %d bytes of header", bytes); + ALOGI(" saving %zu bytes of header", bytes); memcpy(mHeader + mHeaderOffset, buffer, bytes); mHeaderOffset += bytes;// will contain header size when finished receiving header return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; @@ -370,7 +370,7 @@ FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable( if ((samples == 0) || !mEncoderWriteData) { // called by the encoder because there's header data to save, but it's not the role // of this component (unless WRITE_FLAC_HEADER_IN_FIRST_BUFFER is defined) - ALOGV("ignoring %d bytes of header data (samples=%d)", bytes, samples); + ALOGV("ignoring %zu bytes of header data (samples=%d)", bytes, samples); return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; } @@ -391,9 +391,9 @@ FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable( #endif // write encoded data - ALOGV(" writing %d bytes of encoded data on output port", bytes); + ALOGV(" writing %zu bytes of encoded data on output port", bytes); if (bytes > outHeader->nAllocLen - outHeader->nOffset - outHeader->nFilledLen) { - ALOGE(" not enough space left to write encoded data, dropping %u bytes", bytes); + ALOGE(" not enough space left to write encoded data, dropping %zu bytes", bytes); // a fatal error would stop the encoding return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; } diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp index 2c73e57..ee8dcf2 100644 --- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp +++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp @@ -33,6 +33,8 @@ #include "SoftMPEG4Encoder.h" +#include + namespace android { template @@ -725,7 +727,7 @@ void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { if (!PVEncodeVideoFrame(mHandle, &vin, &vout, &modTimeMs, outPtr, &dataLength, &nLayer) || !PVGetHintTrack(mHandle, &hintTrack)) { - ALOGE("Failed to encode frame or get hink track at frame %lld", + ALOGE("Failed to encode frame or get hink track at frame %" PRId64, mNumInputFrames); mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index cdf5209..fd42e77 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -168,7 +169,7 @@ status_t LiveSession::dequeueAccessUnit( if (stream == STREAMTYPE_AUDIO || stream == STREAMTYPE_VIDEO) { int64_t timeUs; CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); - ALOGV("[%s] read buffer at time %lld us", streamStr, timeUs); + ALOGV("[%s] read buffer at time %" PRId64 " us", streamStr, timeUs); mLastDequeuedTimeUs = timeUs; mRealTimeBaseUs = ALooper::GetNowUs() - timeUs; @@ -675,7 +676,7 @@ ssize_t LiveSession::fetchFile( ssize_t bytesRead = 0; // adjust range_length if only reading partial block - if (block_size > 0 && (range_length == -1 || buffer->size() + block_size < range_length)) { + if (block_size > 0 && (range_length == -1 || (int64_t)(buffer->size() + block_size) < range_length)) { range_length = buffer->size() + block_size; } for (;;) { @@ -684,7 +685,7 @@ ssize_t LiveSession::fetchFile( if (bufferRemaining == 0 && getSizeErr != OK) { bufferRemaining = 32768; - ALOGV("increasing download buffer to %d bytes", + ALOGV("increasing download buffer to %zu bytes", buffer->size() + bufferRemaining); sp copy = new ABuffer(buffer->size() + bufferRemaining); @@ -697,7 +698,7 @@ ssize_t LiveSession::fetchFile( size_t maxBytesToRead = bufferRemaining; if (range_length >= 0) { int64_t bytesLeftInRange = range_length - buffer->size(); - if (bytesLeftInRange < maxBytesToRead) { + if (bytesLeftInRange < (int64_t)maxBytesToRead) { maxBytesToRead = bytesLeftInRange; if (bytesLeftInRange == 0) { @@ -964,7 +965,7 @@ void LiveSession::changeConfiguration( mPrevBandwidthIndex = bandwidthIndex; - ALOGV("changeConfiguration => timeUs:%lld us, bwIndex:%d, pickTrack:%d", + ALOGV("changeConfiguration => timeUs:%" PRId64 " us, bwIndex:%zu, pickTrack:%d", timeUs, bandwidthIndex, pickTrack); if (pickTrack) { diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index dacdd40..f22d650 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -163,21 +163,21 @@ status_t M3UParser::MediaGroup::selectTrack(size_t index, bool select) { if (select) { if (index >= mMediaItems.size()) { - ALOGE("track %d does not exist", index); + ALOGE("track %zu does not exist", index); return INVALID_OPERATION; } if (mSelectedIndex == (ssize_t)index) { - ALOGE("track %d already selected", index); + ALOGE("track %zu already selected", index); return BAD_VALUE; } - ALOGV("selected track %d", index); + ALOGV("selected track %zu", index); mSelectedIndex = index; } else { if (mSelectedIndex != (ssize_t)index) { - ALOGE("track %d is not selected", index); + ALOGE("track %zu is not selected", index); return BAD_VALUE; } - ALOGV("unselected track %d", index); + ALOGV("unselected track %zu", index); mSelectedIndex = -1; } diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index c8df831..5011bc1 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -316,7 +317,7 @@ void PlaylistFetcher::postMonitorQueue(int64_t delayUs, int64_t minDelayUs) { maxDelayUs = minDelayUs; } if (delayUs > maxDelayUs) { - ALOGV("Need to refresh playlist in %lld", maxDelayUs); + ALOGV("Need to refresh playlist in %" PRId64 , maxDelayUs); delayUs = maxDelayUs; } sp msg = new AMessage(kWhatMonitorQueue, id()); @@ -627,7 +628,7 @@ void PlaylistFetcher::onMonitorQueue() { int64_t bufferedStreamDurationUs = mPacketSources.valueAt(i)->getBufferedDurationUs(&finalResult); - ALOGV("buffered %lld for stream %d", + ALOGV("buffered %" PRId64 " for stream %d", bufferedStreamDurationUs, mPacketSources.keyAt(i)); if (bufferedStreamDurationUs > bufferedDurationUs) { bufferedDurationUs = bufferedStreamDurationUs; @@ -640,7 +641,7 @@ void PlaylistFetcher::onMonitorQueue() { if (!mPrepared && bufferedDurationUs > targetDurationUs && downloadMore) { mPrepared = true; - ALOGV("prepared, buffered=%lld > %lld", + ALOGV("prepared, buffered=%" PRId64 " > %" PRId64 "", bufferedDurationUs, targetDurationUs); sp msg = mNotify->dup(); msg->setInt32("what", kWhatTemporarilyDoneFetching); @@ -648,7 +649,7 @@ void PlaylistFetcher::onMonitorQueue() { } if (finalResult == OK && downloadMore) { - ALOGV("monitoring, buffered=%lld < %lld", + ALOGV("monitoring, buffered=%" PRId64 " < %" PRId64 "", bufferedDurationUs, durationToBufferUs); // delay the next download slightly; hopefully this gives other concurrent fetchers // a better chance to run. @@ -664,7 +665,7 @@ void PlaylistFetcher::onMonitorQueue() { msg->post(); int64_t delayUs = mPrepared ? kMaxMonitorDelayUs : targetDurationUs / 2; - ALOGV("pausing for %lld, buffered=%lld > %lld", + ALOGV("pausing for %" PRId64 ", buffered=%" PRId64 " > %" PRId64 "", delayUs, bufferedDurationUs, durationToBufferUs); // :TRICKY: need to enforce minimum delay because the delay to // refresh the playlist will become 0 @@ -738,7 +739,7 @@ void PlaylistFetcher::onDownloadNext() { if (mPlaylist->isComplete() || mPlaylist->isEvent()) { mSeqNumber = getSeqNumberForTime(mStartTimeUs); - ALOGV("Initial sequence number for time %lld is %d from (%d .. %d)", + ALOGV("Initial sequence number for time %" PRId64 " is %d from (%d .. %d)", mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist); } else { @@ -772,7 +773,7 @@ void PlaylistFetcher::onDownloadNext() { delayUs = kMaxMonitorDelayUs; } ALOGV("sequence number high: %d from (%d .. %d), " - "monitor in %lld (retry=%d)", + "monitor in %" PRId64 " (retry=%d)", mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist, delayUs, mNumRetries); postMonitorQueue(delayUs); @@ -797,7 +798,7 @@ void PlaylistFetcher::onDownloadNext() { ALOGE("Cannot find sequence number %d in playlist " "(contains %d - %d)", mSeqNumber, firstSeqNumberInPlaylist, - firstSeqNumberInPlaylist + mPlaylist->size() - 1); + firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1); notifyError(ERROR_END_OF_STREAM); return; diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp index f0f203c..7f221a0 100644 --- a/media/libstagefright/id3/ID3.cpp +++ b/media/libstagefright/id3/ID3.cpp @@ -41,9 +41,9 @@ struct MemorySource : public DataSource { } virtual ssize_t readAt(off64_t offset, void *data, size_t size) { - off64_t available = (offset >= mSize) ? 0ll : mSize - offset; + off64_t available = (offset >= (off64_t)mSize) ? 0ll : mSize - offset; - size_t copy = (available > size) ? size : available; + size_t copy = (available > (off64_t)size) ? size : available; memcpy(data, mData + offset, copy); return copy; @@ -172,7 +172,7 @@ struct id3_header { } if (size > kMaxMetadataSize) { - ALOGE("skipping huge ID3 metadata of size %d", size); + ALOGE("skipping huge ID3 metadata of size %zu", size); return false; } @@ -633,8 +633,8 @@ void ID3::Iterator::findFrame() { mFrameSize += 6; if (mOffset + mFrameSize > mParent.mSize) { - ALOGV("partial frame at offset %d (size = %d, bytes-remaining = %d)", - mOffset, mFrameSize, mParent.mSize - mOffset - 6); + ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)", + mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)6); return; } @@ -674,8 +674,8 @@ void ID3::Iterator::findFrame() { mFrameSize = 10 + baseSize; if (mOffset + mFrameSize > mParent.mSize) { - ALOGV("partial frame at offset %d (size = %d, bytes-remaining = %d)", - mOffset, mFrameSize, mParent.mSize - mOffset - 10); + ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)", + mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)10); return; } diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index 6ec9263..d4a7c7f 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -33,6 +33,8 @@ #include #include +#include + namespace android { struct DataSourceReader : public mkvparser::IMkvReader { @@ -103,7 +105,7 @@ struct BlockIterator { private: MatroskaExtractor *mExtractor; - unsigned long mTrackNum; + long long mTrackNum; const mkvparser::Cluster *mCluster; const mkvparser::BlockEntry *mBlockEntry; @@ -183,7 +185,7 @@ MatroskaSource::MatroskaSource( CHECK_GE(avccSize, 5u); mNALSizeLen = 1 + (avcc[4] & 3); - ALOGV("mNALSizeLen = %d", mNALSizeLen); + ALOGV("mNALSizeLen = %zu", mNALSizeLen); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { mType = AAC; } @@ -320,7 +322,7 @@ void BlockIterator::seek( // Special case the 0 seek to avoid loading Cues when the application // extraneously seeks to 0 before playing. if (seekTimeNs <= 0) { - ALOGV("Seek to beginning: %lld", seekTimeUs); + ALOGV("Seek to beginning: %" PRId64, seekTimeUs); mCluster = pSegment->GetFirst(); mBlockEntryIndex = 0; do { @@ -329,7 +331,7 @@ void BlockIterator::seek( return; } - ALOGV("Seeking to: %lld", seekTimeUs); + ALOGV("Seeking to: %" PRId64, seekTimeUs); // If the Cues have not been located then find them. const mkvparser::Cues* pCues = pSegment->GetCues(); @@ -378,7 +380,7 @@ void BlockIterator::seek( for (size_t index = 0; index < pTracks->GetTracksCount(); ++index) { pTrack = pTracks->GetTrackByIndex(index); if (pTrack && pTrack->GetType() == 1) { // VIDEO_TRACK - ALOGV("Video track located at %d", index); + ALOGV("Video track located at %zu", index); break; } } @@ -409,7 +411,7 @@ void BlockIterator::seek( if (isAudio || block()->IsKey()) { // Accept the first key frame *actualFrameTimeUs = (block()->GetTime(mCluster) + 500LL) / 1000LL; - ALOGV("Requested seek point: %lld actual: %lld", + ALOGV("Requested seek point: %" PRId64 " actual: %" PRId64, seekTimeUs, *actualFrameTimeUs); break; } diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index d039f7d..d1afd8b 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -36,6 +36,8 @@ #include #include +#include + namespace android { // I want the expression "y" evaluated even if verbose logging is off. @@ -586,7 +588,7 @@ status_t ATSParser::Stream::parse( // Increment in multiples of 64K. neededSize = (neededSize + 65535) & ~65535; - ALOGI("resizing buffer to %d bytes", neededSize); + ALOGI("resizing buffer to %zu bytes", neededSize); sp newBuffer = new ABuffer(neededSize); memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size()); @@ -748,7 +750,7 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { PTS |= br->getBits(15); CHECK_EQ(br->getBits(1), 1u); - ALOGV("PTS = 0x%016llx (%.2f)", PTS, PTS / 90000.0); + ALOGV("PTS = 0x%016" PRIx64 " (%.2f)", PTS, PTS / 90000.0); optional_bytes_remaining -= 5; @@ -764,7 +766,7 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { DTS |= br->getBits(15); CHECK_EQ(br->getBits(1), 1u); - ALOGV("DTS = %llu", DTS); + ALOGV("DTS = %" PRIu64, DTS); optional_bytes_remaining -= 5; } @@ -782,7 +784,7 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { ESCR |= br->getBits(15); CHECK_EQ(br->getBits(1), 1u); - ALOGV("ESCR = %llu", ESCR); + ALOGV("ESCR = %" PRIu64, ESCR); MY_LOGV("ESCR_extension = %u", br->getBits(9)); CHECK_EQ(br->getBits(1), 1u); @@ -812,7 +814,7 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { if (br->numBitsLeft() < dataLength * 8) { ALOGE("PES packet does not carry enough data to contain " - "payload. (numBitsLeft = %d, required = %d)", + "payload. (numBitsLeft = %zu, required = %u)", br->numBitsLeft(), dataLength * 8); return ERROR_MALFORMED; @@ -832,7 +834,7 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { size_t payloadSizeBits = br->numBitsLeft(); CHECK_EQ(payloadSizeBits % 8, 0u); - ALOGV("There's %d bytes of payload.", payloadSizeBits / 8); + ALOGV("There's %zu bytes of payload.", payloadSizeBits / 8); } } else if (stream_id == 0xbe) { // padding_stream CHECK_NE(PES_packet_length, 0u); @@ -850,7 +852,7 @@ status_t ATSParser::Stream::flush() { return OK; } - ALOGV("flushing stream 0x%04x size = %d", mElementaryPID, mBuffer->size()); + ALOGV("flushing stream 0x%04x size = %zu", mElementaryPID, mBuffer->size()); ABitReader br(mBuffer->data(), mBuffer->size()); @@ -1172,7 +1174,7 @@ void ATSParser::parseAdaptationField(ABitReader *br, unsigned PID) { uint64_t PCR = PCR_base * 300 + PCR_ext; - ALOGV("PID 0x%04x: PCR = 0x%016llx (%.2f)", + ALOGV("PID 0x%04x: PCR = 0x%016" PRIx64 " (%.2f)", PID, PCR, PCR / 27E6); // The number of bytes received by this parser up to and @@ -1268,7 +1270,7 @@ bool ATSParser::PTSTimeDeltaEstablished() { void ATSParser::updatePCR( unsigned /* PID */, uint64_t PCR, size_t byteOffsetFromStart) { - ALOGV("PCR 0x%016llx @ %d", PCR, byteOffsetFromStart); + ALOGV("PCR 0x%016" PRIx64 " @ %zu", PCR, byteOffsetFromStart); if (mNumPCRs == 2) { mPCR[0] = mPCR[1]; diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index 6dfaa94..021b640 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -26,6 +26,8 @@ #include #include +#include + namespace android { const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs @@ -186,7 +188,7 @@ void AnotherPacketSource::queueAccessUnit(const sp &buffer) { int64_t lastQueuedTimeUs; CHECK(buffer->meta()->findInt64("timeUs", &lastQueuedTimeUs)); mLastQueuedTimeUs = lastQueuedTimeUs; - ALOGV("queueAccessUnit timeUs=%lld us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6); + ALOGV("queueAccessUnit timeUs=%" PRIi64 " us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6); Mutex::Autolock autoLock(mLock); mBuffers.push_back(buffer); diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp index c0c9717..f7abf01 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.cpp +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp @@ -31,6 +31,7 @@ #include "include/avc_utils.h" +#include #include namespace android { @@ -264,7 +265,7 @@ status_t ElementaryStreamQueue::appendData( if (startOffset > 0) { ALOGI("found something resembling an H.264/MPEG syncword " - "at offset %d", + "at offset %zd", startOffset); } @@ -297,7 +298,7 @@ status_t ElementaryStreamQueue::appendData( if (startOffset > 0) { ALOGI("found something resembling an H.264/MPEG syncword " - "at offset %d", + "at offset %zd", startOffset); } @@ -330,7 +331,7 @@ status_t ElementaryStreamQueue::appendData( if (startOffset > 0) { ALOGI("found something resembling an AAC syncword at " - "offset %d", + "offset %zd", startOffset); } @@ -358,7 +359,7 @@ status_t ElementaryStreamQueue::appendData( if (startOffset > 0) { ALOGI("found something resembling an AC3 syncword at " - "offset %d", + "offset %zd", startOffset); } @@ -385,7 +386,7 @@ status_t ElementaryStreamQueue::appendData( if (startOffset > 0) { ALOGI("found something resembling an MPEG audio " - "syncword at offset %d", + "syncword at offset %zd", startOffset); } @@ -409,7 +410,7 @@ status_t ElementaryStreamQueue::appendData( if (mBuffer == NULL || neededSize > mBuffer->capacity()) { neededSize = (neededSize + 65535) & ~65535; - ALOGV("resizing buffer to size %d", neededSize); + ALOGV("resizing buffer to size %zu", neededSize); sp buffer = new ABuffer(neededSize); if (mBuffer != NULL) { @@ -432,7 +433,7 @@ status_t ElementaryStreamQueue::appendData( #if 0 if (mMode == AAC) { - ALOGI("size = %d, timeUs = %.2f secs", size, timeUs / 1E6); + ALOGI("size = %zu, timeUs = %.2f secs", size, timeUs / 1E6); hexdump(data, size); } #endif @@ -1027,7 +1028,7 @@ sp ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() { accessUnit->meta()->setInt64("timeUs", timeUs); - ALOGV("returning MPEG video access unit at time %lld us", + ALOGV("returning MPEG video access unit at time %" PRId64 " us", timeUs); // hexdump(accessUnit->data(), accessUnit->size()); @@ -1186,7 +1187,7 @@ sp ElementaryStreamQueue::dequeueAccessUnitMPEG4Video() { accessUnit->meta()->setInt64("timeUs", timeUs); - ALOGV("returning MPEG4 video access unit at time %lld us", + ALOGV("returning MPEG4 video access unit at time %" PRId64 " us", timeUs); // hexdump(accessUnit->data(), accessUnit->size()); diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp index bc2a16d..85859f7 100644 --- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp +++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp @@ -36,6 +36,8 @@ #include #include +#include + namespace android { struct MPEG2PSExtractor::Track : public MediaSource { @@ -409,7 +411,7 @@ ssize_t MPEG2PSExtractor::dequeuePES() { PTS |= br.getBits(15); CHECK_EQ(br.getBits(1), 1u); - ALOGV("PTS = %llu", PTS); + ALOGV("PTS = %" PRIu64, PTS); // ALOGI("PTS = %.2f secs", PTS / 90000.0f); optional_bytes_remaining -= 5; @@ -426,7 +428,7 @@ ssize_t MPEG2PSExtractor::dequeuePES() { DTS |= br.getBits(15); CHECK_EQ(br.getBits(1), 1u); - ALOGV("DTS = %llu", DTS); + ALOGV("DTS = %" PRIu64, DTS); optional_bytes_remaining -= 5; } @@ -444,7 +446,7 @@ ssize_t MPEG2PSExtractor::dequeuePES() { ESCR |= br.getBits(15); CHECK_EQ(br.getBits(1), 1u); - ALOGV("ESCR = %llu", ESCR); + ALOGV("ESCR = %" PRIu64, ESCR); /* unsigned ESCR_extension = */br.getBits(9); CHECK_EQ(br.getBits(1), 1u); @@ -473,7 +475,7 @@ ssize_t MPEG2PSExtractor::dequeuePES() { if (br.numBitsLeft() < dataLength * 8) { ALOGE("PES packet does not carry enough data to contain " - "payload. (numBitsLeft = %d, required = %d)", + "payload. (numBitsLeft = %zu, required = %u)", br.numBitsLeft(), dataLength * 8); return ERROR_MALFORMED; diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp index a6825eb..4bc67e8 100644 --- a/media/libstagefright/rtsp/AAVCAssembler.cpp +++ b/media/libstagefright/rtsp/AAVCAssembler.cpp @@ -124,7 +124,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addNALUnit( } void AAVCAssembler::addSingleNALUnit(const sp &buffer) { - ALOGV("addSingleNALUnit of size %d", buffer->size()); + ALOGV("addSingleNALUnit of size %zu", buffer->size()); #if !LOG_NDEBUG hexdump(buffer->data(), buffer->size()); #endif @@ -191,7 +191,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( CHECK((indicator & 0x1f) == 28); if (size < 2) { - ALOGV("Ignoring malformed FU buffer (size = %d)", size); + ALOGV("Ignoring malformed FU buffer (size = %zu)", size); queue->erase(queue->begin()); ++mNextExpectedSeqNo; @@ -225,7 +225,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( } else { List >::iterator it = ++queue->begin(); while (it != queue->end()) { - ALOGV("sequence length %d", totalCount); + ALOGV("sequence length %zu", totalCount); const sp &buffer = *it; @@ -294,7 +294,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( for (size_t i = 0; i < totalCount; ++i) { const sp &buffer = *it; - ALOGV("piece #%d/%d", i + 1, totalCount); + ALOGV("piece #%zu/%zu", i + 1, totalCount); #if !LOG_NDEBUG hexdump(buffer->data(), buffer->size()); #endif @@ -317,7 +317,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( void AAVCAssembler::submitAccessUnit() { CHECK(!mNALUnits.empty()); - ALOGV("Access unit complete (%d nal units)", mNALUnits.size()); + ALOGV("Access unit complete (%zu nal units)", mNALUnits.size()); size_t totalSize = 0; for (List >::iterator it = mNALUnits.begin(); diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp index eefceba..98b50dd 100644 --- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp +++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp @@ -365,7 +365,7 @@ ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket( void AMPEG4ElementaryAssembler::submitAccessUnit() { CHECK(!mPackets.empty()); - ALOGV("Access unit complete (%d nal units)", mPackets.size()); + ALOGV("Access unit complete (%zu nal units)", mPackets.size()); sp accessUnit; diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp index af369b5..372fbe9 100644 --- a/media/libstagefright/rtsp/ARTPConnection.cpp +++ b/media/libstagefright/rtsp/ARTPConnection.cpp @@ -563,7 +563,7 @@ status_t ARTPConnection::parseRTCP(StreamInfo *s, const sp &buffer) { default: { - ALOGW("Unknown RTCP packet type %u of size %d", + ALOGW("Unknown RTCP packet type %u of size %zu", (unsigned)data[1], headerLength); break; } diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp index c46d16f..793d116 100644 --- a/media/libstagefright/rtsp/ARTPWriter.cpp +++ b/media/libstagefright/rtsp/ARTPWriter.cpp @@ -277,7 +277,7 @@ void ARTPWriter::onRead(const sp &msg) { } if (mediaBuf->range_length() > 0) { - ALOGV("read buffer of size %d", mediaBuf->range_length()); + ALOGV("read buffer of size %zu", mediaBuf->range_length()); if (mMode == H264) { StripStartcode(mediaBuf); diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp index 13e8da3..09f7eee 100644 --- a/media/libstagefright/rtsp/SDPLoader.cpp +++ b/media/libstagefright/rtsp/SDPLoader.cpp @@ -125,7 +125,7 @@ void SDPLoader::onLoad(const sp &msg) { ssize_t readSize = mHTTPDataSource->readAt(0, buffer->data(), sdpSize); if (readSize < 0) { - ALOGE("Failed to read SDP, error code = %d", readSize); + ALOGE("Failed to read SDP, error code = %zu", readSize); err = UNKNOWN_ERROR; } else { desc = new ASessionDescription; diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp index 9fb0afe..a070487 100644 --- a/media/libstagefright/timedtext/TimedTextPlayer.cpp +++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "TimedTextPlayer" #include +#include #include #include #include @@ -271,7 +272,7 @@ int64_t TimedTextPlayer::delayUsFromCurrentTime(int64_t fireTimeUs) { sp listener = mListener.promote(); if (listener == NULL) { // TODO: it may be better to return kInvalidTimeUs - ALOGE("%s: Listener is NULL. (fireTimeUs = %lld)", + ALOGE("%s: Listener is NULL. (fireTimeUs = %" PRId64" )", __FUNCTION__, fireTimeUs); return 0; } diff --git a/media/libstagefright/webm/WebmElement.cpp b/media/libstagefright/webm/WebmElement.cpp index c978966..a008cab 100644 --- a/media/libstagefright/webm/WebmElement.cpp +++ b/media/libstagefright/webm/WebmElement.cpp @@ -119,7 +119,7 @@ int WebmElement::write(int fd, uint64_t& size) { off64_t mapSize = curOff - alignedOff; off64_t pageOff = off - alignedOff; void *dst = ::mmap64(NULL, mapSize, PROT_WRITE, MAP_SHARED, fd, alignedOff); - if ((int) dst == -1) { + if (dst == MAP_FAILED) { ALOGE("mmap64 failed; errno = %d", errno); ALOGE("fd %d; flags: %o", fd, ::fcntl(fd, F_GETFL, 0)); return errno; diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp index 5addd3c..a4b8a42 100644 --- a/media/libstagefright/webm/WebmFrameThread.cpp +++ b/media/libstagefright/webm/WebmFrameThread.cpp @@ -48,7 +48,7 @@ status_t WebmFrameThread::start() { status_t WebmFrameThread::stop() { void *status; pthread_join(mThread, &status); - return (status_t) status; + return (status_t)(intptr_t)status; } //================================================================================================= -- cgit v1.1 From 3b800bf9a1db3c9f2f37c9512deb282588e8b50c Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 19 Mar 2014 15:21:53 -0700 Subject: stagefright: initial media_codecs_google*.xml files Separated description of Google-provided codecs into their own files based on domain. Google-provided audio/telephony codecs should be included prior to specifying vendor codecs. Google- provided video codecs should be included after vendor codecs. Bug: 13549114 Change-Id: I216f01feaf0379c6cd7d8714e02792fdf2214a90 --- .../data/media_codecs_google_audio.xml | 35 ++++++++++++++++++++++ .../data/media_codecs_google_telephony.xml | 21 +++++++++++++ .../data/media_codecs_google_video.xml | 32 ++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 media/libstagefright/data/media_codecs_google_audio.xml create mode 100644 media/libstagefright/data/media_codecs_google_telephony.xml create mode 100644 media/libstagefright/data/media_codecs_google_video.xml (limited to 'media') diff --git a/media/libstagefright/data/media_codecs_google_audio.xml b/media/libstagefright/data/media_codecs_google_audio.xml new file mode 100644 index 0000000..b1f93de --- /dev/null +++ b/media/libstagefright/data/media_codecs_google_audio.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/media/libstagefright/data/media_codecs_google_telephony.xml b/media/libstagefright/data/media_codecs_google_telephony.xml new file mode 100644 index 0000000..28f5ffc --- /dev/null +++ b/media/libstagefright/data/media_codecs_google_telephony.xml @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml new file mode 100644 index 0000000..41e0efb --- /dev/null +++ b/media/libstagefright/data/media_codecs_google_video.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + -- cgit v1.1 From eb5d7f2f1cc049ea7f95a4f089ce2113d7683dda Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 24 Mar 2014 16:18:36 -0700 Subject: mtp: avoid silent allocation overflow in MtpProperty Bug: 13006907 Change-Id: Ice0352394840132c9c2ce6c28366632c792a32c0 --- media/mtp/MtpProperty.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/mtp/MtpProperty.cpp b/media/mtp/MtpProperty.cpp index 3838ce8..c500901 100644 --- a/media/mtp/MtpProperty.cpp +++ b/media/mtp/MtpProperty.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "MtpProperty" #include +#include #include "MtpDataPacket.h" #include "MtpDebug.h" #include "MtpProperty.h" @@ -518,8 +519,14 @@ void MtpProperty::writeValue(MtpDataPacket& packet, MtpPropertyValue& value) { MtpPropertyValue* MtpProperty::readArrayValues(MtpDataPacket& packet, int& length) { length = packet.getUInt32(); - if (length == 0) + // Fail if resulting array is over 2GB. This is because the maximum array + // size may be less than SIZE_MAX on some platforms. + if ( CC_UNLIKELY( + length == 0 || + length >= INT32_MAX / sizeof(MtpPropertyValue)) ) { + length = 0; return NULL; + } MtpPropertyValue* result = new MtpPropertyValue[length]; for (int i = 0; i < length; i++) readValue(packet, result[i]); -- cgit v1.1 From 1392eb3d1802e9f894f87d7a7387207d1b6faca1 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 25 Mar 2014 11:49:08 -0700 Subject: Fix operator precedence Change-Id: I164708a5b76a341a185467b008ecbec98d58a6df --- media/libmedia/CharacterEncodingDetector.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp index 5a3bf9d..4992798 100644 --- a/media/libmedia/CharacterEncodingDetector.cpp +++ b/media/libmedia/CharacterEncodingDetector.cpp @@ -171,12 +171,12 @@ void CharacterEncodingDetector::detectAndConvert() { int32_t inputLength = strlen(s); const char *enc; - if (!allprintable && !strcmp(name, "artist") || + if (!allprintable && (!strcmp(name, "artist") || !strcmp(name, "albumartist") || !strcmp(name, "composer") || !strcmp(name, "genre") || !strcmp(name, "album") || - !strcmp(name, "title")) { + !strcmp(name, "title"))) { // use encoding determined from the combination of artist/album/title etc. enc = combinedenc; } else { -- cgit v1.1 From 3f35eb55f0e2bc5a4dda7f58ed52654403a87efa Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 21 Nov 2013 13:54:25 -0800 Subject: Fix log spam when MonoPipe is unable to get local frequency Local frequency does not change, so only ask for it the first time a MonoPipe is constructed in a given client process. Thereafter use a previously cached value. Likewise, if the local frequency is unavailable, only log this the first time. Change-Id: Ib1fc7251c3832e02fe03811db39a87e500f1df50 --- media/libnbaio/MonoPipe.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp index 9c8461c..4adf018 100644 --- a/media/libnbaio/MonoPipe.cpp +++ b/media/libnbaio/MonoPipe.cpp @@ -30,6 +30,23 @@ namespace android { +static uint64_t cacheN; // output of CCHelper::getLocalFreq() +static bool cacheValid; // whether cacheN is valid +static pthread_once_t cacheOnceControl = PTHREAD_ONCE_INIT; + +static void cacheOnceInit() +{ + CCHelper tmpHelper; + status_t res; + if (OK != (res = tmpHelper.getLocalFreq(&cacheN))) { + ALOGE("Failed to fetch local time frequency when constructing a" + " MonoPipe (res = %d). getNextWriteTimestamp calls will be" + " non-functional", res); + return; + } + cacheValid = true; +} + MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) : NBAIO_Sink(format), mUpdateSeq(0), @@ -47,8 +64,6 @@ MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBl mTimestampMutator(&mTimestampShared), mTimestampObserver(&mTimestampShared) { - CCHelper tmpHelper; - status_t res; uint64_t N, D; mNextRdPTS = AudioBufferProvider::kInvalidPTS; @@ -59,12 +74,13 @@ MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBl mSamplesToLocalTime.a_to_b_denom = 0; D = Format_sampleRate(format); - if (OK != (res = tmpHelper.getLocalFreq(&N))) { - ALOGE("Failed to fetch local time frequency when constructing a" - " MonoPipe (res = %d). getNextWriteTimestamp calls will be" - " non-functional", res); + + (void) pthread_once(&cacheOnceControl, cacheOnceInit); + if (!cacheValid) { + // log has already been done return; } + N = cacheN; LinearTransform::reduce(&N, &D); static const uint64_t kSignedHiBitsMask = ~(0x7FFFFFFFull); -- cgit v1.1 From 85d109a4b0eddd76a8c5cee170bc2bcc99d00118 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 17 Jan 2014 10:25:08 -0800 Subject: Document AudioSystem::newAudioSessionId() failures Change-Id: Iaa168722f362c36bdfa87fe20dc0a59b43cf1ca3 --- media/libmedia/AudioSystem.cpp | 2 +- media/libmedia/IAudioFlinger.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 140fb66..c418466 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -431,7 +431,7 @@ uint32_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) int AudioSystem::newAudioSessionId() { const sp& af = AudioSystem::get_audio_flinger(); - if (af == 0) return 0; + if (af == 0) return AUDIO_SESSION_ALLOCATE; return af->newAudioSessionId(); } diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 762681e..f28b82d 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -599,7 +599,7 @@ public: Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); status_t status = remote()->transact(NEW_AUDIO_SESSION_ID, data, &reply); - int id = 0; + int id = AUDIO_SESSION_ALLOCATE; if (status == NO_ERROR) { id = reply.readInt32(); } -- cgit v1.1 From 9ea65d0f4a564478343b1a722fae4ce5883670c3 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 17 Jan 2014 10:21:24 -0800 Subject: Fix uses of KeyedVector Constructor for AudioFlinger::mAudioHwDevs was missing, and so AudioFlinger::findSuitableHwDev_l() could return an undefined pointer if a non-0 module wasn't found. A KeyedVector of Plain Old Data (POD) element type must specify the default value in the constructor, or else the default will be undefined. Minor: - Parameter had wrong type in constructor for AudioSystem::gOutputs. - Remove obsolete AudioSystem::gStreamOutputMap. Change-Id: I9841493e018440e559d8b8b0e4e748ba2b2d365b --- media/libmedia/AudioSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 140fb66..193e488 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -37,7 +37,7 @@ sp AudioSystem::gAudioFlingerClient; audio_error_callback AudioSystem::gAudioErrorCallback = NULL; // Cached values -DefaultKeyedVector AudioSystem::gOutputs(0); +DefaultKeyedVector AudioSystem::gOutputs(NULL); // Cached values for recording queries, all protected by gLock uint32_t AudioSystem::gPrevInSamplingRate; -- cgit v1.1 From 66e4635cb09fadcaccf912f37c387396c428378a Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 16 Jan 2014 17:44:23 -0800 Subject: Use symbolic constants from AUDIO_INTERLEAVE_* AUDIO_STREAM_MIN AUDIO_SESSION_ALLOCATE Change-Id: I31dd6f327204685e50716079ce21c4ba206dff11 --- media/libmedia/AudioTrack.cpp | 12 ++++++------ media/libmedia/ToneGenerator.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 20c1cdb..74c1800 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -333,8 +333,8 @@ status_t AudioTrack::set( mOffloadInfo = NULL; } - mVolume[LEFT] = 1.0f; - mVolume[RIGHT] = 1.0f; + mVolume[AUDIO_INTERLEAVE_LEFT] = 1.0f; + mVolume[AUDIO_INTERLEAVE_RIGHT] = 1.0f; mSendLevel = 0.0f; // mFrameCount is initialized in createTrack_l mReqFrameCount = frameCount; @@ -573,8 +573,8 @@ status_t AudioTrack::setVolume(float left, float right) } AutoMutex lock(mLock); - mVolume[LEFT] = left; - mVolume[RIGHT] = right; + mVolume[AUDIO_INTERLEAVE_LEFT] = left; + mVolume[AUDIO_INTERLEAVE_RIGHT] = right; mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000)); @@ -1134,8 +1134,8 @@ status_t AudioTrack::createTrack_l(size_t epoch) mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF); mProxy = mStaticProxy; } - mProxy->setVolumeLR((uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | - uint16_t(mVolume[LEFT] * 0x1000)); + mProxy->setVolumeLR((uint32_t(uint16_t(mVolume[AUDIO_INTERLEAVE_RIGHT] * 0x1000)) << 16) | + uint16_t(mVolume[AUDIO_INTERLEAVE_LEFT] * 0x1000)); mProxy->setSendLevel(mSendLevel); mProxy->setSampleRate(mSampleRate); mProxy->setEpoch(epoch); diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp index adef3be..61b6d36 100644 --- a/media/libmedia/ToneGenerator.cpp +++ b/media/libmedia/ToneGenerator.cpp @@ -1057,7 +1057,7 @@ bool ToneGenerator::initAudioTrack() { 0, // notificationFrames 0, // sharedBuffer mThreadCanCallJava, - 0, // sessionId + AUDIO_SESSION_ALLOCATE, AudioTrack::TRANSFER_CALLBACK); if (mpAudioTrack->initCheck() != NO_ERROR) { -- cgit v1.1 From 45faf7e02791993a487d6e038d16ff46395f1975 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 17 Jan 2014 10:23:01 -0800 Subject: Use symbol AUDIO_DEVICE_NONE from Change-Id: I61f882c5e7c949bf00d3bfc745ebf3b5e1c42a58 --- media/libmedia/AudioSystem.cpp | 2 +- media/libmedia/IAudioFlinger.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 140fb66..dafccd6 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -739,7 +739,7 @@ uint32_t AudioSystem::getStrategyForStream(audio_stream_type_t stream) audio_devices_t AudioSystem::getDevicesForStream(audio_stream_type_t stream) { const sp& aps = AudioSystem::get_audio_policy_service(); - if (aps == 0) return (audio_devices_t)0; + if (aps == 0) return AUDIO_DEVICE_NONE; return aps->getDevicesForStream(stream); } diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 762681e..67564ee 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -410,7 +410,7 @@ public: const audio_offload_info_t *offloadInfo) { Parcel data, reply; - audio_devices_t devices = pDevices != NULL ? *pDevices : (audio_devices_t)0; + audio_devices_t devices = pDevices != NULL ? *pDevices : AUDIO_DEVICE_NONE; uint32_t samplingRate = pSamplingRate != NULL ? *pSamplingRate : 0; audio_format_t format = pFormat != NULL ? *pFormat : AUDIO_FORMAT_DEFAULT; audio_channel_mask_t channelMask = pChannelMask != NULL ? @@ -501,7 +501,7 @@ public: audio_channel_mask_t *pChannelMask) { Parcel data, reply; - audio_devices_t devices = pDevices != NULL ? *pDevices : (audio_devices_t)0; + audio_devices_t devices = pDevices != NULL ? *pDevices : AUDIO_DEVICE_NONE; uint32_t samplingRate = pSamplingRate != NULL ? *pSamplingRate : 0; audio_format_t format = pFormat != NULL ? *pFormat : AUDIO_FORMAT_DEFAULT; audio_channel_mask_t channelMask = pChannelMask != NULL ? -- cgit v1.1 From 241618f1b286f9e7e02fe61e96d9194e2e1e8a7a Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 25 Mar 2014 17:48:57 -0700 Subject: Remove streamType parameter from AudioSystem::getLatency() Change-Id: Ie7346e93436ddc215cad7d16be555dcb6c277d54 --- media/libmedia/AudioSystem.cpp | 5 ++--- media/libmedia/AudioTrack.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 140fb66..758e660 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -333,11 +333,10 @@ status_t AudioSystem::getOutputLatency(uint32_t* latency, audio_stream_type_t st return PERMISSION_DENIED; } - return getLatency(output, streamType, latency); + return getLatency(output, latency); } status_t AudioSystem::getLatency(audio_io_handle_t output, - audio_stream_type_t streamType __unused, uint32_t* latency) { OutputDescriptor *outputDesc; @@ -354,7 +353,7 @@ status_t AudioSystem::getLatency(audio_io_handle_t output, gLock.unlock(); } - ALOGV("getLatency() streamType %d, output %d, latency %d", streamType, output, *latency); + ALOGV("getLatency() output %d, latency %d", output, *latency); return NO_ERROR; } diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 20c1cdb..fa7249b 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -878,7 +878,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) // Not all of these values are needed under all conditions, but it is easier to get them all uint32_t afLatency; - status = AudioSystem::getLatency(output, mStreamType, &afLatency); + status = AudioSystem::getLatency(output, &afLatency); if (status != NO_ERROR) { ALOGE("getLatency(%d) failed status %d", output, status); goto release; -- cgit v1.1 From ebb80e4f9873cc1a5ee3f766323f622bb0c07ae5 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 26 Mar 2014 08:21:17 -0700 Subject: Remove dead code Change-Id: I0878d11451c7bbbf96b59f5fe0cd97ba1f033aa9 --- media/libmedia/AudioTrack.cpp | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 20c1cdb..62fd7b9 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -371,16 +371,6 @@ status_t AudioTrack::set( mAudioTrackThread->requestExitAndWait(); mAudioTrackThread.clear(); } - // Use of direct and offloaded output streams is ref counted by audio policy manager. -#if 0 // FIXME This should no longer be needed - //Use of direct and offloaded output streams is ref counted by audio policy manager. - // As getOutput was called above and resulted in an output stream to be opened, - // we need to release it. - if (mOutput != 0) { - AudioSystem::releaseOutput(mOutput); - mOutput = 0; - } -#endif return status; } @@ -1775,16 +1765,6 @@ status_t AudioTrack::restoreTrack_l(const char *from) } } if (result != NO_ERROR) { - // Use of direct and offloaded output streams is ref counted by audio policy manager. -#if 0 // FIXME This should no longer be needed - //Use of direct and offloaded output streams is ref counted by audio policy manager. - // As getOutput was called above and resulted in an output stream to be opened, - // we need to release it. - if (mOutput != 0) { - AudioSystem::releaseOutput(mOutput); - mOutput = 0; - } -#endif ALOGW("restoreTrack_l() failed status %d", result); mState = STATE_STOPPED; } -- cgit v1.1 From 0ed19594452c901c3c8665d06610fffe46895d06 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 26 Mar 2014 07:50:05 -0700 Subject: Remove stream type from AudioSystem::getRenderPosition() The I/O handle is never equal to AUDIO_IO_HANDLE_NONE, so the stream type is not needed. Change-Id: I1ab134a2fa379d6dd0b6167345a856a192d478f9 --- media/libmedia/AudioSystem.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 140fb66..ac93a3a 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -401,19 +401,11 @@ status_t AudioSystem::setVoiceVolume(float value) } status_t AudioSystem::getRenderPosition(audio_io_handle_t output, uint32_t *halFrames, - uint32_t *dspFrames, audio_stream_type_t stream) + uint32_t *dspFrames) { const sp& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; - if (stream == AUDIO_STREAM_DEFAULT) { - stream = AUDIO_STREAM_MUSIC; - } - - if (output == 0) { - output = getOutput(stream); - } - return af->getRenderPosition(halFrames, dspFrames, output); } -- cgit v1.1 From adad3d7d935da176ff24941b4ae9edf7340e9b96 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 21 Feb 2014 14:51:43 -0800 Subject: Use LOG_ALWAYS_FATAL instead of LOG_FATAL LOG_FATAL is compiled out in most builds, so the assertion checks were not being performed. Change-Id: I774f0985ab9c5ccecd8989a0f1c940386b73fc35 --- media/libmedia/AudioTrackShared.cpp | 6 +++--- media/libmediaplayerservice/MediaPlayerService.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index fdd1a12..58c9fc1 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -200,7 +200,7 @@ status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *reques ts = &remaining; break; default: - LOG_FATAL("obtainBuffer() timeout=%d", timeout); + LOG_ALWAYS_FATAL("obtainBuffer() timeout=%d", timeout); ts = NULL; break; } @@ -429,7 +429,7 @@ status_t AudioTrackClientProxy::waitStreamEndDone(const struct timespec *request ts = &remaining; break; default: - LOG_FATAL("waitStreamEndDone() timeout=%d", timeout); + LOG_ALWAYS_FATAL("waitStreamEndDone() timeout=%d", timeout); ts = NULL; break; } @@ -470,7 +470,7 @@ StaticAudioTrackClientProxy::StaticAudioTrackClientProxy(audio_track_cblk_t* cbl void StaticAudioTrackClientProxy::flush() { - LOG_FATAL("static flush"); + LOG_ALWAYS_FATAL("static flush"); } void StaticAudioTrackClientProxy::setLoop(size_t loopStart, size_t loopEnd, int loopCount) diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 200c561..778eb9a 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1679,7 +1679,7 @@ void MediaPlayerService::AudioOutput::switchToNextOutput() { ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size) { - LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback."); + LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback."); //ALOGV("write(%p, %u)", buffer, size); if (mTrack != 0) { -- cgit v1.1 From 2301acc6a9c7a3af4ad01f3d1d0f76f13eca7350 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 17 Jan 2014 10:21:00 -0800 Subject: Update comments Change-Id: I5776313b9b49072cd666d28880f0d07cc73f827b --- media/libmedia/AudioSystem.cpp | 2 +- media/libmedia/IAudioFlinger.cpp | 2 ++ media/libmedia/IAudioPolicyService.cpp | 1 + media/libstagefright/AudioPlayer.cpp | 3 ++- 4 files changed, 6 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 8542404..a2cb619 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -35,8 +35,8 @@ Mutex AudioSystem::gLock; sp AudioSystem::gAudioFlinger; sp AudioSystem::gAudioFlingerClient; audio_error_callback AudioSystem::gAudioErrorCallback = NULL; -// Cached values +// Cached values for output handles DefaultKeyedVector AudioSystem::gOutputs(NULL); // Cached values for recording queries, all protected by gLock diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 2cb0c5c..eb813bd 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -109,6 +109,7 @@ public: data.writeInt32(frameCount); track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT; data.writeInt32(lFlags); + // haveSharedBuffer if (sharedBuffer != 0) { data.writeInt32(true); data.writeStrongBinder(sharedBuffer->asBinder()); @@ -424,6 +425,7 @@ public: data.writeInt32(channelMask); data.writeInt32(latency); data.writeInt32((int32_t) flags); + // hasOffloadInfo if (offloadInfo == NULL) { data.writeInt32(0); } else { diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 1a027a6..9bb4a49 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -137,6 +137,7 @@ public: data.writeInt32(static_cast (format)); data.writeInt32(channelMask); data.writeInt32(static_cast (flags)); + // hasOffloadInfo if (offloadInfo == NULL) { data.writeInt32(0); } else { diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index 8623100..2669849 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -221,7 +221,8 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) { mAudioTrack = new AudioTrack( AUDIO_STREAM_MUSIC, mSampleRate, AUDIO_FORMAT_PCM_16_BIT, audioMask, - 0, AUDIO_OUTPUT_FLAG_NONE, &AudioCallback, this, 0); + 0 /*frameCount*/, AUDIO_OUTPUT_FLAG_NONE, &AudioCallback, this, + 0 /*notificationFrames*/); if ((err = mAudioTrack->initCheck()) != OK) { mAudioTrack.clear(); -- cgit v1.1 From 142f519aa1acd5804d111e60d100f170fed28405 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 25 Mar 2014 17:44:59 -0700 Subject: Use symbol AUDIO_IO_HANDLE_NONE from Change-Id: Id6b1aa17558eb73e17f22b8eab6cd02e00a96dff --- media/libmedia/AudioRecord.cpp | 2 +- media/libmedia/AudioSystem.cpp | 14 +++++++------- media/libmedia/AudioTrack.cpp | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 961b0a2..a7bf380 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -471,7 +471,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) audio_io_handle_t input = AudioSystem::getInput(mInputSource, mSampleRate, mFormat, mChannelMask, mSessionId); - if (input == 0) { + if (input == AUDIO_IO_HANDLE_NONE) { ALOGE("Could not get audio input for record source %d, sample rate %u, format %#x, " "channel mask %#x, session %d", mInputSource, mSampleRate, mFormat, mChannelMask, mSessionId); diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 8542404..301c7d6 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -196,12 +196,12 @@ String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& ke status_t AudioSystem::setParameters(const String8& keyValuePairs) { - return setParameters((audio_io_handle_t) 0, keyValuePairs); + return setParameters(AUDIO_IO_HANDLE_NONE, keyValuePairs); } String8 AudioSystem::getParameters(const String8& keys) { - return getParameters((audio_io_handle_t) 0, keys); + return getParameters(AUDIO_IO_HANDLE_NONE, keys); } // convert volume steps to natural log scale @@ -284,7 +284,7 @@ status_t AudioSystem::getOutputFrameCount(size_t* frameCount, audio_stream_type_ } output = getOutput(streamType); - if (output == 0) { + if (output == AUDIO_IO_HANDLE_NONE) { return PERMISSION_DENIED; } @@ -329,7 +329,7 @@ status_t AudioSystem::getOutputLatency(uint32_t* latency, audio_stream_type_t st } output = getOutput(streamType); - if (output == 0) { + if (output == AUDIO_IO_HANDLE_NONE) { return PERMISSION_DENIED; } @@ -413,7 +413,7 @@ uint32_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) const sp& af = AudioSystem::get_audio_flinger(); uint32_t result = 0; if (af == 0) return result; - if (ioHandle == 0) return result; + if (ioHandle == AUDIO_IO_HANDLE_NONE) return result; result = af->getInputFramesLost(ioHandle); return result; @@ -464,7 +464,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle const OutputDescriptor *desc; audio_stream_type_t stream; - if (ioHandle == 0) return; + if (ioHandle == AUDIO_IO_HANDLE_NONE) return; Mutex::Autolock _l(AudioSystem::gLock); @@ -738,7 +738,7 @@ audio_io_handle_t AudioSystem::getOutputForEffect(const effect_descriptor_t *des { const sp& aps = AudioSystem::get_audio_policy_service(); // FIXME change return type to status_t, and return PERMISSION_DENIED here - if (aps == 0) return 0; + if (aps == 0) return AUDIO_IO_HANDLE_NONE; return aps->getOutputForEffect(desc); } diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 22760d9..fbfd3da 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -546,7 +546,7 @@ void AudioTrack::pause() mAudioTrack->pause(); if (isOffloaded_l()) { - if (mOutput != 0) { + if (mOutput != AUDIO_IO_HANDLE_NONE) { uint32_t halFrames; // OffloadThread sends HAL pause in its threadLoop.. time saved // here can be slightly off @@ -633,7 +633,7 @@ uint32_t AudioTrack::getSampleRate() const // query the HAL and update if needed. // FIXME use Proxy return channel to update the rate from server and avoid polling here if (isOffloaded_l()) { - if (mOutput != 0) { + if (mOutput != AUDIO_IO_HANDLE_NONE) { uint32_t sampleRate = 0; status_t status = AudioSystem::getSamplingRate(mOutput, mStreamType, &sampleRate); if (status == NO_ERROR) { @@ -779,7 +779,7 @@ status_t AudioTrack::getPosition(uint32_t *position) const return NO_ERROR; } - if (mOutput != 0) { + if (mOutput != AUDIO_IO_HANDLE_NONE) { uint32_t halFrames; AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames); } @@ -855,7 +855,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) audio_io_handle_t output = AudioSystem::getOutput(mStreamType, mSampleRate, mFormat, mChannelMask, mFlags, mOffloadInfo); - if (output == 0) { + if (output == AUDIO_IO_HANDLE_NONE) { ALOGE("Could not get audio output for stream type %d, sample rate %u, format %#x, " "channel mask %#x, flags %#x", mStreamType, mSampleRate, mFormat, mChannelMask, mFlags); @@ -1798,7 +1798,7 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) String8 AudioTrack::getParameters(const String8& keys) { audio_io_handle_t output = getOutput(); - if (output != 0) { + if (output != AUDIO_IO_HANDLE_NONE) { return AudioSystem::getParameters(output, keys); } else { return String8::empty(); -- cgit v1.1 From f5ee327780ea2b538b8affafa8063f0ce0390fe0 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 27 Mar 2014 16:41:37 -0700 Subject: DO NOT MERGE: Revert "stagefright: allow for minUndequeuedBufs to be one less" This reverts commit a0470879e25394cb85437366fa53ce8055cd556f. Bug: 13655631 --- media/libstagefright/ACodec.cpp | 7 +++---- media/libstagefright/OMXCodec.cpp | 10 ++++------ 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 3ad3ca7..14d99cf 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -640,8 +640,8 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( // FIXME: assume that surface is controlled by app (native window // returns the number for the case when surface is not controlled by app) - // FIXME2: This means that minUndeqeueudBufs can be 1 larger than reported - // For now, try to allocate 1 more buffer, but don't fail if unsuccessful + (*minUndequeuedBuffers)++; + // Use conservative allocation while also trying to reduce starvation // @@ -649,8 +649,7 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( // minimum needed for the consumer to be able to work // 2. try to allocate two (2) additional buffers to reduce starvation from // the consumer - // plus an extra buffer to account for incorrect minUndequeuedBufs - for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) { + for (OMX_U32 extraBuffers = 2; /* condition inside loop */; extraBuffers--) { OMX_U32 newBufferCount = def.nBufferCountMin + *minUndequeuedBuffers + extraBuffers; def.nBufferCountActual = newBufferCount; diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 070e438..79a9665 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1780,8 +1780,7 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { } // FIXME: assume that surface is controlled by app (native window // returns the number for the case when surface is not controlled by app) - // FIXME2: This means that minUndeqeueudBufs can be 1 larger than reported - // For now, try to allocate 1 more buffer, but don't fail if unsuccessful + minUndequeuedBufs++; // Use conservative allocation while also trying to reduce starvation // @@ -1789,11 +1788,10 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { // minimum needed for the consumer to be able to work // 2. try to allocate two (2) additional buffers to reduce starvation from // the consumer - // plus an extra buffer to account for incorrect minUndequeuedBufs - CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d+1", + CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d", def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs); - for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) { + for (OMX_U32 extraBuffers = 2; /* condition inside loop */; extraBuffers--) { OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs + extraBuffers; def.nBufferCountActual = newBufferCount; @@ -1812,7 +1810,7 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { return err; } } - CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d+1", + CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d", def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs); err = native_window_set_buffer_count( -- cgit v1.1 From 114c1b6553e3d2dc5f2780a76d92bb382234220c Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 27 Mar 2014 16:44:23 -0700 Subject: DO NOT MERGE: Revert "mediaplayer: keep more buffers with the BufferQueue" This reverts commit b635b0e66b257ab442e230bca96afd5105cf6829. Bug: 13655631 --- media/libstagefright/ACodec.cpp | 47 +++++++++++++++++---------------------- media/libstagefright/OMXCodec.cpp | 38 ++++++++----------------------- 2 files changed, 30 insertions(+), 55 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 14d99cf..9276818 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -638,33 +638,18 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( return err; } - // FIXME: assume that surface is controlled by app (native window - // returns the number for the case when surface is not controlled by app) - (*minUndequeuedBuffers)++; - - - // Use conservative allocation while also trying to reduce starvation - // - // 1. allocate at least nBufferCountMin + minUndequeuedBuffers - that is the - // minimum needed for the consumer to be able to work - // 2. try to allocate two (2) additional buffers to reduce starvation from - // the consumer - for (OMX_U32 extraBuffers = 2; /* condition inside loop */; extraBuffers--) { - OMX_U32 newBufferCount = - def.nBufferCountMin + *minUndequeuedBuffers + extraBuffers; + // XXX: Is this the right logic to use? It's not clear to me what the OMX + // buffer counts refer to - how do they account for the renderer holding on + // to buffers? + if (def.nBufferCountActual < def.nBufferCountMin + *minUndequeuedBuffers) { + OMX_U32 newBufferCount = def.nBufferCountMin + *minUndequeuedBuffers; def.nBufferCountActual = newBufferCount; err = mOMX->setParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - if (err == OK) { - *minUndequeuedBuffers += extraBuffers; - break; - } - - ALOGW("[%s] setting nBufferCountActual to %lu failed: %d", - mComponentName.c_str(), newBufferCount, err); - /* exit condition */ - if (extraBuffers == 0) { + if (err != OK) { + ALOGE("[%s] setting nBufferCountActual to %lu failed: %d", + mComponentName.c_str(), newBufferCount, err); return err; } } @@ -689,7 +674,6 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { &bufferCount, &bufferSize, &minUndequeuedBuffers); if (err != 0) return err; - mNumUndequeuedBuffers = minUndequeuedBuffers; ALOGV("[%s] Allocating %lu buffers from a native window of size %lu on " "output port", @@ -755,7 +739,6 @@ status_t ACodec::allocateOutputMetaDataBuffers() { &bufferCount, &bufferSize, &minUndequeuedBuffers); if (err != 0) return err; - mNumUndequeuedBuffers = minUndequeuedBuffers; ALOGV("[%s] Allocating %lu meta buffers on output port", mComponentName.c_str(), bufferCount); @@ -2446,7 +2429,19 @@ void ACodec::waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs() { return; } - while (countBuffersOwnedByNativeWindow() > mNumUndequeuedBuffers + int minUndequeuedBufs = 0; + status_t err = mNativeWindow->query( + mNativeWindow.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &minUndequeuedBufs); + + if (err != OK) { + ALOGE("[%s] NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)", + mComponentName.c_str(), strerror(-err), -err); + + minUndequeuedBufs = 0; + } + + while (countBuffersOwnedByNativeWindow() > (size_t)minUndequeuedBufs && dequeueBufferFromNativeWindow() != NULL) { // these buffers will be submitted as regular buffers; account for this if (mStoreMetaDataInOutputBuffers && mMetaDataBuffersToSubmit > 0) { diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 79a9665..43736ad 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -92,7 +92,6 @@ static sp InstantiateSoftwareEncoder( #define CODEC_LOGI(x, ...) ALOGI("[%s] "x, mComponentName, ##__VA_ARGS__) #define CODEC_LOGV(x, ...) ALOGV("[%s] "x, mComponentName, ##__VA_ARGS__) -#define CODEC_LOGW(x, ...) ALOGW("[%s] "x, mComponentName, ##__VA_ARGS__) #define CODEC_LOGE(x, ...) ALOGE("[%s] "x, mComponentName, ##__VA_ARGS__) struct OMXCodecObserver : public BnOMXObserver { @@ -1778,40 +1777,21 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { strerror(-err), -err); return err; } - // FIXME: assume that surface is controlled by app (native window - // returns the number for the case when surface is not controlled by app) - minUndequeuedBufs++; - - // Use conservative allocation while also trying to reduce starvation - // - // 1. allocate at least nBufferCountMin + minUndequeuedBuffers - that is the - // minimum needed for the consumer to be able to work - // 2. try to allocate two (2) additional buffers to reduce starvation from - // the consumer - CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d", - def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs); - - for (OMX_U32 extraBuffers = 2; /* condition inside loop */; extraBuffers--) { - OMX_U32 newBufferCount = - def.nBufferCountMin + minUndequeuedBufs + extraBuffers; + + // XXX: Is this the right logic to use? It's not clear to me what the OMX + // buffer counts refer to - how do they account for the renderer holding on + // to buffers? + if (def.nBufferCountActual < def.nBufferCountMin + minUndequeuedBufs) { + OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs; def.nBufferCountActual = newBufferCount; err = mOMX->setParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err == OK) { - minUndequeuedBufs += extraBuffers; - break; - } - - CODEC_LOGW("setting nBufferCountActual to %lu failed: %d", - newBufferCount, err); - /* exit condition */ - if (extraBuffers == 0) { + if (err != OK) { + CODEC_LOGE("setting nBufferCountActual to %lu failed: %d", + newBufferCount, err); return err; } } - CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d", - def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs); err = native_window_set_buffer_count( mNativeWindow.get(), def.nBufferCountActual); -- cgit v1.1 From b47558f87ee9bd4fce11a2d5bc213bd1aa9031a8 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 28 Mar 2014 09:53:46 -0700 Subject: mediaplayer: add temporary developer settings to use NuPlayer as default Bug: 11784824 Change-Id: Ic98f5fd15ee283d7f581bdc3331d000198ecc9e8 --- media/libmediaplayerservice/MediaPlayerFactory.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp index 90aed39..74e5013 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.cpp +++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp @@ -67,6 +67,12 @@ player_type MediaPlayerFactory::getDefaultPlayerType() { return NU_PLAYER; } + // TODO: remove this EXPERIMENTAL developer settings property + if (property_get("persist.sys.media.use-nuplayer", value, NULL) + && !strcasecmp("true", value)) { + return NU_PLAYER; + } + return STAGEFRIGHT_PLAYER; } -- cgit v1.1 From 5e184b0d12f1ec436246a391da8d9355cc21ee08 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 28 Mar 2014 14:37:51 -0700 Subject: ACodec: ignore OMX messages to already freed component Bug: 12916984 Change-Id: I92848797b8d556cff468b9b0f0a618946083208f --- media/libstagefright/ACodec.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 9164e5c..ac40568 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -3103,6 +3103,14 @@ bool ACodec::BaseState::onOMXMessage(const sp &msg) { int32_t type; CHECK(msg->findInt32("type", &type)); + // there is a possibility that this is an outstanding message for a + // codec that we have already destroyed + if (mCodec->mNode == NULL) { + ALOGI("ignoring message as already freed component: %s", + msg->debugString().c_str()); + return true; + } + IOMX::node_id nodeID; CHECK(msg->findPointer("node", &nodeID)); CHECK_EQ(nodeID, mCodec->mNode); -- cgit v1.1 From 68d9d71a792deed75d32fe13febc07c9c12c8449 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Tue, 4 Mar 2014 13:21:31 -0800 Subject: Support CAST V2 Authentication in MediaDrm Java API version Update frameworks to enable support for CAST V2 Authentication in the DRM Plugin. Change-Id: I9066ada0edf8e0d777c503897d8c7fc7f76f2861 related-to-bug: 12702350 --- media/libmedia/IDrm.cpp | 60 ++++++++++++++++++++++++++++++++++--- media/libmediaplayerservice/Drm.cpp | 30 ++++++++++++++++--- media/libmediaplayerservice/Drm.h | 14 +++++++-- 3 files changed, 94 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp index f7a9a75..f1a6a9f 100644 --- a/media/libmedia/IDrm.cpp +++ b/media/libmedia/IDrm.cpp @@ -51,6 +51,7 @@ enum { ENCRYPT, DECRYPT, SIGN, + SIGN_RSA, VERIFY, SET_LISTENER }; @@ -196,11 +197,15 @@ struct BpDrm : public BpInterface { return reply.readInt32(); } - virtual status_t getProvisionRequest(Vector &request, + virtual status_t getProvisionRequest(String8 const &certType, + String8 const &certAuthority, + Vector &request, String8 &defaultUrl) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + data.writeString8(certType); + data.writeString8(certAuthority); remote()->transact(GET_PROVISION_REQUEST, data, &reply); readVector(reply, request); @@ -209,13 +214,18 @@ struct BpDrm : public BpInterface { return reply.readInt32(); } - virtual status_t provideProvisionResponse(Vector const &response) { + virtual status_t provideProvisionResponse(Vector const &response, + Vector &certificate, + Vector &wrappedKey) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); writeVector(data, response); remote()->transact(PROVIDE_PROVISION_RESPONSE, data, &reply); + readVector(reply, certificate); + readVector(reply, wrappedKey); + return reply.readInt32(); } @@ -386,6 +396,25 @@ struct BpDrm : public BpInterface { return reply.readInt32(); } + virtual status_t signRSA(Vector const &sessionId, + String8 const &algorithm, + Vector const &message, + Vector const &wrappedKey, + Vector &signature) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, sessionId); + data.writeString8(algorithm); + writeVector(data, message); + writeVector(data, wrappedKey); + + remote()->transact(SIGN_RSA, data, &reply); + readVector(reply, signature); + + return reply.readInt32(); + } + virtual status_t setListener(const sp& listener) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); @@ -563,9 +592,13 @@ status_t BnDrm::onTransact( case GET_PROVISION_REQUEST: { CHECK_INTERFACE(IDrm, data, reply); + String8 certType = data.readString8(); + String8 certAuthority = data.readString8(); + Vector request; String8 defaultUrl; - status_t result = getProvisionRequest(request, defaultUrl); + status_t result = getProvisionRequest(certType, certAuthority, + request, defaultUrl); writeVector(reply, request); reply->writeString8(defaultUrl); reply->writeInt32(result); @@ -576,8 +609,13 @@ status_t BnDrm::onTransact( { CHECK_INTERFACE(IDrm, data, reply); Vector response; + Vector certificate; + Vector wrappedKey; readVector(data, response); - reply->writeInt32(provideProvisionResponse(response)); + status_t result = provideProvisionResponse(response, certificate, wrappedKey); + writeVector(reply, certificate); + writeVector(reply, wrappedKey); + reply->writeInt32(result); return OK; } @@ -725,6 +763,20 @@ status_t BnDrm::onTransact( return OK; } + case SIGN_RSA: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector sessionId, message, wrappedKey, signature; + readVector(data, sessionId); + String8 algorithm = data.readString8(); + readVector(data, message); + readVector(data, wrappedKey); + uint32_t result = signRSA(sessionId, algorithm, message, wrappedKey, signature); + writeVector(reply, signature); + reply->writeInt32(result); + return OK; + } + case SET_LISTENER: { CHECK_INTERFACE(IDrm, data, reply); sp listener = diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp index eebcb79..e68d4cd 100644 --- a/media/libmediaplayerservice/Drm.cpp +++ b/media/libmediaplayerservice/Drm.cpp @@ -373,7 +373,8 @@ status_t Drm::queryKeyStatus(Vector const &sessionId, return mPlugin->queryKeyStatus(sessionId, infoMap); } -status_t Drm::getProvisionRequest(Vector &request, String8 &defaultUrl) { +status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority, + Vector &request, String8 &defaultUrl) { Mutex::Autolock autoLock(mLock); if (mInitCheck != OK) { @@ -384,10 +385,13 @@ status_t Drm::getProvisionRequest(Vector &request, String8 &defaultUrl) return -EINVAL; } - return mPlugin->getProvisionRequest(request, defaultUrl); + return mPlugin->getProvisionRequest(certType, certAuthority, + request, defaultUrl); } -status_t Drm::provideProvisionResponse(Vector const &response) { +status_t Drm::provideProvisionResponse(Vector const &response, + Vector &certificate, + Vector &wrappedKey) { Mutex::Autolock autoLock(mLock); if (mInitCheck != OK) { @@ -398,7 +402,7 @@ status_t Drm::provideProvisionResponse(Vector const &response) { return -EINVAL; } - return mPlugin->provideProvisionResponse(response); + return mPlugin->provideProvisionResponse(response, certificate, wrappedKey); } @@ -589,6 +593,24 @@ status_t Drm::verify(Vector const &sessionId, return mPlugin->verify(sessionId, keyId, message, signature, match); } +status_t Drm::signRSA(Vector const &sessionId, + String8 const &algorithm, + Vector const &message, + Vector const &wrappedKey, + Vector &signature) { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature); +} + void Drm::binderDied(const wp &the_late_who) { delete mPlugin; diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h index 119fd50..3d4b0fc 100644 --- a/media/libmediaplayerservice/Drm.h +++ b/media/libmediaplayerservice/Drm.h @@ -66,10 +66,14 @@ struct Drm : public BnDrm, virtual status_t queryKeyStatus(Vector const &sessionId, KeyedVector &infoMap) const; - virtual status_t getProvisionRequest(Vector &request, + virtual status_t getProvisionRequest(String8 const &certType, + String8 const &certAuthority, + Vector &request, String8 &defaulUrl); - virtual status_t provideProvisionResponse(Vector const &response); + virtual status_t provideProvisionResponse(Vector const &response, + Vector &certificate, + Vector &wrappedKey); virtual status_t getSecureStops(List > &secureStops); @@ -111,6 +115,12 @@ struct Drm : public BnDrm, Vector const &signature, bool &match); + virtual status_t signRSA(Vector const &sessionId, + String8 const &algorithm, + Vector const &message, + Vector const &wrappedKey, + Vector &signature); + virtual status_t setListener(const sp& listener); virtual void sendEvent(DrmPlugin::EventType eventType, int extra, -- cgit v1.1 From ec5f7cc4756d389505e761b9d803a1a3a46b64d7 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 31 Mar 2014 12:30:01 -0700 Subject: MediaCodec: move to UNINITIALIZED state on codec error ACodec moves to Uninitialized state after receiving codec error. Make MediaCodec also move to the same state, so stop() and release() will work correctly. Bug: 13675112 Change-Id: I1c7e8b274f68345fc0e6a55c70dff6c7a4fb2e72 --- media/libstagefright/MediaCodec.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'media') diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index e0419ca..601dccf 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -603,6 +603,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { postActivityNotificationIfPossible(); cancelPendingDequeueOperations(); + setState(UNINITIALIZED); break; } @@ -612,6 +613,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { mFlags |= kFlagStickyError; postActivityNotificationIfPossible(); + setState(UNINITIALIZED); break; } } -- cgit v1.1 From 54b0bc74e051bd7df10cd657b481d88db6cdaa27 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 31 Mar 2014 12:30:01 -0700 Subject: ACodec: do not signal kWhatShutdownCompleted on codec error Do not signal kWhatShutdownCompleted when moving to Uninitialized state due to receiving a codec error. Do not abort if error happens just before handling a stop request. Bug: 13675112 Change-Id: I4b14b2e64cff0f71215d2bbc24cd850617dfb67b --- media/libstagefright/ACodec.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index ac40568..4aecb80 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -365,6 +365,7 @@ ACodec::ACodec() mIsEncoder(false), mUseMetadataOnEncoderOutput(false), mShutdownInProgress(false), + mExplicitShutdown(false), mEncoderDelay(0), mEncoderPadding(0), mChannelMaskPresent(false), @@ -3722,7 +3723,8 @@ bool ACodec::UninitializedState::onMessageReceived(const sp &msg) { int32_t keepComponentAllocated; CHECK(msg->findInt32( "keepComponentAllocated", &keepComponentAllocated)); - CHECK(!keepComponentAllocated); + ALOGW_IF(keepComponentAllocated, + "cannot keep component allocated on shutdown in Uninitialized state"); sp notify = mCodec->mNotify->dup(); notify->setInt32("what", ACodec::kWhatShutdownCompleted); @@ -3895,6 +3897,7 @@ void ACodec::LoadedState::stateEntered() { onShutdown(keepComponentAllocated); } + mCodec->mExplicitShutdown = false; } void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) { @@ -3904,9 +3907,12 @@ void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) { mCodec->changeState(mCodec->mUninitializedState); } - sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatShutdownCompleted); - notify->post(); + if (mCodec->mExplicitShutdown) { + sp notify = mCodec->mNotify->dup(); + notify->setInt32("what", ACodec::kWhatShutdownCompleted); + notify->post(); + mCodec->mExplicitShutdown = false; + } } bool ACodec::LoadedState::onMessageReceived(const sp &msg) { @@ -3940,6 +3946,7 @@ bool ACodec::LoadedState::onMessageReceived(const sp &msg) { CHECK(msg->findInt32( "keepComponentAllocated", &keepComponentAllocated)); + mCodec->mExplicitShutdown = true; onShutdown(keepComponentAllocated); handled = true; @@ -4359,6 +4366,7 @@ bool ACodec::ExecutingState::onMessageReceived(const sp &msg) { "keepComponentAllocated", &keepComponentAllocated)); mCodec->mShutdownInProgress = true; + mCodec->mExplicitShutdown = true; mCodec->mKeepComponentAllocated = keepComponentAllocated; mActive = false; -- cgit v1.1 From 81e0bd44a10e90778ab5b0a3babd4fc52cadedd8 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Wed, 2 Apr 2014 16:41:38 -0700 Subject: Add signature|system permission to MediaDrm signer APIs Change-Id: If970e5ff8dcab2e67af2f3376dcd14dca82f2394 related-to-bug: 12702350 --- media/libmediaplayerservice/Drm.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp index e68d4cd..d50037f 100644 --- a/media/libmediaplayerservice/Drm.cpp +++ b/media/libmediaplayerservice/Drm.cpp @@ -28,9 +28,21 @@ #include #include #include +#include +#include namespace android { +static bool checkPermission(const char* permissionString) { +#ifndef HAVE_ANDROID_OS + return true; +#endif + if (getpid() == IPCThreadState::self()->getCallingPid()) return true; + bool ok = checkCallingPermission(String16(permissionString)); + if (!ok) ALOGE("Request requires %s", permissionString); + return ok; +} + KeyedVector, String8> Drm::mUUIDToLibraryPathMap; KeyedVector > Drm::mLibraryPathToOpenLibraryMap; Mutex Drm::mMapLock; @@ -608,6 +620,10 @@ status_t Drm::signRSA(Vector const &sessionId, return -EINVAL; } + if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) { + return -EPERM; + } + return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature); } -- cgit v1.1 From bcf08569453dcb42730cda3230d5d375a697005b Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 4 Apr 2014 18:09:35 -0700 Subject: stagefright: add AString constructor from String8 Change-Id: I85b37b6dee4ea9d5f7f1c1a40ff405a01a0c67f1 --- media/libstagefright/foundation/AString.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'media') diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp index dee786d..fcd825f 100644 --- a/media/libstagefright/foundation/AString.cpp +++ b/media/libstagefright/foundation/AString.cpp @@ -20,6 +20,7 @@ #include #include +#include #include "ADebug.h" #include "AString.h" @@ -48,6 +49,13 @@ AString::AString(const char *s, size_t size) setTo(s, size); } +AString::AString(const String8 &from) + : mData(NULL), + mSize(0), + mAllocSize(1) { + setTo(from.string(), from.length()); +} + AString::AString(const AString &from) : mData(NULL), mSize(0), -- cgit v1.1 From a1df816c0677185534babba6ffc29970b048e52e Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 3 Apr 2014 19:13:01 -0700 Subject: stagefright: log uri protocols, and opt-in to log full uri Added property media.stagefright.log-uri. Set it to true or 1 to log uris by AwesomePlayer. Added utility function to get uri debug string based on incognito and log opt-in status. Change-Id: I5ccc23079ddfb120dd9703a3ed651a162ed5acec Related-Bug: 6994761 --- media/libstagefright/AwesomePlayer.cpp | 4 +-- media/libstagefright/Utils.cpp | 36 +++++++++++++++++++++++++++ media/libstagefright/httplive/LiveSession.cpp | 9 +++---- media/libstagefright/httplive/M3UParser.cpp | 3 ++- media/libstagefright/rtsp/ARTSPConnection.cpp | 2 +- media/libstagefright/rtsp/SDPLoader.cpp | 7 ++---- 6 files changed, 46 insertions(+), 15 deletions(-) (limited to 'media') diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 4bad14b..e924076 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -310,7 +310,7 @@ status_t AwesomePlayer::setDataSource_l( } } - ALOGI("setDataSource_l(URL suppressed)"); + ALOGI("setDataSource_l(%s)", uriDebugString(mUri, mFlags & INCOGNITO).c_str()); // The actual work will be done during preparation in the call to // ::finishSetDataSource_l to avoid blocking the calling thread in @@ -2823,7 +2823,7 @@ status_t AwesomePlayer::dump( fprintf(out, " AwesomePlayer\n"); if (mStats.mFd < 0) { - fprintf(out, " URI(suppressed)"); + fprintf(out, " URI(%s)", uriDebugString(mUri, mFlags & INCOGNITO).c_str()); } else { fprintf(out, " fd(%d)", mStats.mFd); } diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 4ff805f..047fac7 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "Utils" #include +#include #include "include/ESDS.h" @@ -628,5 +629,40 @@ bool canOffloadStream(const sp& meta, bool hasVideo, return AudioSystem::isOffloadSupported(info); } +AString uriDebugString(const AString &uri, bool incognito) { + if (incognito) { + return AString(""); + } + + char prop[PROPERTY_VALUE_MAX]; + if (property_get("media.stagefright.log-uri", prop, "false") && + (!strcmp(prop, "1") || !strcmp(prop, "true"))) { + return uri; + } + + // find scheme + AString scheme; + const char *chars = uri.c_str(); + for (size_t i = 0; i < uri.size(); i++) { + const char c = chars[i]; + if (!isascii(c)) { + break; + } else if (isalpha(c)) { + continue; + } else if (i == 0) { + // first character must be a letter + break; + } else if (isdigit(c) || c == '+' || c == '.' || c =='-') { + continue; + } else if (c != ':') { + break; + } + scheme = AString(uri, 0, i); + scheme.append("://"); + return scheme; + } + return AString(""); +} + } // namespace android diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index fd42e77..08a146f 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -477,11 +477,8 @@ void LiveSession::onConnect(const sp &msg) { headers = NULL; } -#if 1 - ALOGI("onConnect "); -#else - ALOGI("onConnect %s", url.c_str()); -#endif + // TODO currently we don't know if we are coming here from incognito mode + ALOGI("onConnect %s", uriDebugString(url).c_str()); mMasterURL = url; @@ -489,7 +486,7 @@ void LiveSession::onConnect(const sp &msg) { mPlaylist = fetchPlaylist(url.c_str(), NULL /* curPlaylistHash */, &dummy); if (mPlaylist == NULL) { - ALOGE("unable to fetch master playlist ."); + ALOGE("unable to fetch master playlist %s.", uriDebugString(url).c_str()); postPrepared(ERROR_IO); return; diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index f22d650..785c515 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -798,7 +798,8 @@ status_t M3UParser::parseCipherInfo( if (MakeURL(baseURI.c_str(), val.c_str(), &absURI)) { val = absURI; } else { - ALOGE("failed to make absolute url for ."); + ALOGE("failed to make absolute url for %s.", + uriDebugString(baseURI).c_str()); } } diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp index cc3b63c..f25539c 100644 --- a/media/libstagefright/rtsp/ARTSPConnection.cpp +++ b/media/libstagefright/rtsp/ARTSPConnection.cpp @@ -239,7 +239,7 @@ void ARTSPConnection::onConnect(const sp &msg) { // right here, since we currently have no way of asking the user // for this information. - ALOGE("Malformed rtsp url "); + ALOGE("Malformed rtsp url %s", uriDebugString(url).c_str()); reply->setInt32("result", ERROR_MALFORMED); reply->post(); diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp index 09f7eee..424badf 100644 --- a/media/libstagefright/rtsp/SDPLoader.cpp +++ b/media/libstagefright/rtsp/SDPLoader.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #define DEFAULT_SDP_SIZE 100000 @@ -89,11 +90,7 @@ void SDPLoader::onLoad(const sp &msg) { KeyedVector *headers = NULL; msg->findPointer("headers", (void **)&headers); - if (!(mFlags & kFlagIncognito)) { - ALOGV("onLoad '%s'", url.c_str()); - } else { - ALOGI("onLoad "); - } + ALOGV("onLoad %s", uriDebugString(url, mFlags & kFlagIncognito).c_str()); if (!mCancelled) { err = mHTTPDataSource->connect(url.c_str(), headers); -- cgit v1.1 From c51db0a6bfb71ea9c934fb7971cb5ae1f1cf03a0 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 2 Apr 2014 07:35:29 -0700 Subject: stagefright: handle corrupt matroska files gracefully Bug: 13693438 Bug: 13744158 Change-Id: I557595b5b5d4a20934f79e00a622b06d13378223 --- media/libstagefright/matroska/MatroskaExtractor.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index d4a7c7f..d7bec59 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -657,14 +657,22 @@ MatroskaExtractor::MatroskaExtractor(const sp &source) return; } + // from mkvparser::Segment::Load(), but stop at first cluster ret = mSegment->ParseHeaders(); - CHECK_EQ(ret, 0); - - long len; - ret = mSegment->LoadCluster(pos, len); - CHECK_EQ(ret, 0); + if (ret == 0) { + long len; + ret = mSegment->LoadCluster(pos, len); + if (ret >= 1) { + // no more clusters + ret = 0; + } + } else if (ret > 0) { + ret = mkvparser::E_BUFFER_NOT_FULL; + } if (ret < 0) { + ALOGW("Corrupt %s source: %s", mIsWebm ? "webm" : "matroska", + uriDebugString(mDataSource->getUri()).c_str()); delete mSegment; mSegment = NULL; return; -- cgit v1.1 From 0f37620e0f79bfab1354e2e3049c260342a2637e Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 11 Apr 2014 11:54:52 -0700 Subject: Revert "build fix for aosp-idea133 @ 1119318" Build fix is needed in AOSP, but in master it re-introduces a warning and breaks the build on -Werror. Revert it in master. This reverts commit effbb3a9b72050dbe150af7302d9148fe7e927d3. --- media/libstagefright/timedtext/TimedTextDriver.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'media') diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp index 05d6d02..71aa21e 100644 --- a/media/libstagefright/timedtext/TimedTextDriver.cpp +++ b/media/libstagefright/timedtext/TimedTextDriver.cpp @@ -45,6 +45,7 @@ TimedTextDriver::TimedTextDriver( const sp &httpService) : mLooper(new ALooper), mListener(listener), + mHTTPService(httpService), mState(UNINITIALIZED), mCurrentTrackIndex(UINT_MAX) { mLooper->setName("TimedTextDriver"); -- cgit v1.1 From 2475264264b51a7592c5b2e4cd6cfdaddba16644 Mon Sep 17 00:00:00 2001 From: Dan Stoza Date: Wed, 9 Apr 2014 16:10:53 -0700 Subject: BufferQueue: Increase max slots from 32 to 64 Increases NUM_BUFFER_SLOTS from 32 to 64 and changes the mask returned by IGBC::getReleasedBuffers from 32 to 64 bits. Bug: 13174352 Change-Id: I1c41256ffbc30abcf9f7b0b5fcf53da40462da28 --- media/libstagefright/omx/GraphicBufferSource.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 1be76b3..0b4a616 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -27,6 +27,8 @@ #include #include +#include + namespace android { static const bool EXTRA_CHECK = true; @@ -761,13 +763,13 @@ void GraphicBufferSource::onFrameAvailable() { void GraphicBufferSource::onBuffersReleased() { Mutex::Autolock lock(mMutex); - uint32_t slotMask; + uint64_t slotMask; if (mConsumer->getReleasedBuffers(&slotMask) != NO_ERROR) { ALOGW("onBuffersReleased: unable to get released buffer set"); - slotMask = 0xffffffff; + slotMask = 0xffffffffffffffffULL; } - ALOGV("onBuffersReleased: 0x%08x", slotMask); + ALOGV("onBuffersReleased: 0x%016" PRIx64, slotMask); for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { if ((slotMask & 0x01) != 0) { -- cgit v1.1 From 4154795d5526750b7aec5f774831a9e1ba0a3f15 Mon Sep 17 00:00:00 2001 From: Alex Glaznev Date: Thu, 20 Mar 2014 17:32:57 -0700 Subject: Support VP8 encoder key frame interval and number of temporal layers configuration. - Change ACodec.cpp to populate VP8 extra parameters structure with key frame interval, number of temporal layers and quantization parameters. - Change software VP8 encoder to select frame temporal patterns and temporal layers bitrate distribution based on the number of layers similar to patterns used in WebRTC. - Calculate video frame duration in VP8 encoder from the timestamps. Bug: 11969958 Change-Id: Ia96054d886cd09d8c108dfe250fc5f4478eaa042 --- media/libstagefright/ACodec.cpp | 70 ++++++ .../codecs/on2/enc/SoftVPXEncoder.cpp | 258 ++++++++++++++++++++- .../libstagefright/codecs/on2/enc/SoftVPXEncoder.h | 78 +++++++ 3 files changed, 394 insertions(+), 12 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 9164e5c..20a5a8b 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -2369,12 +2370,81 @@ status_t ACodec::setupAVCEncoderParameters(const sp &msg) { status_t ACodec::setupVPXEncoderParameters(const sp &msg) { int32_t bitrate; + int32_t iFrameInterval = 0; + size_t tsLayers = 0; + OMX_VIDEO_ANDROID_VPXTEMPORALLAYERPATTERNTYPE pattern = + OMX_VIDEO_VPXTemporalLayerPatternNone; + static const uint32_t kVp8LayerRateAlloction + [OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS] + [OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS] = { + {100, 100, 100}, // 1 layer + { 60, 100, 100}, // 2 layers {60%, 40%} + { 40, 60, 100}, // 3 layers {40%, 20%, 40%} + }; if (!msg->findInt32("bitrate", &bitrate)) { return INVALID_OPERATION; } + msg->findInt32("i-frame-interval", &iFrameInterval); OMX_VIDEO_CONTROLRATETYPE bitrateMode = getBitrateMode(msg); + float frameRate; + if (!msg->findFloat("frame-rate", &frameRate)) { + int32_t tmp; + if (!msg->findInt32("frame-rate", &tmp)) { + return INVALID_OPERATION; + } + frameRate = (float)tmp; + } + + AString tsSchema; + if (msg->findString("ts-schema", &tsSchema)) { + if (tsSchema == "webrtc.vp8.1-layer") { + pattern = OMX_VIDEO_VPXTemporalLayerPatternWebRTC; + tsLayers = 1; + } else if (tsSchema == "webrtc.vp8.2-layer") { + pattern = OMX_VIDEO_VPXTemporalLayerPatternWebRTC; + tsLayers = 2; + } else if (tsSchema == "webrtc.vp8.3-layer") { + pattern = OMX_VIDEO_VPXTemporalLayerPatternWebRTC; + tsLayers = 3; + } else { + ALOGW("Unsupported ts-schema [%s]", tsSchema.c_str()); + } + } + + OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE vp8type; + InitOMXParams(&vp8type); + vp8type.nPortIndex = kPortIndexOutput; + status_t err = mOMX->getParameter( + mNode, (OMX_INDEXTYPE)OMX_IndexParamVideoAndroidVp8Encoder, + &vp8type, sizeof(vp8type)); + + if (err == OK) { + if (iFrameInterval > 0) { + vp8type.nKeyFrameInterval = setPFramesSpacing(iFrameInterval, frameRate); + } + vp8type.eTemporalPattern = pattern; + vp8type.nTemporalLayerCount = tsLayers; + if (tsLayers > 0) { + for (size_t i = 0; i < OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS; i++) { + vp8type.nTemporalLayerBitrateRatio[i] = + kVp8LayerRateAlloction[tsLayers - 1][i]; + } + } + if (bitrateMode == OMX_Video_ControlRateConstant) { + vp8type.nMinQuantizer = 2; + vp8type.nMaxQuantizer = 63; + } + + err = mOMX->setParameter( + mNode, (OMX_INDEXTYPE)OMX_IndexParamVideoAndroidVp8Encoder, + &vp8type, sizeof(vp8type)); + if (err != OK) { + ALOGW("Extended VP8 parameters set failed: %d", err); + } + } + return configureBitrate(bitrate, bitrateMode); } diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp index b3a6bcc..dc38ea8 100644 --- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp +++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp @@ -27,7 +27,6 @@ namespace android { - template static void InitOMXParams(T *params) { params->nSize = sizeof(T); @@ -148,10 +147,20 @@ SoftVPXEncoder::SoftVPXEncoder(const char *name, mErrorResilience(OMX_FALSE), mColorFormat(OMX_COLOR_FormatYUV420Planar), mLevel(OMX_VIDEO_VP8Level_Version0), + mKeyFrameInterval(0), + mMinQuantizer(0), + mMaxQuantizer(0), + mTemporalLayers(0), + mTemporalPatternType(OMX_VIDEO_VPXTemporalLayerPatternNone), + mTemporalPatternLength(0), + mTemporalPatternIdx(0), + mLastTimestamp(0x7FFFFFFFFFFFFFFFLL), mConversionBuffer(NULL), mInputDataIsMeta(false), mGrallocModule(NULL), mKeyFrameRequested(false) { + memset(mTemporalLayerBitrateRatio, 0, sizeof(mTemporalLayerBitrateRatio)); + mTemporalLayerBitrateRatio[0] = 100; initPorts(); } @@ -235,7 +244,9 @@ status_t SoftVPXEncoder::initEncoder() { if (mCodecInterface == NULL) { return UNKNOWN_ERROR; } - + ALOGD("VP8: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u", + (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval, + mMinQuantizer, mMaxQuantizer); codec_return = vpx_codec_enc_config_default(mCodecInterface, mCodecConfiguration, 0); // Codec specific flags @@ -276,7 +287,7 @@ status_t SoftVPXEncoder::initEncoder() { mCodecConfiguration->g_timebase.num = 1; mCodecConfiguration->g_timebase.den = 1000000; // rc_target_bitrate is in kbps, mBitrate in bps - mCodecConfiguration->rc_target_bitrate = mBitrate / 1000; + mCodecConfiguration->rc_target_bitrate = (mBitrate + 500) / 1000; mCodecConfiguration->rc_end_usage = mBitrateControlMode; // Disable frame drop - not allowed in MediaCodec now. mCodecConfiguration->rc_dropframe_thresh = 0; @@ -285,10 +296,6 @@ status_t SoftVPXEncoder::initEncoder() { mCodecConfiguration->rc_resize_allowed = 0; // Single-pass mode. mCodecConfiguration->g_pass = VPX_RC_ONE_PASS; - // Minimum quantization level. - mCodecConfiguration->rc_min_quantizer = 2; - // Maximum quantization level. - mCodecConfiguration->rc_max_quantizer = 63; // Maximum amount of bits that can be subtracted from the target // bitrate - expressed as percentage of the target bitrate. mCodecConfiguration->rc_undershoot_pct = 100; @@ -306,10 +313,95 @@ status_t SoftVPXEncoder::initEncoder() { mCodecConfiguration->g_error_resilient = 1; // Disable lagged encoding. mCodecConfiguration->g_lag_in_frames = 0; + // Maximum key frame interval - for CBR boost to 3000 + mCodecConfiguration->kf_max_dist = 3000; // Encoder determines optimal key frame placement automatically. mCodecConfiguration->kf_mode = VPX_KF_AUTO; } + // Frames temporal pattern - for now WebRTC like pattern is only supported. + switch (mTemporalLayers) { + case 0: + { + mTemporalPatternLength = 0; + break; + } + case 1: + { + mCodecConfiguration->ts_number_layers = 1; + mCodecConfiguration->ts_rate_decimator[0] = 1; + mCodecConfiguration->ts_periodicity = 1; + mCodecConfiguration->ts_layer_id[0] = 0; + mTemporalPattern[0] = kTemporalUpdateLastRefAll; + mTemporalPatternLength = 1; + break; + } + case 2: + { + mCodecConfiguration->ts_number_layers = 2; + mCodecConfiguration->ts_rate_decimator[0] = 2; + mCodecConfiguration->ts_rate_decimator[1] = 1; + mCodecConfiguration->ts_periodicity = 2; + mCodecConfiguration->ts_layer_id[0] = 0; + mCodecConfiguration->ts_layer_id[1] = 1; + mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef; + mTemporalPattern[1] = kTemporalUpdateGoldenWithoutDependencyRefAltRef; + mTemporalPattern[2] = kTemporalUpdateLastRefAltRef; + mTemporalPattern[3] = kTemporalUpdateGoldenRefAltRef; + mTemporalPattern[4] = kTemporalUpdateLastRefAltRef; + mTemporalPattern[5] = kTemporalUpdateGoldenRefAltRef; + mTemporalPattern[6] = kTemporalUpdateLastRefAltRef; + mTemporalPattern[7] = kTemporalUpdateNone; + mTemporalPatternLength = 8; + break; + } + case 3: + { + mCodecConfiguration->ts_number_layers = 3; + mCodecConfiguration->ts_rate_decimator[0] = 4; + mCodecConfiguration->ts_rate_decimator[1] = 2; + mCodecConfiguration->ts_rate_decimator[2] = 1; + mCodecConfiguration->ts_periodicity = 4; + mCodecConfiguration->ts_layer_id[0] = 0; + mCodecConfiguration->ts_layer_id[1] = 2; + mCodecConfiguration->ts_layer_id[2] = 1; + mCodecConfiguration->ts_layer_id[3] = 2; + mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef; + mTemporalPattern[1] = kTemporalUpdateNoneNoRefGoldenRefAltRef; + mTemporalPattern[2] = kTemporalUpdateGoldenWithoutDependencyRefAltRef; + mTemporalPattern[3] = kTemporalUpdateNone; + mTemporalPattern[4] = kTemporalUpdateLastRefAltRef; + mTemporalPattern[5] = kTemporalUpdateNone; + mTemporalPattern[6] = kTemporalUpdateGoldenRefAltRef; + mTemporalPattern[7] = kTemporalUpdateNone; + mTemporalPatternLength = 8; + break; + } + default: + { + ALOGE("Wrong number of temporal layers %u", mTemporalLayers); + return UNKNOWN_ERROR; + } + } + + // Set bitrate values for each layer + for (size_t i = 0; i < mCodecConfiguration->ts_number_layers; i++) { + mCodecConfiguration->ts_target_bitrate[i] = + mCodecConfiguration->rc_target_bitrate * + mTemporalLayerBitrateRatio[i] / 100; + } + if (mKeyFrameInterval > 0) { + mCodecConfiguration->kf_max_dist = mKeyFrameInterval; + mCodecConfiguration->kf_min_dist = mKeyFrameInterval; + mCodecConfiguration->kf_mode = VPX_KF_AUTO; + } + if (mMinQuantizer > 0) { + mCodecConfiguration->rc_min_quantizer = mMinQuantizer; + } + if (mMaxQuantizer > 0) { + mCodecConfiguration->rc_max_quantizer = mMaxQuantizer; + } + codec_return = vpx_codec_enc_init(mCodecContext, mCodecInterface, mCodecConfiguration, @@ -466,6 +558,24 @@ OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index, return OMX_ErrorNone; } + case OMX_IndexParamVideoAndroidVp8Encoder: { + OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vp8AndroidParams = + (OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param; + + if (vp8AndroidParams->nPortIndex != kOutputPortIndex) { + return OMX_ErrorUnsupportedIndex; + } + + vp8AndroidParams->nKeyFrameInterval = mKeyFrameInterval; + vp8AndroidParams->eTemporalPattern = mTemporalPatternType; + vp8AndroidParams->nTemporalLayerCount = mTemporalLayers; + vp8AndroidParams->nMinQuantizer = mMinQuantizer; + vp8AndroidParams->nMaxQuantizer = mMaxQuantizer; + memcpy(vp8AndroidParams->nTemporalLayerBitrateRatio, + mTemporalLayerBitrateRatio, sizeof(mTemporalLayerBitrateRatio)); + return OMX_ErrorNone; + } + case OMX_IndexParamVideoProfileLevelQuerySupported: { OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel = (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param; @@ -552,11 +662,15 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index, return internalSetVp8Params( (const OMX_VIDEO_PARAM_VP8TYPE *)param); + case OMX_IndexParamVideoAndroidVp8Encoder: + return internalSetAndroidVp8Params( + (const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param); + case OMX_IndexParamVideoProfileLevelCurrent: return internalSetProfileLevel( (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param); - case OMX_IndexVendorStartUnused: + case kStoreMetaDataExtensionIndex: { // storeMetaDataInBuffers const StoreMetaDataInBuffersParams *storeParam = @@ -665,6 +779,50 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetVp8Params( return OMX_ErrorNone; } +OMX_ERRORTYPE SoftVPXEncoder::internalSetAndroidVp8Params( + const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE* vp8AndroidParams) { + if (vp8AndroidParams->nPortIndex != kOutputPortIndex) { + return OMX_ErrorUnsupportedIndex; + } + if (vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternNone && + vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternWebRTC) { + return OMX_ErrorBadParameter; + } + if (vp8AndroidParams->nTemporalLayerCount > OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS) { + return OMX_ErrorBadParameter; + } + if (vp8AndroidParams->nMinQuantizer > vp8AndroidParams->nMaxQuantizer) { + return OMX_ErrorBadParameter; + } + + mTemporalPatternType = vp8AndroidParams->eTemporalPattern; + if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternWebRTC) { + mTemporalLayers = vp8AndroidParams->nTemporalLayerCount; + } else if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternNone) { + mTemporalLayers = 0; + } + // Check the bitrate distribution between layers is in increasing order + if (mTemporalLayers > 1) { + for (size_t i = 0; i < mTemporalLayers - 1; i++) { + if (vp8AndroidParams->nTemporalLayerBitrateRatio[i + 1] <= + vp8AndroidParams->nTemporalLayerBitrateRatio[i]) { + ALOGE("Wrong bitrate ratio - should be in increasing order."); + return OMX_ErrorBadParameter; + } + } + } + mKeyFrameInterval = vp8AndroidParams->nKeyFrameInterval; + mMinQuantizer = vp8AndroidParams->nMinQuantizer; + mMaxQuantizer = vp8AndroidParams->nMaxQuantizer; + memcpy(mTemporalLayerBitrateRatio, vp8AndroidParams->nTemporalLayerBitrateRatio, + sizeof(mTemporalLayerBitrateRatio)); + ALOGD("VP8: internalSetAndroidVp8Params. BRMode: %u. TS: %zu. KF: %u." + " QP: %u - %u BR0: %u. BR1: %u. BR2: %u", + (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval, + mMinQuantizer, mMaxQuantizer, mTemporalLayerBitrateRatio[0], + mTemporalLayerBitrateRatio[1], mTemporalLayerBitrateRatio[2]); + return OMX_ErrorNone; +} OMX_ERRORTYPE SoftVPXEncoder::internalSetFormatParams( const OMX_VIDEO_PARAM_PORTFORMATTYPE* format) { @@ -728,7 +886,7 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams( OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef; def->format.video.nFrameWidth = mWidth; def->format.video.nFrameHeight = mHeight; - def->format.video.xFramerate = port->format.video.xFramerate; + def->format.video.xFramerate = mFramerate; def->format.video.eColorFormat = mColorFormat; def = &editPortInfo(kOutputPortIndex)->mDef; def->format.video.nFrameWidth = mWidth; @@ -770,6 +928,74 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams( return OMX_ErrorNone; } +vpx_enc_frame_flags_t SoftVPXEncoder::getEncodeFlags() { + vpx_enc_frame_flags_t flags = 0; + int patternIdx = mTemporalPatternIdx % mTemporalPatternLength; + mTemporalPatternIdx++; + switch (mTemporalPattern[patternIdx]) { + case kTemporalUpdateLast: + flags |= VP8_EFLAG_NO_UPD_GF; + flags |= VP8_EFLAG_NO_UPD_ARF; + flags |= VP8_EFLAG_NO_REF_GF; + flags |= VP8_EFLAG_NO_REF_ARF; + break; + case kTemporalUpdateGoldenWithoutDependency: + flags |= VP8_EFLAG_NO_REF_GF; + // Deliberately no break here. + case kTemporalUpdateGolden: + flags |= VP8_EFLAG_NO_REF_ARF; + flags |= VP8_EFLAG_NO_UPD_ARF; + flags |= VP8_EFLAG_NO_UPD_LAST; + break; + case kTemporalUpdateAltrefWithoutDependency: + flags |= VP8_EFLAG_NO_REF_ARF; + flags |= VP8_EFLAG_NO_REF_GF; + // Deliberately no break here. + case kTemporalUpdateAltref: + flags |= VP8_EFLAG_NO_UPD_GF; + flags |= VP8_EFLAG_NO_UPD_LAST; + break; + case kTemporalUpdateNoneNoRefAltref: + flags |= VP8_EFLAG_NO_REF_ARF; + // Deliberately no break here. + case kTemporalUpdateNone: + flags |= VP8_EFLAG_NO_UPD_GF; + flags |= VP8_EFLAG_NO_UPD_ARF; + flags |= VP8_EFLAG_NO_UPD_LAST; + flags |= VP8_EFLAG_NO_UPD_ENTROPY; + break; + case kTemporalUpdateNoneNoRefGoldenRefAltRef: + flags |= VP8_EFLAG_NO_REF_GF; + flags |= VP8_EFLAG_NO_UPD_GF; + flags |= VP8_EFLAG_NO_UPD_ARF; + flags |= VP8_EFLAG_NO_UPD_LAST; + flags |= VP8_EFLAG_NO_UPD_ENTROPY; + break; + case kTemporalUpdateGoldenWithoutDependencyRefAltRef: + flags |= VP8_EFLAG_NO_REF_GF; + flags |= VP8_EFLAG_NO_UPD_ARF; + flags |= VP8_EFLAG_NO_UPD_LAST; + break; + case kTemporalUpdateLastRefAltRef: + flags |= VP8_EFLAG_NO_UPD_GF; + flags |= VP8_EFLAG_NO_UPD_ARF; + flags |= VP8_EFLAG_NO_REF_GF; + break; + case kTemporalUpdateGoldenRefAltRef: + flags |= VP8_EFLAG_NO_UPD_ARF; + flags |= VP8_EFLAG_NO_UPD_LAST; + break; + case kTemporalUpdateLastAndGoldenRefAltRef: + flags |= VP8_EFLAG_NO_UPD_ARF; + flags |= VP8_EFLAG_NO_REF_GF; + break; + case kTemporalUpdateLastRefAll: + flags |= VP8_EFLAG_NO_UPD_ARF; + flags |= VP8_EFLAG_NO_UPD_GF; + break; + } + return flags; +} void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { // Initialize encoder if not already @@ -854,6 +1080,9 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { kInputBufferAlignment, source); vpx_enc_frame_flags_t flags = 0; + if (mTemporalPatternLength > 0) { + flags = getEncodeFlags(); + } if (mKeyFrameRequested) { flags |= VPX_EFLAG_FORCE_KF; mKeyFrameRequested = false; @@ -874,7 +1103,13 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { mBitrateUpdated = false; } - uint32_t frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate); + uint32_t frameDuration; + if (inputBufferHeader->nTimeStamp > mLastTimestamp) { + frameDuration = (uint32_t)(inputBufferHeader->nTimeStamp - mLastTimestamp); + } else { + frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate); + } + mLastTimestamp = inputBufferHeader->nTimeStamp; codec_return = vpx_codec_encode( mCodecContext, &raw_frame, @@ -921,10 +1156,9 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { OMX_ERRORTYPE SoftVPXEncoder::getExtensionIndex( const char *name, OMX_INDEXTYPE *index) { if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) { - *index = OMX_IndexVendorStartUnused; + *(int32_t*)index = kStoreMetaDataExtensionIndex; return OMX_ErrorNone; } - return SimpleSoftOMXComponent::getExtensionIndex(name, index); } diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h index 1c983ab..c5a83d1 100644 --- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h +++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h @@ -91,6 +91,47 @@ protected: const char *name, OMX_INDEXTYPE *index); private: + enum { + kStoreMetaDataExtensionIndex = OMX_IndexVendorStartUnused + 1, + }; + + enum TemporalReferences { + // For 1 layer case: reference all (last, golden, and alt ref), but only + // update last. + kTemporalUpdateLastRefAll = 12, + // First base layer frame for 3 temporal layers, which updates last and + // golden with alt ref dependency. + kTemporalUpdateLastAndGoldenRefAltRef = 11, + // First enhancement layer with alt ref dependency. + kTemporalUpdateGoldenRefAltRef = 10, + // First enhancement layer with alt ref dependency. + kTemporalUpdateGoldenWithoutDependencyRefAltRef = 9, + // Base layer with alt ref dependency. + kTemporalUpdateLastRefAltRef = 8, + // Highest enhacement layer without dependency on golden with alt ref + // dependency. + kTemporalUpdateNoneNoRefGoldenRefAltRef = 7, + // Second layer and last frame in cycle, for 2 layers. + kTemporalUpdateNoneNoRefAltref = 6, + // Highest enhancement layer. + kTemporalUpdateNone = 5, + // Second enhancement layer. + kTemporalUpdateAltref = 4, + // Second enhancement layer without dependency on previous frames in + // the second enhancement layer. + kTemporalUpdateAltrefWithoutDependency = 3, + // First enhancement layer. + kTemporalUpdateGolden = 2, + // First enhancement layer without dependency on previous frames in + // the first enhancement layer. + kTemporalUpdateGoldenWithoutDependency = 1, + // Base layer. + kTemporalUpdateLast = 0, + }; + enum { + kMaxTemporalPattern = 8 + }; + // number of buffers allocated per port static const uint32_t kNumBuffers = 4; @@ -159,6 +200,36 @@ private: // something else. OMX_VIDEO_VP8LEVELTYPE mLevel; + // Key frame interval in frames + uint32_t mKeyFrameInterval; + + // Minimum (best quality) quantizer + uint32_t mMinQuantizer; + + // Maximum (worst quality) quantizer + uint32_t mMaxQuantizer; + + // Number of coding temporal layers to be used. + size_t mTemporalLayers; + + // Temporal layer bitrare ratio in percentage + uint32_t mTemporalLayerBitrateRatio[OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS]; + + // Temporal pattern type + OMX_VIDEO_ANDROID_VPXTEMPORALLAYERPATTERNTYPE mTemporalPatternType; + + // Temporal pattern length + size_t mTemporalPatternLength; + + // Temporal pattern current index + size_t mTemporalPatternIdx; + + // Frame type temporal pattern + TemporalReferences mTemporalPattern[kMaxTemporalPattern]; + + // Last input buffer timestamp + OMX_TICKS mLastTimestamp; + // Conversion buffer is needed to convert semi // planar yuv420 to planar format // It is only allocated if input format is @@ -184,6 +255,9 @@ private: // dtor. status_t releaseEncoder(); + // Get current encode flags + vpx_enc_frame_flags_t getEncodeFlags(); + // Handles port changes with respect to color formats OMX_ERRORTYPE internalSetFormatParams( const OMX_VIDEO_PARAM_PORTFORMATTYPE* format); @@ -205,6 +279,10 @@ private: OMX_ERRORTYPE internalSetVp8Params( const OMX_VIDEO_PARAM_VP8TYPE* vp8Params); + // Handles Android vp8 specific parameters. + OMX_ERRORTYPE internalSetAndroidVp8Params( + const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE* vp8AndroidParams); + // Updates encoder profile OMX_ERRORTYPE internalSetProfileLevel( const OMX_VIDEO_PARAM_PROFILELEVELTYPE* profileAndLevel); -- cgit v1.1 From 170056540e9ce65261b45efd15f67e72e2df1bed Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 10 Apr 2014 17:30:21 -0700 Subject: Expose sample duration in MPEG4Extractor. Bug: 12782113 Change-Id: I75ee361243c5382d9288349c554deb7bed952782 --- media/libstagefright/MPEG4Extractor.cpp | 12 ++++++++++-- media/libstagefright/SampleIterator.cpp | 9 ++++++--- media/libstagefright/SampleTable.cpp | 7 ++++++- media/libstagefright/include/SampleIterator.h | 4 +++- media/libstagefright/include/SampleTable.h | 3 ++- 5 files changed, 27 insertions(+), 8 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 2a3fa04..e07b6aa 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -3540,7 +3540,7 @@ status_t MPEG4Source::read( off64_t offset; size_t size; - uint32_t cts; + uint32_t cts, stts; bool isSyncSample; bool newBuffer = false; if (mBuffer == NULL) { @@ -3548,7 +3548,7 @@ status_t MPEG4Source::read( status_t err = mSampleTable->getMetaDataForSample( - mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample); + mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample, &stts); if (err != OK) { return err; @@ -3579,6 +3579,8 @@ status_t MPEG4Source::read( mBuffer->meta_data()->clear(); mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)cts * 1000000) / mTimescale); + mBuffer->meta_data()->setInt64( + kKeyDuration, ((int64_t)stts * 1000000) / mTimescale); if (targetSampleTimeUs >= 0) { mBuffer->meta_data()->setInt64( @@ -3701,6 +3703,8 @@ status_t MPEG4Source::read( mBuffer->meta_data()->clear(); mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)cts * 1000000) / mTimescale); + mBuffer->meta_data()->setInt64( + kKeyDuration, ((int64_t)stts * 1000000) / mTimescale); if (targetSampleTimeUs >= 0) { mBuffer->meta_data()->setInt64( @@ -3850,6 +3854,8 @@ status_t MPEG4Source::fragmentedRead( mBuffer->set_range(0, size); mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)cts * 1000000) / mTimescale); + mBuffer->meta_data()->setInt64( + kKeyDuration, ((int64_t)smpl->duration * 1000000) / mTimescale); if (targetSampleTimeUs >= 0) { mBuffer->meta_data()->setInt64( @@ -3973,6 +3979,8 @@ status_t MPEG4Source::fragmentedRead( mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)cts * 1000000) / mTimescale); + mBuffer->meta_data()->setInt64( + kKeyDuration, ((int64_t)smpl->duration * 1000000) / mTimescale); if (targetSampleTimeUs >= 0) { mBuffer->meta_data()->setInt64( diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp index eae721b..2748349 100644 --- a/media/libstagefright/SampleIterator.cpp +++ b/media/libstagefright/SampleIterator.cpp @@ -133,7 +133,8 @@ status_t SampleIterator::seekTo(uint32_t sampleIndex) { } status_t err; - if ((err = findSampleTime(sampleIndex, &mCurrentSampleTime)) != OK) { + if ((err = findSampleTimeAndDuration( + sampleIndex, &mCurrentSampleTime, &mCurrentSampleDuration)) != OK) { ALOGE("findSampleTime return error"); return err; } @@ -285,8 +286,8 @@ status_t SampleIterator::getSampleSizeDirect( return OK; } -status_t SampleIterator::findSampleTime( - uint32_t sampleIndex, uint32_t *time) { +status_t SampleIterator::findSampleTimeAndDuration( + uint32_t sampleIndex, uint32_t *time, uint32_t *duration) { if (sampleIndex >= mTable->mNumSampleSizes) { return ERROR_OUT_OF_RANGE; } @@ -309,6 +310,8 @@ status_t SampleIterator::findSampleTime( *time += mTable->getCompositionTimeOffset(sampleIndex); + *duration = mTTSDuration; + return OK; } diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index d9858d7..9a92805 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -778,7 +778,8 @@ status_t SampleTable::getMetaDataForSample( off64_t *offset, size_t *size, uint32_t *compositionTime, - bool *isSyncSample) { + bool *isSyncSample, + uint32_t *sampleDuration) { Mutex::Autolock autoLock(mLock); status_t err; @@ -820,6 +821,10 @@ status_t SampleTable::getMetaDataForSample( } } + if (sampleDuration) { + *sampleDuration = mSampleIterator->getSampleDuration(); + } + return OK; } diff --git a/media/libstagefright/include/SampleIterator.h b/media/libstagefright/include/SampleIterator.h index b5a043c..60c9e7e 100644 --- a/media/libstagefright/include/SampleIterator.h +++ b/media/libstagefright/include/SampleIterator.h @@ -30,6 +30,7 @@ struct SampleIterator { off64_t getSampleOffset() const { return mCurrentSampleOffset; } size_t getSampleSize() const { return mCurrentSampleSize; } uint32_t getSampleTime() const { return mCurrentSampleTime; } + uint32_t getSampleDuration() const { return mCurrentSampleDuration; } status_t getSampleSizeDirect( uint32_t sampleIndex, size_t *size); @@ -61,11 +62,12 @@ private: off64_t mCurrentSampleOffset; size_t mCurrentSampleSize; uint32_t mCurrentSampleTime; + uint32_t mCurrentSampleDuration; void reset(); status_t findChunkRange(uint32_t sampleIndex); status_t getChunkOffset(uint32_t chunk, off64_t *offset); - status_t findSampleTime(uint32_t sampleIndex, uint32_t *time); + status_t findSampleTimeAndDuration(uint32_t sampleIndex, uint32_t *time, uint32_t *duration); SampleIterator(const SampleIterator &); SampleIterator &operator=(const SampleIterator &); diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h index 847dff7..fe146f2 100644 --- a/media/libstagefright/include/SampleTable.h +++ b/media/libstagefright/include/SampleTable.h @@ -66,7 +66,8 @@ public: off64_t *offset, size_t *size, uint32_t *compositionTime, - bool *isSyncSample = NULL); + bool *isSyncSample = NULL, + uint32_t *sampleDuration = NULL); enum { kFlagBefore, -- cgit v1.1 From 15387a6e8e7930ea80f46c98fab54f22981e7f11 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 17 Apr 2014 11:16:05 -0700 Subject: AwesomePlayer: fixed division by zero in onBufferingUpdate Bug: 13911283 Change-Id: I968a274634a86f5c46f75dc533024dad44afc36b --- media/libstagefright/AwesomePlayer.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index e924076..6e5003f 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -718,11 +718,9 @@ void AwesomePlayer::onBufferingUpdate() { finishAsyncPrepare_l(); } } else { - int64_t bitrate; - if (getBitrate(&bitrate)) { - size_t cachedSize = mCachedSource->cachedSize(); - int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate; - + bool eos2; + int64_t cachedDurationUs; + if (getCachedDuration_l(&cachedDurationUs, &eos2) && mDurationUs > 0) { int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; if (percentage > 100) { percentage = 100; @@ -730,7 +728,7 @@ void AwesomePlayer::onBufferingUpdate() { notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); } else { - // We don't know the bitrate of the stream, use absolute size + // We don't know the bitrate/duration of the stream, use absolute size // limits to maintain the cache. if ((mFlags & PLAYING) && !eos -- cgit v1.1 From 1da7ee098ac97d2fdd2cff16a2bfa51fd1889ad8 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 23 Apr 2014 17:03:10 -0700 Subject: PlaylistFetcher: start queueing AUs after the 1st IDR nalu Bug: 14159556 Change-Id: I4fc16dda9357e1251d2909571a79215d13d0104b --- media/libstagefright/httplive/PlaylistFetcher.cpp | 19 +++++++++++++++++++ media/libstagefright/httplive/PlaylistFetcher.h | 2 ++ 2 files changed, 21 insertions(+) (limited to 'media') diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 5011bc1..07a3ed0 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -69,6 +69,7 @@ PlaylistFetcher::PlaylistFetcher( mNumRetries(0), mStartup(true), mPrepared(false), + mSkipToFirstIDRAfterConnect(false), mNextPTSTimeUs(-1ll), mMonitorQueueGeneration(0), mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY), @@ -1096,12 +1097,30 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu continue; } + if (stream == LiveSession::STREAMTYPE_VIDEO && mVideoMime.empty()) { + const char *mime; + if (source->getFormat()->findCString(kKeyMIMEType, &mime)) { + mVideoMime.setTo(mime); + if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { + mSkipToFirstIDRAfterConnect = true; + } + } + } + int64_t timeUs; sp accessUnit; status_t finalResult; while (source->hasBufferAvailable(&finalResult) && source->dequeueAccessUnit(&accessUnit) == OK) { + if (stream == LiveSession::STREAMTYPE_VIDEO && mSkipToFirstIDRAfterConnect) { + if (!IsIDR(accessUnit)) { + continue; + } else { + mSkipToFirstIDRAfterConnect = false; + } + } + CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); if (mMinStartTimeUs > 0) { if (timeUs < mMinStartTimeUs) { diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index 7e21523..e0ed11d 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -98,6 +98,7 @@ private: sp mSession; AString mURI; + AString mVideoMime; uint32_t mStreamTypeMask; int64_t mStartTimeUs; @@ -115,6 +116,7 @@ private: int32_t mNumRetries; bool mStartup; bool mPrepared; + bool mSkipToFirstIDRAfterConnect; int64_t mNextPTSTimeUs; int32_t mMonitorQueueGeneration; -- cgit v1.1 From 5cda1b30b8c3900f8405f9bf2fab2df6e38ea95f Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 23 Apr 2014 17:07:21 -0700 Subject: PlaylistFetcher: clear mTSParser on bad starting seq # hint Bug: 14159556 Change-Id: If25187477066282d5980da3c4d8a76dcfcf54d27 --- media/libstagefright/httplive/PlaylistFetcher.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'media') diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 5011bc1..c34f3cb 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -916,6 +916,7 @@ void PlaylistFetcher::onDownloadNext() { if (err == -EAGAIN) { // bad starting sequence number hint + mTSParser.clear(); postMonitorQueue(); return; } -- cgit v1.1 From 32fa3c6fab55b075c916f4dad38e42e239bb7813 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 29 Apr 2014 09:01:52 -0700 Subject: Remove AUDIO_CHANNEL_OUT_SURROUND and corresponding downmix effect Change-Id: I1576aa373ca7acbb84d7742bacbd9c2da04a7a4c --- media/libeffects/downmix/EffectDownmix.c | 63 -------------------------------- media/libeffects/downmix/EffectDownmix.h | 1 - 2 files changed, 64 deletions(-) (limited to 'media') diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c index 1663d47..ed10dea 100644 --- a/media/libeffects/downmix/EffectDownmix.c +++ b/media/libeffects/downmix/EffectDownmix.c @@ -31,7 +31,6 @@ #define MINUS_3_DB_IN_Q19_12 2896 // -3dB = 0.707 * 2^12 = 2896 typedef enum { - CHANNEL_MASK_SURROUND = AUDIO_CHANNEL_OUT_SURROUND, CHANNEL_MASK_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD, // like AUDIO_CHANNEL_OUT_QUAD with *_SIDE_* instead of *_BACK_*, same channel order CHANNEL_MASK_QUAD_SIDE = @@ -340,9 +339,6 @@ static int Downmix_Process(effect_handle_t self, case CHANNEL_MASK_QUAD_SIDE: Downmix_foldFromQuad(pSrc, pDst, numFrames, accumulate); break; - case CHANNEL_MASK_SURROUND: - Downmix_foldFromSurround(pSrc, pDst, numFrames, accumulate); - break; case CHANNEL_MASK_5POINT1_BACK: case CHANNEL_MASK_5POINT1_SIDE: Downmix_foldFrom5Point1(pSrc, pDst, numFrames, accumulate); @@ -828,65 +824,6 @@ void Downmix_foldFromQuad(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool ac /*---------------------------------------------------------------------------- - * Downmix_foldFromSurround() - *---------------------------------------------------------------------------- - * Purpose: - * downmix a "surround sound" (mono rear) signal to stereo - * - * Inputs: - * pSrc surround signal to downmix - * numFrames the number of surround frames to downmix - * accumulate whether to mix (when true) the result of the downmix with the contents of pDst, - * or overwrite pDst (when false) - * - * Outputs: - * pDst downmixed stereo audio samples - * - *---------------------------------------------------------------------------- - */ -void Downmix_foldFromSurround(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) { - int32_t lt, rt, centerPlusRearContrib; // samples in Q19.12 format - // sample at index 0 is FL - // sample at index 1 is FR - // sample at index 2 is FC - // sample at index 3 is RC - // code is mostly duplicated between the two values of accumulate to avoid repeating the test - // for every sample - if (accumulate) { - while (numFrames) { - // centerPlusRearContrib = FC(-3dB) + RC(-3dB) - centerPlusRearContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12) + (pSrc[3] * MINUS_3_DB_IN_Q19_12); - // FL + centerPlusRearContrib - lt = (pSrc[0] << 12) + centerPlusRearContrib; - // FR + centerPlusRearContrib - rt = (pSrc[1] << 12) + centerPlusRearContrib; - // accumulate in destination - pDst[0] = clamp16(pDst[0] + (lt >> 13)); - pDst[1] = clamp16(pDst[1] + (rt >> 13)); - pSrc += 4; - pDst += 2; - numFrames--; - } - } else { // same code as above but without adding and clamping pDst[i] to itself - while (numFrames) { - // centerPlusRearContrib = FC(-3dB) + RC(-3dB) - centerPlusRearContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12) + (pSrc[3] * MINUS_3_DB_IN_Q19_12); - // FL + centerPlusRearContrib - lt = (pSrc[0] << 12) + centerPlusRearContrib; - // FR + centerPlusRearContrib - rt = (pSrc[1] << 12) + centerPlusRearContrib; - // store in destination - pDst[0] = clamp16(lt >> 13); // differs from when accumulate is true above - pDst[1] = clamp16(rt >> 13); // differs from when accumulate is true above - pSrc += 4; - pDst += 2; - numFrames--; - } - } -} - - -/*---------------------------------------------------------------------------- * Downmix_foldFrom5Point1() *---------------------------------------------------------------------------- * Purpose: diff --git a/media/libeffects/downmix/EffectDownmix.h b/media/libeffects/downmix/EffectDownmix.h index fcb3c9e..2399abd 100644 --- a/media/libeffects/downmix/EffectDownmix.h +++ b/media/libeffects/downmix/EffectDownmix.h @@ -97,7 +97,6 @@ int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t s int Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue); void Downmix_foldFromQuad(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate); -void Downmix_foldFromSurround(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate); void Downmix_foldFrom5Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate); void Downmix_foldFrom7Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate); bool Downmix_foldGeneric( -- cgit v1.1 From 029a64e0327ecc1215a3d17ce50f508edae1c4a6 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 15 Apr 2014 09:58:55 -0700 Subject: Define CHANNEL_MASK_* in terms of AUDIO_CHANNEL_OUT_* and use same suffixes Change-Id: I90b74ede171ba2550db4a220cfd1ad2e3caefe2d --- media/libeffects/downmix/EffectDownmix.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'media') diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c index ed10dea..661fde9 100644 --- a/media/libeffects/downmix/EffectDownmix.c +++ b/media/libeffects/downmix/EffectDownmix.c @@ -30,24 +30,13 @@ #define MINUS_3_DB_IN_Q19_12 2896 // -3dB = 0.707 * 2^12 = 2896 +// subset of possible audio_channel_mask_t values, and AUDIO_CHANNEL_OUT_* renamed to CHANNEL_MASK_* typedef enum { - CHANNEL_MASK_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD, - // like AUDIO_CHANNEL_OUT_QUAD with *_SIDE_* instead of *_BACK_*, same channel order - CHANNEL_MASK_QUAD_SIDE = - AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_SIDE_LEFT | - AUDIO_CHANNEL_OUT_SIDE_RIGHT, - CHANNEL_MASK_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1, - // like AUDIO_CHANNEL_OUT_5POINT1 with *_SIDE_* instead of *_BACK_*, same channel order - CHANNEL_MASK_5POINT1_SIDE = - AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_LOW_FREQUENCY | - AUDIO_CHANNEL_OUT_SIDE_LEFT | - AUDIO_CHANNEL_OUT_SIDE_RIGHT, - CHANNEL_MASK_7POINT1_SIDE_BACK = AUDIO_CHANNEL_OUT_7POINT1, + CHANNEL_MASK_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD_BACK, + CHANNEL_MASK_QUAD_SIDE = AUDIO_CHANNEL_OUT_QUAD_SIDE, + CHANNEL_MASK_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1_BACK, + CHANNEL_MASK_5POINT1_SIDE = AUDIO_CHANNEL_OUT_5POINT1_SIDE, + CHANNEL_MASK_7POINT1 = AUDIO_CHANNEL_OUT_7POINT1, } downmix_input_channel_mask_t; // effect_handle_t interface implementation for downmix effect @@ -343,7 +332,7 @@ static int Downmix_Process(effect_handle_t self, case CHANNEL_MASK_5POINT1_SIDE: Downmix_foldFrom5Point1(pSrc, pDst, numFrames, accumulate); break; - case CHANNEL_MASK_7POINT1_SIDE_BACK: + case CHANNEL_MASK_7POINT1: Downmix_foldFrom7Point1(pSrc, pDst, numFrames, accumulate); break; default: -- cgit v1.1 From 877a0ac7e8677fa1cbd0e8565ad9d38ba0db5fc0 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 30 Apr 2014 17:04:13 -0700 Subject: Use AUDIO_INTERLEAVE_* constants Change-Id: I6609fa75c9a57fc4ca3887d626a2f4fb8b6593a1 --- media/libmedia/AudioTrack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index fbfd3da..8daf08b 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1820,7 +1820,7 @@ status_t AudioTrack::dump(int fd, const Vector& args __unused) const result.append(" AudioTrack::dump\n"); snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n", mStreamType, - mVolume[0], mVolume[1]); + mVolume[AUDIO_INTERLEAVE_LEFT], mVolume[AUDIO_INTERLEAVE_RIGHT]); result.append(buffer); snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%zu)\n", mFormat, mChannelCount, mFrameCount); -- cgit v1.1 From c4b88a8d0f524666bf0f390075c334d047a104f2 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 30 Apr 2014 16:54:30 -0700 Subject: Fix bug for direct track with PCM != 16-bit The AUDIO_FORMAT_PCM_8_BIT format was being converted to AUDIO_FORMAT_PCM_16_BIT on client side even for direct tracks. That conversion was incorrect; it should only be done for mixed tracks. Also remove checks for specific PCM formats in the generic part of server side of createTrack. Those format checks should only be done by the thread. This will allow direct tracks for PCM 8-bit, PCM 24-bit, etc. Change-Id: If5b9fd79f8642ed93e2aeabcaf4809b2ed798978 --- media/libmedia/AudioTrack.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 8daf08b..dc4f90e 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1005,7 +1005,8 @@ status_t AudioTrack::createTrack_l(size_t epoch) sp track = audioFlinger->createTrack(mStreamType, mSampleRate, // AudioFlinger only sees 16-bit PCM - mFormat == AUDIO_FORMAT_PCM_8_BIT ? + mFormat == AUDIO_FORMAT_PCM_8_BIT && + !(mFlags & AUDIO_OUTPUT_FLAG_DIRECT) ? AUDIO_FORMAT_PCM_16_BIT : mFormat, mChannelMask, &temp, -- cgit v1.1 From 0c3be875376adaee8d8e8dd917c64926e1513b29 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 1 May 2014 10:14:44 -0700 Subject: WIP: MediaCodec and friends NDK APIs, plain C version Change-Id: I9ed6b9c5afb026a1b5fe8b652e75635bbcc223df --- media/ndk/Android.mk | 41 +++++++ media/ndk/NdkMediaCodec.cpp | 237 ++++++++++++++++++++++++++++++++++++++++ media/ndk/NdkMediaExtractor.cpp | 189 ++++++++++++++++++++++++++++++++ media/ndk/NdkMediaFormat.cpp | 198 +++++++++++++++++++++++++++++++++ media/ndk/NdkMediaFormatPriv.h | 44 ++++++++ 5 files changed, 709 insertions(+) create mode 100644 media/ndk/Android.mk create mode 100644 media/ndk/NdkMediaCodec.cpp create mode 100644 media/ndk/NdkMediaExtractor.cpp create mode 100644 media/ndk/NdkMediaFormat.cpp create mode 100644 media/ndk/NdkMediaFormatPriv.h (limited to 'media') diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk new file mode 100644 index 0000000..0ea0c3f --- /dev/null +++ b/media/ndk/Android.mk @@ -0,0 +1,41 @@ +# +# Copyright (C) 2010 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + NdkMediaCodec.cpp \ + NdkMediaExtractor.cpp \ + NdkMediaFormat.cpp \ + +LOCAL_MODULE:= libmediandk + +LOCAL_C_INCLUDES := \ + bionic/libc/private \ + frameworks/base/core/jni \ + frameworks/av/include/ndk + +LOCAL_SHARED_LIBRARIES := \ + libmedia \ + libstagefright \ + libstagefright_foundation \ + liblog \ + libutils \ + libandroid_runtime \ + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp new file mode 100644 index 0000000..5412b9b --- /dev/null +++ b/media/ndk/NdkMediaCodec.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "NdkMediaCodec" + +#include "NdkMediaCodec.h" +#include "NdkMediaFormatPriv.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +using namespace android; + + +static int translate_error(status_t err) { + if (err == OK) { + return OK; + } else if (err == -EAGAIN) { + return AMEDIACODEC_INFO_TRY_AGAIN_LATER; + } + ALOGE("sf error code: %d", err); + return -1000; +} + + +class CodecHandler: public AHandler { +public: + CodecHandler(sp); + virtual void onMessageReceived(const sp &msg); +}; + +CodecHandler::CodecHandler(sp) { + +} + +void CodecHandler::onMessageReceived(const sp &msg) { + ALOGI("handler got message %d", msg->what()); +} + +struct AMediaCodec { + sp mCodec; + sp mLooper; + sp mHandler; +}; + +extern "C" { + +static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool encoder) { + AMediaCodec *mData = new AMediaCodec(); + mData->mLooper = new ALooper; + mData->mLooper->setName("NDK MediaCodec_looper"); + status_t ret = mData->mLooper->start( + false, // runOnCallingThread + true, // canCallJava XXX + PRIORITY_FOREGROUND); + ALOGV("looper start: %d", ret); + if (name_is_type) { + mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder); + } else { + mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name); + } + mData->mHandler = new CodecHandler(mData->mCodec); + mData->mLooper->registerHandler(mData->mHandler); + return mData; +} + + +AMediaCodec* AMediaCodec_createByCodecName(const char *name) { + return createAMediaCodec(name, false, false); +} + +AMediaCodec* AMediaCodec_createByCodecType(const char *mime_type) { + return createAMediaCodec(mime_type, true, false); +} + +AMediaCodec* AMediaCodec_createEncoderByName(const char *name) { + return createAMediaCodec(name, false, true); +} + +int AMediaCodec_delete(AMediaCodec *mData) { + if (mData->mCodec != NULL) { + mData->mCodec->release(); + mData->mCodec.clear(); + } + + if (mData->mLooper != NULL) { + mData->mLooper->unregisterHandler(mData->mHandler->id()); + mData->mLooper->stop(); + mData->mLooper.clear(); + } + delete mData; + return OK; +} + +int AMediaCodec_configure(AMediaCodec *mData, AMediaFormat *format, ANativeWindow* window) { + sp nativeFormat; + AMediaFormat_getFormat(format, &nativeFormat); + ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str()); + sp surface = NULL; + if (window != NULL) { + surface = (Surface*) window; + } + + return translate_error(mData->mCodec->configure(nativeFormat, surface, NULL, 0)); +} + +int AMediaCodec_start(AMediaCodec *mData) { + return translate_error(mData->mCodec->start()); +} + +int AMediaCodec_stop(AMediaCodec *mData) { + return translate_error(mData->mCodec->stop()); +} + +int AMediaCodec_flush(AMediaCodec *mData) { + return translate_error(mData->mCodec->flush()); +} + +ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { + size_t idx; + status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs); + if (ret == OK) { + return idx; + } + return translate_error(ret); +} + +uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { + android::Vector > abufs; + if (mData->mCodec->getInputBuffers(&abufs) == 0) { + size_t n = abufs.size(); + if (idx >= n) { + ALOGE("buffer index %d out of range", idx); + return NULL; + } + if (out_size != NULL) { + *out_size = abufs[idx]->capacity(); + } + return abufs[idx]->data(); + } + ALOGE("couldn't get input buffers"); + return NULL; +} + +uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { + android::Vector > abufs; + if (mData->mCodec->getOutputBuffers(&abufs) == 0) { + size_t n = abufs.size(); + if (idx >= n) { + ALOGE("buffer index %d out of range", idx); + return NULL; + } + if (out_size != NULL) { + *out_size = abufs[idx]->capacity(); + } + return abufs[idx]->data(); + } + ALOGE("couldn't get output buffers"); + return NULL; +} + +int AMediaCodec_queueInputBuffer(AMediaCodec *mData, + size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { + + AString errorMsg; + status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg); + return translate_error(ret); +} + +ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData, + AMediaCodecBufferInfo *info, int64_t timeoutUs) { + size_t idx; + size_t offset; + size_t size; + uint32_t flags; + int64_t presentationTimeUs; + status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs, + &flags, timeoutUs); + + switch (ret) { + case OK: + info->offset = offset; + info->size = size; + info->flags = flags; + info->presentationTimeUs = presentationTimeUs; + return idx; + case -EAGAIN: + return AMEDIACODEC_INFO_TRY_AGAIN_LATER; + case android::INFO_FORMAT_CHANGED: + return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED; + case INFO_OUTPUT_BUFFERS_CHANGED: + return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED; + default: + break; + } + return translate_error(ret); +} + +AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { + sp format; + mData->mCodec->getOutputFormat(&format); + return AMediaFormat_fromMsg(&format); +} + +int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) { + if (render) { + return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx)); + } else { + return translate_error(mData->mCodec->releaseOutputBuffer(idx)); + } +} + +} // extern "C" + diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp new file mode 100644 index 0000000..681633a --- /dev/null +++ b/media/ndk/NdkMediaExtractor.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "NdkMediaExtractor" + + +#include "NdkMediaExtractor.h" +#include "NdkMediaFormatPriv.h" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace android; + +static int translate_error(status_t err) { + if (err == OK) { + return OK; + } + ALOGE("sf error code: %d", err); + return -1000; +} + +struct AMediaExtractor { + sp mImpl; + +}; + +extern "C" { + +AMediaExtractor* AMediaExtractor_new() { + ALOGV("ctor"); + AMediaExtractor *mData = new AMediaExtractor(); + mData->mImpl = new NuMediaExtractor(); + return mData; +} + +int AMediaExtractor_delete(AMediaExtractor *mData) { + ALOGV("dtor"); + delete mData; + return OK; +} + +int AMediaExtractor_setDataSourceFd(AMediaExtractor *mData, int fd, off64_t offset, off64_t length) { + ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); + mData->mImpl->setDataSource(fd, offset, length); + return 0; +} + +int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) { + ALOGV("setDataSource(%s)", location); + // TODO: add header support + + JNIEnv *env = AndroidRuntime::getJNIEnv(); + jobject service = NULL; + if (env == NULL) { + ALOGE("setDataSource(path) must be called from Java thread"); + env->ExceptionClear(); + return -1; + } + + jclass mediahttpclass = env->FindClass("android/media/MediaHTTPService"); + if (mediahttpclass == NULL) { + ALOGE("can't find MediaHttpService"); + env->ExceptionClear(); + return -1; + } + + jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass, + "createHttpServiceBinderIfNecessary", "(Ljava/lang/String;)Landroid/os/IBinder;"); + if (mediaHttpCreateMethod == NULL) { + ALOGE("can't find method"); + env->ExceptionClear(); + return -1; + } + + jstring jloc = env->NewStringUTF(location); + + service = env->CallStaticObjectMethod(mediahttpclass, mediaHttpCreateMethod, jloc); + env->DeleteLocalRef(jloc); + + sp httpService; + if (service != NULL) { + sp binder = ibinderForJavaObject(env, service); + httpService = interface_cast(binder); + } + + mData->mImpl->setDataSource(httpService, location, NULL); + env->ExceptionClear(); + return 0; +} + +int AMediaExtractor_getTrackCount(AMediaExtractor *mData) { + return mData->mImpl->countTracks(); +} + +AMediaFormat* AMediaExtractor_getTrackFormat(AMediaExtractor *mData, size_t idx) { + sp format; + mData->mImpl->getTrackFormat(idx, &format); + return AMediaFormat_fromMsg(&format); +} + +int AMediaExtractor_selectTrack(AMediaExtractor *mData, size_t idx) { + ALOGV("selectTrack(%z)", idx); + return translate_error(mData->mImpl->selectTrack(idx)); +} + +int AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx) { + ALOGV("unselectTrack(%z)", idx); + return translate_error(mData->mImpl->unselectTrack(idx)); +} + +bool AMediaExtractor_advance(AMediaExtractor *mData) { + //ALOGV("advance"); + return mData->mImpl->advance(); +} + +int AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size_t capacity) { + //ALOGV("readSampleData"); + sp tmp = new ABuffer(buffer, capacity); + if (mData->mImpl->readSampleData(tmp) == OK) { + return tmp->size(); + } + return -1; +} + +int AMediaExtractor_getSampleFlags(AMediaExtractor *mData) { + int sampleFlags = 0; + sp meta; + status_t err = mData->mImpl->getSampleMeta(&meta); + if (err != OK) { + return -1; + } + int32_t val; + if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) { + sampleFlags |= NuMediaExtractor::SAMPLE_FLAG_SYNC; + } + + uint32_t type; + const void *data; + size_t size; + if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) { + sampleFlags |= NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED; + } + return sampleFlags; +} + +int AMediaExtractor_getSampleTrackIndex(AMediaExtractor *mData) { + size_t idx; + if (mData->mImpl->getSampleTrackIndex(&idx) != OK) { + return -1; + } + return idx; +} + +int64_t AMediaExtractor_getSampletime(AMediaExtractor *mData) { + int64_t time; + if (mData->mImpl->getSampleTime(&time) != OK) { + return -1; + } + return time; +} + + +} // extern "C" + diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp new file mode 100644 index 0000000..359f37e --- /dev/null +++ b/media/ndk/NdkMediaFormat.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "NdkMediaFormat" + + +#include "NdkMediaFormat.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace android; + +struct AMediaFormat { + sp mFormat; +}; + +extern "C" { + +// private functions for conversion to/from AMessage +AMediaFormat* AMediaFormat_fromMsg(void* data) { + ALOGV("private ctor"); + AMediaFormat* mData = new AMediaFormat(); + mData->mFormat = *((sp*)data); + return mData; +} + +void AMediaFormat_getFormat(AMediaFormat* mData, void* dest) { + *((sp*)dest) = mData->mFormat; +} + + +/* + * public function follow + */ +AMediaFormat *AMediaFormat_new() { + ALOGV("ctor"); + sp msg = new AMessage(); + return AMediaFormat_fromMsg(&msg); +} + +int AMediaFormat_delete(AMediaFormat *mData) { + ALOGV("dtor"); + delete mData; + return OK; +} + + +const char* AMediaFormat_toString(AMediaFormat *mData) { + sp f = mData->mFormat; + String8 ret; + int num = f->countEntries(); + for (int i = 0; i < num; i++) { + if (i != 0) { + ret.append(", "); + } + AMessage::Type t; + const char *name = f->getEntryNameAt(i, &t); + ret.append(name); + ret.append(": "); + switch (t) { + case AMessage::kTypeInt32: + { + int32_t val; + f->findInt32(name, &val); + ret.appendFormat("int32(%d)", val); + break; + } + case AMessage::kTypeInt64: + { + int64_t val; + f->findInt64(name, &val); + ret.appendFormat("int64(%lld)", val); + break; + } + case AMessage::kTypeSize: + { + size_t val; + f->findSize(name, &val); + ret.appendFormat("size_t(%d)", val); + break; + } + case AMessage::kTypeFloat: + { + float val; + f->findFloat(name, &val); + ret.appendFormat("float(%f)", val); + break; + } + case AMessage::kTypeDouble: + { + double val; + f->findDouble(name, &val); + ret.appendFormat("double(%f)", val); + break; + } + case AMessage::kTypeString: + { + AString val; + f->findString(name, &val); + ret.appendFormat("string(%s)", val.c_str()); + break; + } + case AMessage::kTypeBuffer: + { + ret.appendFormat("data"); + break; + } + default: + { + ret.appendFormat("unknown(%d)", t); + break; + } + } + } + ret.append("}"); + return strdup(ret.string()); +} + +bool AMediaFormat_getInt32(AMediaFormat* mData, const char *name, int32_t *out) { + return mData->mFormat->findInt32(name, out); +} + +bool AMediaFormat_getInt64(AMediaFormat* mData, const char *name, int64_t *out) { + return mData->mFormat->findInt64(name, out); +} + +bool AMediaFormat_getFloat(AMediaFormat* mData, const char *name, float *out) { + return mData->mFormat->findFloat(name, out); +} + +bool AMediaFormat_getDouble(AMediaFormat* mData, const char *name, double *out) { + return mData->mFormat->findDouble(name, out); +} + +bool AMediaFormat_getSize(AMediaFormat* mData, const char *name, size_t *out) { + return mData->mFormat->findSize(name, out); +} + +bool AMediaFormat_getString(AMediaFormat* mData, const char *name, const char **out) { + AString tmp; + if (mData->mFormat->findString(name, &tmp)) { + *out = strdup(tmp.c_str()); + return true; + } + return false; +} + +const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile"; +const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate"; +const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count"; +const char* AMEDIAFORMAT_KEY_CHANNEL_MASK = "channel-mask"; +const char* AMEDIAFORMAT_KEY_COLOR_FORMAT = "color-format"; +const char* AMEDIAFORMAT_KEY_DURATION = "durationUs"; +const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level"; +const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate"; +const char* AMEDIAFORMAT_KEY_HEIGHT = "height"; +const char* AMEDIAFORMAT_KEY_IS_ADTS = "is-adts"; +const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT = "is-autoselect"; +const char* AMEDIAFORMAT_KEY_IS_DEFAULT = "is-default"; +const char* AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle"; +const char* AMEDIAFORMAT_KEY_I_FRAME_INTERVAL = "i-frame-interval"; +const char* AMEDIAFORMAT_KEY_LANGUAGE = "language"; +const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height"; +const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size"; +const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width"; +const char* AMEDIAFORMAT_KEY_MIME = "mime"; +const char* AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown"; +const char* AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after"; +const char* AMEDIAFORMAT_KEY_SAMPLE_RATE = "sample-rate"; +const char* AMEDIAFORMAT_KEY_WIDTH = "width"; +const char* AMEDIAFORMAT_KEY_STRIDE = "stride"; + + +} // extern "C" + + diff --git a/media/ndk/NdkMediaFormatPriv.h b/media/ndk/NdkMediaFormatPriv.h new file mode 100644 index 0000000..f67e782 --- /dev/null +++ b/media/ndk/NdkMediaFormatPriv.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2014 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. + */ + +/* + * This file defines an NDK API. + * Do not remove methods. + * Do not change method signatures. + * Do not change the value of constants. + * Do not change the size of any of the classes defined in here. + * Do not reference types that are not part of the NDK. + * Do not #include files that aren't part of the NDK. + */ + +#ifndef _NDK_MEDIA_FORMAT_PRIV_H +#define _NDK_MEDIA_FORMAT_PRIV_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +AMediaFormat* AMediaFormat_fromMsg(void*); +void AMediaFormat_getFormat(AMediaFormat* mData, void* dest); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _NDK_MEDIA_FORMAT_PRIV_H + -- cgit v1.1 From 83ae5be9a9928a7265e40d2906530e56eb3bc20c Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 5 May 2014 14:48:34 -0700 Subject: Don't build libmediandk for PDK Change-Id: I9b2e5f5c8cc0fad59d4a4268c8767f540d536d10 --- media/ndk/Android.mk | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk index 0ea0c3f..82fb970 100644 --- a/media/ndk/Android.mk +++ b/media/ndk/Android.mk @@ -1,5 +1,5 @@ # -# Copyright (C) 2010 The Android Open Source Project +# Copyright (C) 2014 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. @@ -16,6 +16,8 @@ LOCAL_PATH:= $(call my-dir) +ifneq ($(TARGET_BUILD_PDK), true) + include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ @@ -39,3 +41,5 @@ LOCAL_SHARED_LIBRARIES := \ libandroid_runtime \ include $(BUILD_SHARED_LIBRARY) + +endif -- cgit v1.1 From 7c9b141d551fde406f199f0dd21582f8551aea23 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 6 May 2014 10:33:07 -0700 Subject: MediaFormat owns its strings Have MediaFormat own the strings it returns from toString and getString, reducing the chance of memory leaks. Change-Id: I0ddd593874c8b3af0b7714f2d8a106edf8121108 --- media/ndk/NdkMediaFormat.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp index 359f37e..6f69f8d 100644 --- a/media/ndk/NdkMediaFormat.cpp +++ b/media/ndk/NdkMediaFormat.cpp @@ -34,6 +34,8 @@ using namespace android; struct AMediaFormat { sp mFormat; + String8 mDebug; + KeyedVector mStringCache; }; extern "C" { @@ -135,7 +137,8 @@ const char* AMediaFormat_toString(AMediaFormat *mData) { } } ret.append("}"); - return strdup(ret.string()); + mData->mDebug = ret; + return mData->mDebug.string(); } bool AMediaFormat_getInt32(AMediaFormat* mData, const char *name, int32_t *out) { @@ -159,9 +162,19 @@ bool AMediaFormat_getSize(AMediaFormat* mData, const char *name, size_t *out) { } bool AMediaFormat_getString(AMediaFormat* mData, const char *name, const char **out) { + + for (size_t i = 0; i < mData->mStringCache.size(); i++) { + if (strcmp(mData->mStringCache.keyAt(i).string(), name) == 0) { + mData->mStringCache.removeItemsAt(i, 1); + break; + } + } + AString tmp; if (mData->mFormat->findString(name, &tmp)) { - *out = strdup(tmp.c_str()); + String8 ret(tmp.c_str()); + mData->mStringCache.add(String8(name), ret); + *out = ret.string(); return true; } return false; -- cgit v1.1 From 784e24e386b088c05d653ab482f2e95cb53e3d01 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 6 May 2014 15:05:53 -0700 Subject: Remove legacy omx_message variables Remove platform_private and data_ptr from omx_message. These were used for legacy deferred buffer creation. See OMXCodec quirks: kDefersOutputBufferAllocation and kRequiresAllocateBufferOnOutputPorts. Change-Id: I94da56bc64f3b46ee1276e93d67b36c1662e2eaf Signed-off-by: Andy Hung --- media/libstagefright/ACodec.cpp | 22 +++------------------- media/libstagefright/OMXCodec.cpp | 38 +++++++++----------------------------- media/libstagefright/omx/OMX.cpp | 2 -- 3 files changed, 12 insertions(+), 50 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 5bca317..537d9de 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -100,12 +100,6 @@ struct CodecObserver : public BnOMXObserver { msg->setInt64( "timestamp", omx_msg.u.extended_buffer_data.timestamp); - msg->setPointer( - "platform_private", - omx_msg.u.extended_buffer_data.platform_private); - msg->setPointer( - "data_ptr", - omx_msg.u.extended_buffer_data.data_ptr); break; } @@ -160,9 +154,7 @@ private: IOMX::buffer_id bufferID, size_t rangeOffset, size_t rangeLength, OMX_U32 flags, - int64_t timeUs, - void *platformPrivate, - void *dataPtr); + int64_t timeUs); void getMoreInputDataIfPossible(); @@ -3228,23 +3220,17 @@ bool ACodec::BaseState::onOMXMessage(const sp &msg) { int32_t rangeOffset, rangeLength, flags; int64_t timeUs; - void *platformPrivate; - void *dataPtr; CHECK(msg->findInt32("range_offset", &rangeOffset)); CHECK(msg->findInt32("range_length", &rangeLength)); CHECK(msg->findInt32("flags", &flags)); CHECK(msg->findInt64("timestamp", &timeUs)); - CHECK(msg->findPointer("platform_private", &platformPrivate)); - CHECK(msg->findPointer("data_ptr", &dataPtr)); return onOMXFillBufferDone( bufferID, (size_t)rangeOffset, (size_t)rangeLength, (OMX_U32)flags, - timeUs, - platformPrivate, - dataPtr); + timeUs); } default: @@ -3543,9 +3529,7 @@ bool ACodec::BaseState::onOMXFillBufferDone( IOMX::buffer_id bufferID, size_t rangeOffset, size_t rangeLength, OMX_U32 flags, - int64_t timeUs, - void * /* platformPrivate */, - void * /* dataPtr */) { + int64_t timeUs) { ALOGV("[%s] onOMXFillBufferDone %p time %lld us, flags = 0x%08lx", mCodec->mComponentName.c_str(), bufferID, timeUs, flags); diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index a879656..9a7f3db 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1627,15 +1627,15 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { info.mMediaBuffer = NULL; if (portIndex == kPortIndexOutput) { - if (!(mOMXLivesLocally - && (mQuirks & kRequiresAllocateBufferOnOutputPorts) - && (mQuirks & kDefersOutputBufferAllocation))) { - // If the node does not fill in the buffer ptr at this time, - // we will defer creating the MediaBuffer until receiving - // the first FILL_BUFFER_DONE notification instead. - info.mMediaBuffer = new MediaBuffer(info.mData, info.mSize); - info.mMediaBuffer->setObserver(this); - } + // Fail deferred MediaBuffer creation until FILL_BUFFER_DONE; + // this legacy mode is no longer supported. + LOG_ALWAYS_FATAL_IF((mOMXLivesLocally + && (mQuirks & kRequiresAllocateBufferOnOutputPorts) + && (mQuirks & kDefersOutputBufferAllocation)), + "allocateBuffersOnPort cannot defer buffer allocation"); + + info.mMediaBuffer = new MediaBuffer(info.mData, info.mSize); + info.mMediaBuffer->setObserver(this); } mPortBuffers[portIndex].push(info); @@ -2234,22 +2234,6 @@ void OMXCodec::on_message(const omx_message &msg) { } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) { CHECK_EQ((int)mPortStatus[kPortIndexOutput], (int)ENABLED); - if (info->mMediaBuffer == NULL) { - CHECK(mOMXLivesLocally); - CHECK(mQuirks & kRequiresAllocateBufferOnOutputPorts); - CHECK(mQuirks & kDefersOutputBufferAllocation); - - // The qcom video decoders on Nexus don't actually allocate - // output buffer memory on a call to OMX_AllocateBuffer - // the "pBuffer" member of the OMX_BUFFERHEADERTYPE - // structure is only filled in later. - - info->mMediaBuffer = new MediaBuffer( - msg.u.extended_buffer_data.data_ptr, - info->mSize); - info->mMediaBuffer->setObserver(this); - } - MediaBuffer *buffer = info->mMediaBuffer; bool isGraphicBuffer = buffer->graphicBuffer() != NULL; @@ -2285,10 +2269,6 @@ void OMXCodec::on_message(const omx_message &msg) { } buffer->meta_data()->setPointer( - kKeyPlatformPrivate, - msg.u.extended_buffer_data.platform_private); - - buffer->meta_data()->setPointer( kKeyBufferID, msg.u.extended_buffer_data.buffer); diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index 74076c6..b62d5f5 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -470,8 +470,6 @@ OMX_ERRORTYPE OMX::OnFillBufferDone( msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; msg.u.extended_buffer_data.flags = pBuffer->nFlags; msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; - msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate; - msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer; findDispatcher(node)->post(msg); -- cgit v1.1 From 08aaabe87960c04ecac180db1fe88b5a7bc2ed3b Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 6 May 2014 16:08:19 -0700 Subject: Add NDK version of MediaMuxer and add some constness here and there. Change-Id: Ib3caa8310691e8f27aaa1afcfaec0b384513d4f1 --- media/ndk/Android.mk | 1 + media/ndk/NdkMediaCodec.cpp | 2 +- media/ndk/NdkMediaFormat.cpp | 4 +- media/ndk/NdkMediaFormatPriv.h | 2 +- media/ndk/NdkMediaMuxer.cpp | 99 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 media/ndk/NdkMediaMuxer.cpp (limited to 'media') diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk index 82fb970..b8dd19e 100644 --- a/media/ndk/Android.mk +++ b/media/ndk/Android.mk @@ -24,6 +24,7 @@ LOCAL_SRC_FILES:= \ NdkMediaCodec.cpp \ NdkMediaExtractor.cpp \ NdkMediaFormat.cpp \ + NdkMediaMuxer.cpp \ LOCAL_MODULE:= libmediandk diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index 5412b9b..e7f009e 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -115,7 +115,7 @@ int AMediaCodec_delete(AMediaCodec *mData) { return OK; } -int AMediaCodec_configure(AMediaCodec *mData, AMediaFormat *format, ANativeWindow* window) { +int AMediaCodec_configure(AMediaCodec *mData, const AMediaFormat* format, ANativeWindow* window) { sp nativeFormat; AMediaFormat_getFormat(format, &nativeFormat); ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str()); diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp index 6f69f8d..32acf59 100644 --- a/media/ndk/NdkMediaFormat.cpp +++ b/media/ndk/NdkMediaFormat.cpp @@ -41,14 +41,14 @@ struct AMediaFormat { extern "C" { // private functions for conversion to/from AMessage -AMediaFormat* AMediaFormat_fromMsg(void* data) { +AMediaFormat* AMediaFormat_fromMsg(const void* data) { ALOGV("private ctor"); AMediaFormat* mData = new AMediaFormat(); mData->mFormat = *((sp*)data); return mData; } -void AMediaFormat_getFormat(AMediaFormat* mData, void* dest) { +void AMediaFormat_getFormat(const AMediaFormat* mData, void* dest) { *((sp*)dest) = mData->mFormat; } diff --git a/media/ndk/NdkMediaFormatPriv.h b/media/ndk/NdkMediaFormatPriv.h index f67e782..02342d9 100644 --- a/media/ndk/NdkMediaFormatPriv.h +++ b/media/ndk/NdkMediaFormatPriv.h @@ -34,7 +34,7 @@ extern "C" { #endif AMediaFormat* AMediaFormat_fromMsg(void*); -void AMediaFormat_getFormat(AMediaFormat* mData, void* dest); +void AMediaFormat_getFormat(const AMediaFormat* mData, void* dest); #ifdef __cplusplus } // extern "C" diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp new file mode 100644 index 0000000..98129cb --- /dev/null +++ b/media/ndk/NdkMediaMuxer.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "NdkMediaMuxer" + + +#include "NdkMediaMuxer.h" +#include "NdkMediaCodec.h" +#include "NdkMediaFormatPriv.h" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace android; + +static int translate_error(status_t err) { + if (err == OK) { + return OK; + } + ALOGE("sf error code: %d", err); + return -1000; +} + +struct AMediaMuxer { + sp mImpl; + +}; + +extern "C" { + +AMediaMuxer* AMediaMuxer_new(int fd, OutputFormat format) { + ALOGV("ctor"); + AMediaMuxer *mData = new AMediaMuxer(); + mData->mImpl = new MediaMuxer(fd, (android::MediaMuxer::OutputFormat)format); + return mData; +} + +int AMediaMuxer_delete(AMediaMuxer *muxer) { + ALOGV("dtor"); + delete muxer; + return OK; +} + +int AMediaMuxer_setLocation(AMediaMuxer *muxer, float latitude, float longtitude) { + return translate_error(muxer->mImpl->setLocation(latitude * 10000, longtitude * 10000)); +} + +int AMediaMuxer_setOrientationHint(AMediaMuxer *muxer, int degrees) { + return translate_error(muxer->mImpl->setOrientationHint(degrees)); +} + +ssize_t AMediaMuxer_addTrack(AMediaMuxer *muxer, const AMediaFormat *format) { + sp msg; + AMediaFormat_getFormat(format, &msg); + return translate_error(muxer->mImpl->addTrack(msg)); +} + +int AMediaMuxer_start(AMediaMuxer *muxer) { + return translate_error(muxer->mImpl->start()); +} + +int AMediaMuxer_stop(AMediaMuxer *muxer) { + return translate_error(muxer->mImpl->stop()); +} + +int AMediaMuxer_writeSampleData(AMediaMuxer *muxer, + size_t trackIdx, const uint8_t *data, const AMediaCodecBufferInfo &info) { + sp buf = new ABuffer((void*)(data + info.offset), info.size); + return translate_error( + muxer->mImpl->writeSampleData(buf, trackIdx, info.presentationTimeUs, info.flags)); +} + + +} // extern "C" + -- cgit v1.1 From 828f883a43f66f77d776a75d0ea2b87c7c826071 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 7 May 2014 11:17:52 -0700 Subject: Fix a couple of fast capture typo bugs AudioRecord constructor was not passing flags through to set(). Server-side check was using wrong kind of channel mask. Change-Id: Ifaa880ec323771e9fd168262be05f3e539f53390 --- media/libmedia/AudioRecord.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index a7bf380..2c8605c 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -79,14 +79,14 @@ AudioRecord::AudioRecord( uint32_t notificationFrames, int sessionId, transfer_type transferType, - audio_input_flags_t flags __unused) + audio_input_flags_t flags) : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mProxy(NULL) { mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user, - notificationFrames, false /*threadCanCallJava*/, sessionId, transferType); + notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags); } AudioRecord::~AudioRecord() -- cgit v1.1 From 34d497283c66b5ef0f8855c007eaa20d7ac8b96d Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 7 May 2014 12:55:18 -0700 Subject: Expand AMediaFormat Remove getDouble and getSize methods, since these are not used and/or not present in the corresponding Java MediaFormat API. Add setBuffer/getBuffer, needed for making formats for encoding, and add other setters. Change-Id: I528d51b4ed571d852b949637f7ae3a95d31da7c1 --- media/ndk/NdkMediaFormat.cpp | 54 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp index 32acf59..c08814f 100644 --- a/media/ndk/NdkMediaFormat.cpp +++ b/media/ndk/NdkMediaFormat.cpp @@ -141,24 +141,30 @@ const char* AMediaFormat_toString(AMediaFormat *mData) { return mData->mDebug.string(); } -bool AMediaFormat_getInt32(AMediaFormat* mData, const char *name, int32_t *out) { - return mData->mFormat->findInt32(name, out); +bool AMediaFormat_getInt32(AMediaFormat* format, const char *name, int32_t *out) { + return format->mFormat->findInt32(name, out); } -bool AMediaFormat_getInt64(AMediaFormat* mData, const char *name, int64_t *out) { - return mData->mFormat->findInt64(name, out); +bool AMediaFormat_getInt64(AMediaFormat* format, const char *name, int64_t *out) { + return format->mFormat->findInt64(name, out); } -bool AMediaFormat_getFloat(AMediaFormat* mData, const char *name, float *out) { - return mData->mFormat->findFloat(name, out); +bool AMediaFormat_getFloat(AMediaFormat* format, const char *name, float *out) { + return format->mFormat->findFloat(name, out); } -bool AMediaFormat_getDouble(AMediaFormat* mData, const char *name, double *out) { - return mData->mFormat->findDouble(name, out); +bool AMediaFormat_getSize(AMediaFormat* format, const char *name, size_t *out) { + return format->mFormat->findSize(name, out); } -bool AMediaFormat_getSize(AMediaFormat* mData, const char *name, size_t *out) { - return mData->mFormat->findSize(name, out); +bool AMediaFormat_getBuffer(AMediaFormat* format, const char *name, void** data, size_t *outsize) { + sp buf; + if (format->mFormat->findBuffer(name, &buf)) { + *data = buf->data() + buf->offset(); + *outsize = buf->size(); + return true; + } + return false; } bool AMediaFormat_getString(AMediaFormat* mData, const char *name, const char **out) { @@ -180,6 +186,34 @@ bool AMediaFormat_getString(AMediaFormat* mData, const char *name, const char ** return false; } +void AMediaFormat_setInt32(AMediaFormat* format, const char *name, int32_t value) { + format->mFormat->setInt32(name, value); +} + +void AMediaFormat_setInt64(AMediaFormat* format, const char *name, int64_t value) { + format->mFormat->setInt64(name, value); +} + +void AMediaFormat_setFloat(AMediaFormat* format, const char* name, float value) { + format->mFormat->setFloat(name, value); +} + +void AMediaFormat_setString(AMediaFormat* format, const char* name, const char* value) { + // AMessage::setString() makes a copy of the string + format->mFormat->setString(name, value, strlen(value)); +} + +void AMediaFormat_setBuffer(AMediaFormat* format, const char* name, void* data, size_t size) { + // the ABuffer(void*, size_t) constructor doesn't take ownership of the data, so create + // a new buffer and copy the data into it + sp buf = new ABuffer(size); + memcpy(buf->data(), data, size); + buf->setRange(0, size); + // AMessage::setBuffer() increases the refcount of the buffer + format->mFormat->setBuffer(name, buf); +} + + const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile"; const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate"; const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count"; -- cgit v1.1 From b773038277ba328696832b690b91ce6e95bd1a6c Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 30 Apr 2014 15:50:31 -0700 Subject: Add client side support for more AUDIO_FORMAT_PCM_* As much as possible, the checks for specific formats are done on server side. The only exception is 8-bit, which needs a client side workaround. Change-Id: I52fe086c039460c8dac009de03b67eb54c56a836 --- media/libmedia/AudioTrack.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index dc4f90e..aaaa3f1 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -315,12 +315,20 @@ status_t AudioTrack::set( flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER); } - if (audio_is_linear_pcm(format)) { - mFrameSize = channelCount * audio_bytes_per_sample(format); - mFrameSizeAF = channelCount * sizeof(int16_t); + if (flags & AUDIO_OUTPUT_FLAG_DIRECT) { + if (audio_is_linear_pcm(format)) { + mFrameSize = channelCount * audio_bytes_per_sample(format); + } else { + mFrameSize = sizeof(uint8_t); + } + mFrameSizeAF = mFrameSize; } else { - mFrameSize = sizeof(uint8_t); - mFrameSizeAF = sizeof(uint8_t); + ALOG_ASSERT(audio_is_linear_pcm(format)); + mFrameSize = channelCount * audio_bytes_per_sample(format); + mFrameSizeAF = channelCount * audio_bytes_per_sample( + format == AUDIO_FORMAT_PCM_8_BIT ? AUDIO_FORMAT_PCM_16_BIT : format); + // createTrack will return an error if PCM format is not supported by server, + // so no need to check for specific PCM formats here } // Make copy of input parameter offloadInfo so that in the future: @@ -931,7 +939,11 @@ status_t AudioTrack::createTrack_l(size_t epoch) // Ensure that buffer alignment matches channel count // 8-bit data in shared memory is not currently supported by AudioFlinger - size_t alignment = /* mFormat == AUDIO_FORMAT_PCM_8_BIT ? 1 : */ 2; + size_t alignment = audio_bytes_per_sample( + mFormat == AUDIO_FORMAT_PCM_8_BIT ? AUDIO_FORMAT_PCM_16_BIT : mFormat); + if (alignment & 1) { + alignment = 1; + } if (mChannelCount > 1) { // More than 2 channels does not require stronger alignment than stereo alignment <<= 1; @@ -947,7 +959,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) // there's no frameCount parameter. // But when initializing a shared buffer AudioTrack via set(), // there _is_ a frameCount parameter. We silently ignore it. - frameCount = mSharedBuffer->size()/mChannelCount/sizeof(int16_t); + frameCount = mSharedBuffer->size() / mFrameSizeAF; } else if (!(mFlags & AUDIO_OUTPUT_FLAG_FAST)) { -- cgit v1.1 From 908ea6603c64e29e40277a74c9fb0e776c097830 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 7 May 2014 15:30:51 -0700 Subject: stagefright: set PTS for SoftwareRenderer Change-Id: I08661a9eae09f919149aa5a58aa514d848de50a1 --- media/libstagefright/AwesomePlayer.cpp | 9 ++++++--- media/libstagefright/colorconversion/SoftwareRenderer.cpp | 7 ++++++- media/libstagefright/include/SoftwareRenderer.h | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 8d3032b..d679be1 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -106,12 +106,15 @@ struct AwesomeLocalRenderer : public AwesomeRenderer { } virtual void render(MediaBuffer *buffer) { + int64_t timeUs; + CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); + render((const uint8_t *)buffer->data() + buffer->range_offset(), - buffer->range_length()); + buffer->range_length(), timeUs * 1000); } - void render(const void *data, size_t size) { - mTarget->render(data, size, NULL); + void render(const void *data, size_t size, int64_t timestampNs) { + mTarget->render(data, size, timestampNs, NULL); } protected: diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp index 77f21b7..67dfcd2 100644 --- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp +++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp @@ -138,7 +138,7 @@ static int ALIGN(int x, int y) { } void SoftwareRenderer::render( - const void *data, size_t size, void *platformPrivate) { + const void *data, size_t size, int64_t timestampNs, void *platformPrivate) { ANativeWindowBuffer *buf; int err; if ((err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), @@ -230,6 +230,11 @@ void SoftwareRenderer::render( CHECK_EQ(0, mapper.unlock(buf->handle)); + if ((err = native_window_set_buffers_timestamp(mNativeWindow.get(), + timestampNs)) != 0) { + ALOGW("Surface::set_buffers_timestamp returned error %d", err); + } + if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf, -1)) != 0) { ALOGW("Surface::queueBuffer returned error %d", err); diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h index 7ab0042..0ba670c 100644 --- a/media/libstagefright/include/SoftwareRenderer.h +++ b/media/libstagefright/include/SoftwareRenderer.h @@ -34,7 +34,7 @@ public: ~SoftwareRenderer(); void render( - const void *data, size_t size, void *platformPrivate); + const void *data, size_t size, int64_t timestampNs, void *platformPrivate); private: enum YUVMode { -- cgit v1.1 From 86aa02ce274826dc80ffa00766b16172c47503fd Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 7 May 2014 16:03:54 -0700 Subject: Make AMediaCodec_create* APIs more like their Java counterparts and add configure flags. Change-Id: Ibfb7f8cad724fa1db2320966828104d40b5e6590 --- media/ndk/NdkMediaCodec.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index e7f009e..9592af8 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -88,16 +88,16 @@ static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool } -AMediaCodec* AMediaCodec_createByCodecName(const char *name) { +AMediaCodec* AMediaCodec_createCodecByName(const char *name) { return createAMediaCodec(name, false, false); } -AMediaCodec* AMediaCodec_createByCodecType(const char *mime_type) { +AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) { return createAMediaCodec(mime_type, true, false); } -AMediaCodec* AMediaCodec_createEncoderByName(const char *name) { - return createAMediaCodec(name, false, true); +AMediaCodec* AMediaCodec_createEncoderByType(const char *name) { + return createAMediaCodec(name, true, true); } int AMediaCodec_delete(AMediaCodec *mData) { @@ -115,7 +115,8 @@ int AMediaCodec_delete(AMediaCodec *mData) { return OK; } -int AMediaCodec_configure(AMediaCodec *mData, const AMediaFormat* format, ANativeWindow* window) { +int AMediaCodec_configure( + AMediaCodec *mData, const AMediaFormat* format, ANativeWindow* window, uint32_t flags) { sp nativeFormat; AMediaFormat_getFormat(format, &nativeFormat); ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str()); @@ -124,7 +125,7 @@ int AMediaCodec_configure(AMediaCodec *mData, const AMediaFormat* format, ANativ surface = (Surface*) window; } - return translate_error(mData->mCodec->configure(nativeFormat, surface, NULL, 0)); + return translate_error(mData->mCodec->configure(nativeFormat, surface, NULL, flags)); } int AMediaCodec_start(AMediaCodec *mData) { -- cgit v1.1 From 7d8e3ccfbf326b5e190b416590e956c2fc3021f7 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 8 May 2014 16:13:54 -0700 Subject: Allow BOM and space in WebVTT files Bug: 10900755 Change-Id: I47a7a33f749ea2470ce7d9d36d33c7484637d61c --- media/libstagefright/httplive/PlaylistFetcher.cpp | 28 ++++++++++++++++++++++- media/libstagefright/httplive/PlaylistFetcher.h | 1 + 2 files changed, 28 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index c34f3cb..6160009 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -1183,9 +1183,35 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu return OK; } +/* static */ +bool PlaylistFetcher::bufferStartsWithWebVTTMagicSequence( + const sp &buffer) { + size_t pos = 0; + + // skip possible BOM + if (buffer->size() >= pos + 3 && + !memcmp("\xef\xbb\xbf", buffer->data() + pos, 3)) { + pos += 3; + } + + // accept WEBVTT followed by SPACE, TAB or (CR) LF + if (buffer->size() < pos + 6 || + memcmp("WEBVTT", buffer->data() + pos, 6)) { + return false; + } + pos += 6; + + if (buffer->size() == pos) { + return true; + } + + uint8_t sep = buffer->data()[pos]; + return sep == ' ' || sep == '\t' || sep == '\n' || sep == '\r'; +} + status_t PlaylistFetcher::extractAndQueueAccessUnits( const sp &buffer, const sp &itemMeta) { - if (buffer->size() >= 7 && !memcmp("WEBVTT\n", buffer->data(), 7)) { + if (bufferStartsWithWebVTTMagicSequence(buffer)) { if (mStreamTypeMask != LiveSession::STREAMTYPE_SUBTITLES) { ALOGE("This stream only contains subtitles."); return ERROR_MALFORMED; diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index 7e21523..6af82c4 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -91,6 +91,7 @@ private: static const int32_t kNumSkipFrames; static bool bufferStartsWithTsSyncByte(const sp& buffer); + static bool bufferStartsWithWebVTTMagicSequence(const sp& buffer); // notifications to mSession sp mNotify; -- cgit v1.1 From fc7fca77caa12993dd938d5ff43797d781291027 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 7 May 2014 15:31:28 -0700 Subject: MediaCodec: add renderAndReleaseOutputBuffer() method with timestamp Bug: 11784827 Change-Id: Ia1dcbd6c1d1a4380db04b750c0eb3fa0bd58d7b4 --- media/libstagefright/ACodec.cpp | 21 +++++++++++++++++++++ media/libstagefright/MediaCodec.cpp | 29 ++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 537d9de..0a3a3b6 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -3670,7 +3670,28 @@ void ACodec::BaseState::onOutputBufferDrained(const sp &msg) { ATRACE_NAME("render"); // The client wants this buffer to be rendered. + int64_t timestampNs = 0; + if (!msg->findInt64("timestampNs", ×tampNs)) { + // TODO: it seems like we should use the timestamp + // in the (media)buffer as it potentially came from + // an input surface, but we did not propagate it prior to + // API 20. Perhaps check for target SDK version. +#if 0 + if (info->mData->meta()->findInt64("timeUs", ×tampNs)) { + ALOGI("using buffer PTS of %" PRId64, timestampNs); + timestampNs *= 1000; + } +#endif + } + status_t err; + err = native_window_set_buffers_timestamp(mCodec->mNativeWindow.get(), timestampNs); + if (err != OK) { + ALOGW("failed to set buffer timestamp: %d", err); + } else { + ALOGI("set PTS to %" PRId64, timestampNs); + } + if ((err = mCodec->mNativeWindow->queueBuffer( mCodec->mNativeWindow.get(), info->mGraphicBuffer.get(), -1)) == OK) { diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 601dccf..5b525f2 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaCodec" #include +#include #include @@ -323,6 +324,16 @@ status_t MediaCodec::renderOutputBufferAndRelease(size_t index) { return PostAndAwaitResponse(msg, &response); } +status_t MediaCodec::renderOutputBufferAndRelease(size_t index, int64_t timestampNs) { + sp msg = new AMessage(kWhatReleaseOutputBuffer, id()); + msg->setSize("index", index); + msg->setInt32("render", true); + msg->setInt64("timestampNs", timestampNs); + + sp response; + return PostAndAwaitResponse(msg, &response); +} + status_t MediaCodec::releaseOutputBuffer(size_t index) { sp msg = new AMessage(kWhatReleaseOutputBuffer, id()); msg->setSize("index", index); @@ -1707,9 +1718,25 @@ status_t MediaCodec::onReleaseOutputBuffer(const sp &msg) { if (render && info->mData != NULL && info->mData->size() != 0) { info->mNotify->setInt32("render", true); + int64_t timestampNs = 0; + if (msg->findInt64("timestampNs", ×tampNs)) { + info->mNotify->setInt64("timestampNs", timestampNs); + } else { + // TODO: it seems like we should use the timestamp + // in the (media)buffer as it potentially came from + // an input surface, but we did not propagate it prior to + // API 20. Perhaps check for target SDK version. +#if 0 + if (info->mData->meta()->findInt64("timeUs", ×tampNs)) { + ALOGI("using buffer PTS of %" PRId64, timestampNs); + timestampNs *= 1000; + } +#endif + } + if (mSoftRenderer != NULL) { mSoftRenderer->render( - info->mData->data(), info->mData->size(), NULL); + info->mData->data(), info->mData->size(), timestampNs, NULL); } } -- cgit v1.1 From cdb42cdc5ccb785edabe1ee6407134fbae5662a9 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 8 May 2014 14:46:05 -0700 Subject: Add AMediaCodec callback Change-Id: I33b7ff3bcdcff6d3a5e1db385b900ae18b7e0f03 --- media/ndk/NdkMediaCodec.cpp | 119 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 106 insertions(+), 13 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index 9592af8..1789f75 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -45,26 +45,94 @@ static int translate_error(status_t err) { return -1000; } +enum { + kWhatActivityNotify, + kWhatRequestActivityNotifications, + kWhatStopActivityNotifications, +}; + class CodecHandler: public AHandler { +private: + AMediaCodec* mCodec; public: - CodecHandler(sp); + CodecHandler(AMediaCodec *codec); virtual void onMessageReceived(const sp &msg); }; -CodecHandler::CodecHandler(sp) { +struct AMediaCodec { + sp mCodec; + sp mLooper; + sp mHandler; + sp mActivityNotification; + int32_t mGeneration; + bool mRequestedActivityNotification; + OnCodecEvent mCallback; + void *mCallbackUserData; +}; +CodecHandler::CodecHandler(AMediaCodec *codec) { + mCodec = codec; } void CodecHandler::onMessageReceived(const sp &msg) { - ALOGI("handler got message %d", msg->what()); + + switch (msg->what()) { + case kWhatRequestActivityNotifications: + { + if (mCodec->mRequestedActivityNotification) { + break; + } + + mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification); + mCodec->mRequestedActivityNotification = true; + break; + } + + case kWhatActivityNotify: + { + { + int32_t generation; + msg->findInt32("generation", &generation); + + if (generation != mCodec->mGeneration) { + // stale + break; + } + + mCodec->mRequestedActivityNotification = false; + } + + if (mCodec->mCallback) { + mCodec->mCallback(mCodec, mCodec->mCallbackUserData); + } + break; + } + + case kWhatStopActivityNotifications: + { + uint32_t replyID; + msg->senderAwaitsResponse(&replyID); + + mCodec->mGeneration++; + mCodec->mRequestedActivityNotification = false; + + sp response = new AMessage; + response->postReply(replyID); + break; + } + + default: + ALOGE("shouldn't be here"); + break; + } + } -struct AMediaCodec { - sp mCodec; - sp mLooper; - sp mHandler; -}; + +static void requestActivityNotification(AMediaCodec *codec) { + (new AMessage(kWhatRequestActivityNotifications, codec->mHandler->id()))->post(); +} extern "C" { @@ -76,14 +144,17 @@ static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool false, // runOnCallingThread true, // canCallJava XXX PRIORITY_FOREGROUND); - ALOGV("looper start: %d", ret); if (name_is_type) { mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder); } else { mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name); } - mData->mHandler = new CodecHandler(mData->mCodec); + mData->mHandler = new CodecHandler(mData); mData->mLooper->registerHandler(mData->mHandler); + mData->mGeneration = 1; + mData->mRequestedActivityNotification = false; + mData->mCallback = NULL; + return mData; } @@ -129,11 +200,25 @@ int AMediaCodec_configure( } int AMediaCodec_start(AMediaCodec *mData) { - return translate_error(mData->mCodec->start()); + status_t ret = mData->mCodec->start(); + if (ret != OK) { + return translate_error(ret); + } + mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler->id()); + mData->mActivityNotification->setInt32("generation", mData->mGeneration); + requestActivityNotification(mData); + return OK; } int AMediaCodec_stop(AMediaCodec *mData) { - return translate_error(mData->mCodec->stop()); + int ret = translate_error(mData->mCodec->stop()); + + sp msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler->id()); + sp response; + msg->postAndAwaitResponse(&response); + mData->mActivityNotification.clear(); + + return ret; } int AMediaCodec_flush(AMediaCodec *mData) { @@ -143,6 +228,7 @@ int AMediaCodec_flush(AMediaCodec *mData) { ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { size_t idx; status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs); + requestActivityNotification(mData); if (ret == OK) { return idx; } @@ -200,7 +286,7 @@ ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData, int64_t presentationTimeUs; status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs, &flags, timeoutUs); - + requestActivityNotification(mData); switch (ret) { case OK: info->offset = offset; @@ -234,5 +320,12 @@ int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) } } +int AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) { + mData->mCallback = callback; + mData->mCallbackUserData = userdata; + return OK; +} + + } // extern "C" -- cgit v1.1 From d776ac63ce9c013c9626226e43f7db606e035838 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 7 May 2014 09:16:09 -0700 Subject: IAudioFlinger::openRecord returns IMemory(s) openRecord() now explicitly returns the control block and data buffer as separate IMemory references. If the IMemory for data buffer is 0, this means it immediately follows the control block. Change-Id: Ic098f88f0e037f8fbe30006689e18cacacf09d06 --- media/libmedia/AudioRecord.cpp | 32 ++++++++++++++++++++++++-------- media/libmedia/IAudioFlinger.cpp | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 12 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 2c8605c..97ab8f8 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -484,6 +484,8 @@ status_t AudioRecord::openRecord_l(size_t epoch) size_t temp = frameCount; // temp may be replaced by a revised value of frameCount, // but we will still need the original value also int originalSessionId = mSessionId; + sp iMem; // for cblk + sp bufferMem; sp record = audioFlinger->openRecord(input, mSampleRate, mFormat, mChannelMask, @@ -491,6 +493,8 @@ status_t AudioRecord::openRecord_l(size_t epoch) &trackFlags, tid, &mSessionId, + iMem, + bufferMem, &status); ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId, "session ID changed from %d to %d", originalSessionId, mSessionId); @@ -504,7 +508,6 @@ status_t AudioRecord::openRecord_l(size_t epoch) // AudioFlinger now owns the reference to the I/O handle, // so we are no longer responsible for releasing it. - sp iMem = record->getCblk(); if (iMem == 0) { ALOGE("Could not get control block"); return NO_INIT; @@ -514,6 +517,22 @@ status_t AudioRecord::openRecord_l(size_t epoch) ALOGE("Could not get control block pointer"); return NO_INIT; } + audio_track_cblk_t* cblk = static_cast(iMemPointer); + + // Starting address of buffers in shared memory. + // The buffers are either immediately after the control block, + // or in a separate area at discretion of server. + void *buffers; + if (bufferMem == 0) { + buffers = cblk + 1; + } else { + buffers = bufferMem->pointer(); + if (buffers == NULL) { + ALOGE("Could not get buffer pointer"); + return NO_INIT; + } + } + // invariant that mAudioRecord != 0 is true only after set() returns successfully if (mAudioRecord != 0) { mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this); @@ -522,7 +541,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) mAudioRecord = record; mCblkMemory = iMem; - audio_track_cblk_t* cblk = static_cast(iMemPointer); + mBufferMemory = bufferMem; mCblk = cblk; // note that temp is the (possibly revised) value of frameCount if (temp < frameCount || (frameCount == 0 && temp == 0)) { @@ -552,11 +571,6 @@ status_t AudioRecord::openRecord_l(size_t epoch) mInput = input; mRefreshRemaining = true; - // Starting address of buffers in shared memory, immediately after the control block. This - // address is for the mapping within client address space. AudioFlinger::TrackBase::mBuffer - // is for the server address space. - void *buffers = (char*)cblk + sizeof(audio_track_cblk_t); - mFrameCount = frameCount; // If IAudioRecord is re-created, don't let the requested frameCount // decrease. This can confuse clients that cache frameCount(). @@ -631,6 +645,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, const struct timespec *r // keep them from going away if another thread re-creates the track during obtainBuffer() sp proxy; sp iMem; + sp bufferMem; { // start of lock scope AutoMutex lock(mLock); @@ -654,6 +669,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, const struct timespec *r // Keep the extra references proxy = mProxy; iMem = mCblkMemory; + bufferMem = mBufferMemory; // Non-blocking if track is stopped if (!mActive) { @@ -986,7 +1002,7 @@ status_t AudioRecord::restoreRecord_l(const char *from) status_t result; // if the new IAudioRecord is created, openRecord_l() will modify the - // following member variables: mAudioRecord, mCblkMemory and mCblk. + // following member variables: mAudioRecord, mCblkMemory, mCblk, mBufferMemory. // It will also delete the strong references on previous IAudioRecord and IMemory size_t position = mProxy->getPosition(); mNewPosition = position + mUpdatePeriod; diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 1940fe7..0e2463e 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -169,6 +169,8 @@ public: track_flags_t *flags, pid_t tid, int *sessionId, + sp& cblk, + sp& buffers, status_t *status) { Parcel data, reply; @@ -188,6 +190,8 @@ public: lSessionId = *sessionId; } data.writeInt32(lSessionId); + cblk.clear(); + buffers.clear(); status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply); if (lStatus != NO_ERROR) { ALOGE("openRecord error: %s", strerror(-lStatus)); @@ -206,17 +210,34 @@ public: } lStatus = reply.readInt32(); record = interface_cast(reply.readStrongBinder()); + cblk = interface_cast(reply.readStrongBinder()); + if (cblk != 0 && cblk->pointer() == NULL) { + cblk.clear(); + } + buffers = interface_cast(reply.readStrongBinder()); + if (buffers != 0 && buffers->pointer() == NULL) { + buffers.clear(); + } if (lStatus == NO_ERROR) { if (record == 0) { ALOGE("openRecord should have returned an IAudioRecord"); lStatus = UNKNOWN_ERROR; + } else if (cblk == 0) { + ALOGE("openRecord should have returned a cblk"); + lStatus = NO_MEMORY; } + // buffers is permitted to be 0 } else { - if (record != 0) { - ALOGE("openRecord returned an IAudioRecord but with status %d", lStatus); - record.clear(); + if (record != 0 || cblk != 0 || buffers != 0) { + ALOGE("openRecord returned an IAudioRecord, cblk, " + "or buffers but with status %d", lStatus); } } + if (lStatus != NO_ERROR) { + record.clear(); + cblk.clear(); + buffers.clear(); + } } if (status != NULL) { *status = lStatus; @@ -838,15 +859,20 @@ status_t BnAudioFlinger::onTransact( track_flags_t flags = (track_flags_t) data.readInt32(); pid_t tid = (pid_t) data.readInt32(); int sessionId = data.readInt32(); + sp cblk; + sp buffers; status_t status; sp record = openRecord(input, - sampleRate, format, channelMask, &frameCount, &flags, tid, &sessionId, &status); + sampleRate, format, channelMask, &frameCount, &flags, tid, &sessionId, + cblk, buffers, &status); LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR)); reply->writeInt64(frameCount); reply->writeInt32(flags); reply->writeInt32(sessionId); reply->writeInt32(status); reply->writeStrongBinder(record->asBinder()); + reply->writeStrongBinder(cblk->asBinder()); + reply->writeStrongBinder(buffers->asBinder()); return NO_ERROR; } break; case SAMPLE_RATE: { -- cgit v1.1 From fe9570c7b937b49d3603ccb394aed732b79bc6be Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 7 May 2014 08:42:25 -0700 Subject: Remove obsolete IAudioRecord::getCblk() Change-Id: Id20b5efd765b9796b0e391610e06dc928a829ebf --- media/libmedia/IAudioRecord.cpp | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) (limited to 'media') diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp index 9866d70..8a4a383 100644 --- a/media/libmedia/IAudioRecord.cpp +++ b/media/libmedia/IAudioRecord.cpp @@ -29,7 +29,7 @@ namespace android { enum { - GET_CBLK = IBinder::FIRST_CALL_TRANSACTION, + UNUSED_WAS_GET_CBLK = IBinder::FIRST_CALL_TRANSACTION, START, STOP }; @@ -42,21 +42,6 @@ public: { } - virtual sp getCblk() const - { - Parcel data, reply; - sp cblk; - data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor()); - status_t status = remote()->transact(GET_CBLK, data, &reply); - if (status == NO_ERROR) { - cblk = interface_cast(reply.readStrongBinder()); - if (cblk != 0 && cblk->pointer() == NULL) { - cblk.clear(); - } - } - return cblk; - } - virtual status_t start(int /*AudioSystem::sync_event_t*/ event, int triggerSession) { Parcel data, reply; @@ -89,11 +74,6 @@ status_t BnAudioRecord::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch (code) { - case GET_CBLK: { - CHECK_INTERFACE(IAudioRecord, data, reply); - reply->writeStrongBinder(getCblk()->asBinder()); - return NO_ERROR; - } break; case START: { CHECK_INTERFACE(IAudioRecord, data, reply); int /*AudioSystem::sync_event_t*/ event = data.readInt32(); -- cgit v1.1 From 844f88ccfcca95687e774bccb5e9065da61d33f8 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 9 May 2014 13:38:09 -0700 Subject: Cache mCblk in local variable cblk This is the style used throughout the rest of AudioTrackShared. Change-Id: I959a6be3064e087bb19eba41173fd130dfcb4a9a --- media/libmedia/AudioTrackShared.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index 58c9fc1..323b675 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -621,7 +621,7 @@ void ServerProxy::releaseBuffer(Buffer* buffer) android_atomic_release_store(stepCount + rear, &cblk->u.mStreaming.mRear); } - mCblk->mServer += stepCount; + cblk->mServer += stepCount; size_t half = mFrameCount / 2; if (half == 0) { @@ -679,10 +679,11 @@ size_t AudioTrackServerProxy::framesReady() } bool AudioTrackServerProxy::setStreamEndDone() { + audio_track_cblk_t* cblk = mCblk; bool old = - (android_atomic_or(CBLK_STREAM_END_DONE, &mCblk->mFlags) & CBLK_STREAM_END_DONE) != 0; + (android_atomic_or(CBLK_STREAM_END_DONE, &cblk->mFlags) & CBLK_STREAM_END_DONE) != 0; if (!old) { - (void) __futex_syscall3(&mCblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, + (void) __futex_syscall3(&cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1); } return old; @@ -690,10 +691,11 @@ bool AudioTrackServerProxy::setStreamEndDone() { void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount) { - mCblk->u.mStreaming.mUnderrunFrames += frameCount; + audio_track_cblk_t* cblk = mCblk; + cblk->u.mStreaming.mUnderrunFrames += frameCount; // FIXME also wake futex so that underrun is noticed more quickly - (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags); + (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags); } // --------------------------------------------------------------------------- -- cgit v1.1 From c26d923712a59e669d18191d93fbe3696789d592 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 9 May 2014 13:37:29 -0700 Subject: Allow placement of Pipe buffer to be specified Change-Id: I2f6b68089ecfe85cd975d29ad0d0afd13c487002 --- media/libnbaio/Pipe.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libnbaio/Pipe.cpp b/media/libnbaio/Pipe.cpp index 28a034c..6e0ec8c 100644 --- a/media/libnbaio/Pipe.cpp +++ b/media/libnbaio/Pipe.cpp @@ -25,19 +25,22 @@ namespace android { -Pipe::Pipe(size_t maxFrames, const NBAIO_Format& format) : +Pipe::Pipe(size_t maxFrames, const NBAIO_Format& format, void *buffer) : NBAIO_Sink(format), mMaxFrames(roundup(maxFrames)), - mBuffer(malloc(mMaxFrames * Format_frameSize(format))), + mBuffer(buffer == NULL ? malloc(mMaxFrames * Format_frameSize(format)) : buffer), mRear(0), - mReaders(0) + mReaders(0), + mFreeBufferInDestructor(buffer == NULL) { } Pipe::~Pipe() { ALOG_ASSERT(android_atomic_acquire_load(&mReaders) == 0); - free(mBuffer); + if (mFreeBufferInDestructor) { + free(mBuffer); + } } ssize_t Pipe::write(const void *buffer, size_t count) -- cgit v1.1 From 5e4c4f12337ff4d7ceb105bcd441bb7aea6ab070 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 9 May 2014 14:50:48 -0700 Subject: Fix bit rot in AudioStreamInSource It obviously had not been compiled in a while. Change-Id: If514f474808e557a67a671c3b833572ad4a88338 --- media/libnbaio/AudioStreamInSource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp index 80bf61a..af8f365 100644 --- a/media/libnbaio/AudioStreamInSource.cpp +++ b/media/libnbaio/AudioStreamInSource.cpp @@ -63,7 +63,7 @@ size_t AudioStreamInSource::framesOverrun() return mFramesOverrun; } -ssize_t AudioStreamInSource::read(void *buffer, size_t count) +ssize_t AudioStreamInSource::read(void *buffer, size_t count, int64_t readPTS __unused) { if (CC_UNLIKELY(!Format_isValid(mFormat))) { return NEGOTIATE; -- cgit v1.1 From 050eb3280d7305b84f723d515be2dc9606dc39d1 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 9 May 2014 15:10:23 -0700 Subject: Some crypto stuff, error codes Add crypto/drm related functions, define some media errors instead of using magic numbers in the code. Change-Id: I5924cba0bfcdb3623073c9182a646b70f4ead5a5 --- media/ndk/Android.mk | 2 + media/ndk/NdkMediaCodec.cpp | 137 +++++++++++++++++++++++++++++++++++-- media/ndk/NdkMediaCrypto.cpp | 117 +++++++++++++++++++++++++++++++ media/ndk/NdkMediaCryptoPriv.h | 41 +++++++++++ media/ndk/NdkMediaExtractor.cpp | 148 ++++++++++++++++++++++++++++++++++++++-- 5 files changed, 436 insertions(+), 9 deletions(-) create mode 100644 media/ndk/NdkMediaCrypto.cpp create mode 100644 media/ndk/NdkMediaCryptoPriv.h (limited to 'media') diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk index b8dd19e..03f26a0 100644 --- a/media/ndk/Android.mk +++ b/media/ndk/Android.mk @@ -22,6 +22,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ NdkMediaCodec.cpp \ + NdkMediaCrypto.cpp \ NdkMediaExtractor.cpp \ NdkMediaFormat.cpp \ NdkMediaMuxer.cpp \ @@ -34,6 +35,7 @@ LOCAL_C_INCLUDES := \ frameworks/av/include/ndk LOCAL_SHARED_LIBRARIES := \ + libbinder \ libmedia \ libstagefright \ libstagefright_foundation \ diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index 1789f75..1f62fa2 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -18,13 +18,14 @@ #define LOG_TAG "NdkMediaCodec" #include "NdkMediaCodec.h" +#include "NdkMediaError.h" +#include "NdkMediaCryptoPriv.h" #include "NdkMediaFormatPriv.h" #include #include #include -#include #include #include #include @@ -42,7 +43,7 @@ static int translate_error(status_t err) { return AMEDIACODEC_INFO_TRY_AGAIN_LATER; } ALOGE("sf error code: %d", err); - return -1000; + return AMEDIAERROR_GENERIC; } enum { @@ -187,7 +188,11 @@ int AMediaCodec_delete(AMediaCodec *mData) { } int AMediaCodec_configure( - AMediaCodec *mData, const AMediaFormat* format, ANativeWindow* window, uint32_t flags) { + AMediaCodec *mData, + const AMediaFormat* format, + ANativeWindow* window, + AMediaCrypto *crypto, + uint32_t flags) { sp nativeFormat; AMediaFormat_getFormat(format, &nativeFormat); ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str()); @@ -196,7 +201,8 @@ int AMediaCodec_configure( surface = (Surface*) window; } - return translate_error(mData->mCodec->configure(nativeFormat, surface, NULL, flags)); + return translate_error(mData->mCodec->configure(nativeFormat, surface, + crypto ? crypto->mCrypto : NULL, flags)); } int AMediaCodec_start(AMediaCodec *mData) { @@ -326,6 +332,129 @@ int AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callbac return OK; } +typedef struct AMediaCodecCryptoInfo { + int numsubsamples; + uint8_t key[16]; + uint8_t iv[16]; + uint32_t mode; + size_t *clearbytes; + size_t *encryptedbytes; +} AMediaCodecCryptoInfo; + +int AMediaCodec_queueSecureInputBuffer( + AMediaCodec* codec, + size_t idx, + off_t offset, + AMediaCodecCryptoInfo* crypto, + uint64_t time, + uint32_t flags) { + + CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples]; + for (int i = 0; i < crypto->numsubsamples; i++) { + subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i]; + subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i]; + } + + AString errormsg; + status_t err = codec->mCodec->queueSecureInputBuffer(idx, + offset, + subSamples, + crypto->numsubsamples, + crypto->key, + crypto->iv, + (CryptoPlugin::Mode) crypto->mode, + time, + flags, + &errormsg); + if (err != 0) { + ALOGE("queSecureInputBuffer: %s", errormsg.c_str()); + } + delete subSamples; + return translate_error(err); +} + + + +AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( + int numsubsamples, + uint8_t key[16], + uint8_t iv[16], + uint32_t mode, + size_t *clearbytes, + size_t *encryptedbytes) { + + // size needed to store all the crypto data + size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2; + AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize); + if (!ret) { + ALOGE("couldn't allocate %d bytes", cryptosize); + return NULL; + } + ret->numsubsamples = numsubsamples; + memcpy(ret->key, key, 16); + memcpy(ret->iv, iv, 16); + ret->mode = mode; + + // clearbytes and encryptedbytes point at the actual data, which follows + ret->clearbytes = (size_t*) ((&ret->encryptedbytes) + sizeof(ret->encryptedbytes)); + ret->encryptedbytes = (size_t*) (ret->clearbytes + (sizeof(size_t) * numsubsamples)); + + size_t *dst = ret->clearbytes; + memcpy(dst, clearbytes, numsubsamples * sizeof(size_t)); + dst += numsubsamples * sizeof(size_t); + memcpy(dst, encryptedbytes, numsubsamples * sizeof(size_t)); + + return ret; +} + + +int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) { + free(info); + return OK; +} + +size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) { + return ci->numsubsamples; +} + +int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) { + if (!dst || !ci) { + return AMEDIAERROR_UNSUPPORTED; + } + memcpy(dst, ci->key, 16); + return OK; +} + +int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) { + if (!dst || !ci) { + return AMEDIAERROR_UNSUPPORTED; + } + memcpy(dst, ci->iv, 16); + return OK; +} + +uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) { + if (!ci) { + return AMEDIAERROR_UNSUPPORTED; + } + return ci->mode; +} + +int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { + if (!dst || !ci) { + return AMEDIAERROR_UNSUPPORTED; + } + memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples); + return OK; +} + +int AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { + if (!dst || !ci) { + return AMEDIAERROR_UNSUPPORTED; + } + memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples); + return OK; +} } // extern "C" diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp new file mode 100644 index 0000000..25dfe6a --- /dev/null +++ b/media/ndk/NdkMediaCrypto.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "NdkMediaCrypto" + + +#include "NdkMediaCrypto.h" +#include "NdkMediaCodec.h" +#include "NdkMediaFormatPriv.h" + + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace android; + +static int translate_error(status_t err) { + if (err == OK) { + return OK; + } + ALOGE("sf error code: %d", err); + return -1000; +} + + +static sp makeCrypto() { + sp sm = defaultServiceManager(); + + sp binder = + sm->getService(String16("media.player")); + + sp service = + interface_cast(binder); + + if (service == NULL) { + return NULL; + } + + sp crypto = service->makeCrypto(); + + if (crypto == NULL || (crypto->initCheck() != OK && crypto->initCheck() != NO_INIT)) { + return NULL; + } + + return crypto; +} + +struct AMediaCrypto { + sp mCrypto; +}; + + +extern "C" { + + +bool AMediaCrypto_isCryptoSchemeSupport(const AMediaUUID uuid) { + sp crypto = makeCrypto(); + if (crypto == NULL) { + return false; + } + return crypto->isCryptoSchemeSupported(uuid); +} + +bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime) { + sp crypto = makeCrypto(); + if (crypto == NULL) { + return false; + } + return crypto->requiresSecureDecoderComponent(mime); +} + +AMediaCrypto* AMediaCrypto_new(const AMediaUUID uuid, const void *data, size_t datasize) { + + sp tmp = makeCrypto(); + if (tmp == NULL) { + return NULL; + } + + if (tmp->createPlugin(uuid, data, datasize) != 0) { + return NULL; + } + + AMediaCrypto *crypto = new AMediaCrypto(); + crypto->mCrypto = tmp; + + return crypto; +} + +void AMediaCrypto_delete(AMediaCrypto* crypto) { + delete crypto; +} + + + +} // extern "C" + diff --git a/media/ndk/NdkMediaCryptoPriv.h b/media/ndk/NdkMediaCryptoPriv.h new file mode 100644 index 0000000..14ea928 --- /dev/null +++ b/media/ndk/NdkMediaCryptoPriv.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2014 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. + */ + + +/* + * This file defines an NDK API. + * Do not remove methods. + * Do not change method signatures. + * Do not change the value of constants. + * Do not change the size of any of the classes defined in here. + * Do not reference types that are not part of the NDK. + * Do not #include files that aren't part of the NDK. + */ + +#ifndef _NDK_MEDIA_CRYPTO_PRIV_H +#define _NDK_MEDIA_CRYPTO_PRIV_H + +#include +#include +#include + +using namespace android; + +struct AMediaCrypto { + sp mCrypto; +}; + +#endif // _NDK_MEDIA_CRYPTO_PRIV_H diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp index 681633a..0a66988 100644 --- a/media/ndk/NdkMediaExtractor.cpp +++ b/media/ndk/NdkMediaExtractor.cpp @@ -18,12 +18,14 @@ #define LOG_TAG "NdkMediaExtractor" +#include "NdkMediaError.h" #include "NdkMediaExtractor.h" #include "NdkMediaFormatPriv.h" #include #include +#include #include #include #include @@ -41,11 +43,12 @@ static int translate_error(status_t err) { return OK; } ALOGE("sf error code: %d", err); - return -1000; + return AMEDIAERROR_GENERIC; } struct AMediaExtractor { sp mImpl; + sp mPsshBuf; }; @@ -79,14 +82,14 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) if (env == NULL) { ALOGE("setDataSource(path) must be called from Java thread"); env->ExceptionClear(); - return -1; + return AMEDIAERROR_UNSUPPORTED; } jclass mediahttpclass = env->FindClass("android/media/MediaHTTPService"); if (mediahttpclass == NULL) { ALOGE("can't find MediaHttpService"); env->ExceptionClear(); - return -1; + return AMEDIAERROR_UNSUPPORTED; } jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass, @@ -94,7 +97,7 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) if (mediaHttpCreateMethod == NULL) { ALOGE("can't find method"); env->ExceptionClear(); - return -1; + return AMEDIAERROR_UNSUPPORTED; } jstring jloc = env->NewStringUTF(location); @@ -110,7 +113,7 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) mData->mImpl->setDataSource(httpService, location, NULL); env->ExceptionClear(); - return 0; + return OK; } int AMediaExtractor_getTrackCount(AMediaExtractor *mData) { @@ -184,6 +187,141 @@ int64_t AMediaExtractor_getSampletime(AMediaExtractor *mData) { return time; } +PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor *ex) { + + if (ex->mPsshBuf != NULL) { + return (PsshInfo*) ex->mPsshBuf->data(); + } + + sp format; + ex->mImpl->getFileFormat(&format); + sp buffer; + if(!format->findBuffer("pssh", &buffer)) { + return NULL; + } + + // the format of the buffer is 1 or more of: + // { + // 16 byte uuid + // 4 byte data length N + // N bytes of data + // } + + // Determine the number of entries in the source data. + // Since we got the data from stagefright, we trust it is valid and properly formatted. + const uint8_t* data = buffer->data(); + size_t len = buffer->size(); + size_t numentries = 0; + while (len > 0) { + numentries++; + + // skip uuid + data += 16; + len -= 16; + + // get data length + uint32_t datalen = *((uint32_t*)data); + data += 4; + len -= 4; + + // skip the data + data += datalen; + len -= datalen; + } + + // there are in the buffer, we need + // (source buffer size) + 4 + (4 * numentries) bytes for the PsshInfo structure + size_t newsize = buffer->size() + 4 + (4 * numentries); + ex->mPsshBuf = new ABuffer(newsize); + ex->mPsshBuf->setRange(0, newsize); + + // copy data + const uint8_t* src = buffer->data(); + uint8_t* dst = ex->mPsshBuf->data(); + uint8_t* dstdata = dst + 4 + numentries * sizeof(PsshEntry); + *((uint32_t*)dst) = numentries; + dst += 4; + for (size_t i = 0; i < numentries; i++) { + // copy uuid + memcpy(dst, src, 16); + src += 16; + dst += 16; + + // get/copy data length + uint32_t datalen = *((uint32_t*)src); + memcpy(dst, src, 4); + src += 4; + dst += 4; + + // the next entry in the destination is a pointer to the actual data, which we store + // after the array of PsshEntry + memcpy(dst, &dstdata, sizeof(dstdata)); + dst += 4; + + // copy the actual data + memcpy(dstdata, src, datalen); + dstdata += datalen; + src += datalen; + } + + return (PsshInfo*) ex->mPsshBuf->data(); +} + +AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *ex) { + sp meta; + if(ex->mImpl->getSampleMeta(&meta) != 0) { + return NULL; + } + + uint32_t type; + const void *crypteddata; + size_t cryptedsize; + if (!meta->findData(kKeyEncryptedSizes, &type, &crypteddata, &cryptedsize)) { + return NULL; + } + size_t numSubSamples = cryptedsize / sizeof(size_t); + + const void *cleardata; + size_t clearsize; + if (meta->findData(kKeyPlainSizes, &type, &cleardata, &clearsize)) { + if (clearsize != cryptedsize) { + // The two must be of the same length. + return NULL; + } + } + + const void *key; + size_t keysize; + if (meta->findData(kKeyCryptoIV, &type, &key, &keysize)) { + if (keysize != 16) { + // IVs must be 16 bytes in length. + return NULL; + } + } + + const void *iv; + size_t ivsize; + if (meta->findData(kKeyCryptoIV, &type, &iv, &ivsize)) { + if (ivsize != 16) { + // IVs must be 16 bytes in length. + return NULL; + } + } + + int32_t mode; + if (!meta->findInt32(kKeyCryptoMode, &mode)) { + mode = CryptoPlugin::kMode_AES_CTR; + } + + return AMediaCodecCryptoInfo_new( + numSubSamples, + (uint8_t*) key, + (uint8_t*) iv, + mode, + (size_t*) cleardata, + (size_t*) crypteddata); +} + } // extern "C" -- cgit v1.1 From 497ca097bf373ac69405131bd257915c97b31dc0 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Tue, 13 May 2014 09:31:15 -0700 Subject: WIP: MediaDrm NDK APIs Change-Id: I3ac08a3b027135c3fd2a9e95c5e8b3fd722df019 TODO: hooking up event handler, testing --- media/ndk/Android.mk | 2 + media/ndk/NdkMediaDrm.cpp | 605 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 607 insertions(+) create mode 100644 media/ndk/NdkMediaDrm.cpp (limited to 'media') diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk index 03f26a0..1f155f3 100644 --- a/media/ndk/Android.mk +++ b/media/ndk/Android.mk @@ -26,6 +26,7 @@ LOCAL_SRC_FILES:= \ NdkMediaExtractor.cpp \ NdkMediaFormat.cpp \ NdkMediaMuxer.cpp \ + NdkMediaDrm.cpp \ LOCAL_MODULE:= libmediandk @@ -42,6 +43,7 @@ LOCAL_SHARED_LIBRARIES := \ liblog \ libutils \ libandroid_runtime \ + libbinder \ include $(BUILD_SHARED_LIBRARY) diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp new file mode 100644 index 0000000..c55cba2 --- /dev/null +++ b/media/ndk/NdkMediaDrm.cpp @@ -0,0 +1,605 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "NdkMediaDrm" + +#include "NdkMediaDrm.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +using namespace android; + +typedef Vector idvec_t; + +struct AMediaDrm { + sp mDrm; + sp mDrmClient; + AMediaDrmEventListener mListener; + List mIds; + KeyedVector mQueryResults; + Vector mKeyRequest; + Vector mProvisionRequest; + String8 mProvisionUrl; + String8 mPropertyString; + Vector mPropertyByteArray; + List > mSecureStops; +}; + +extern "C" { + +static mediadrm_status_t translateStatus(status_t status) { + mediadrm_status_t result = MEDIADRM_UNKNOWN_ERROR; + switch (status) { + case OK: + result = MEDIADRM_OK; + break; + case android::ERROR_DRM_NOT_PROVISIONED: + result = MEDIADRM_NOT_PROVISIONED_ERROR; + break; + case android::ERROR_DRM_RESOURCE_BUSY: + result = MEDIADRM_RESOURCE_BUSY_ERROR; + break; + case android::ERROR_DRM_DEVICE_REVOKED: + result = MEDIADRM_DEVICE_REVOKED_ERROR; + break; + case android::ERROR_DRM_CANNOT_HANDLE: + result = MEDIADRM_INVALID_PARAMETER_ERROR; + break; + case android::ERROR_DRM_TAMPER_DETECTED: + result = MEDIADRM_TAMPER_DETECTED_ERROR; + break; + case android::ERROR_DRM_SESSION_NOT_OPENED: + result = MEDIADRM_SESSION_NOT_OPENED_ERROR; + break; + case android::ERROR_DRM_NO_LICENSE: + result = MEDIADRM_NEED_KEY_ERROR; + break; + case android::ERROR_DRM_LICENSE_EXPIRED: + result = MEDIADRM_LICENSE_EXPIRED_ERROR; + break; + default: + result = MEDIADRM_UNKNOWN_ERROR; + break; + } + return result; +} + +static sp CreateDrm() { + sp sm = defaultServiceManager(); + + sp binder = + sm->getService(String16("media.player")); + + sp service = + interface_cast(binder); + + if (service == NULL) { + return NULL; + } + + sp drm = service->makeDrm(); + + if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) { + return NULL; + } + + return drm; +} + + +static sp CreateDrmFromUUID(const AMediaUUID uuid) { + sp drm = CreateDrm(); + + if (drm == NULL) { + return NULL; + } + + status_t err = drm->createPlugin(uuid); + + if (err != OK) { + return NULL; + } + + return drm; +} + +bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) { + sp drm = CreateDrm(); + + if (drm == NULL) { + return false; + } + + String8 mimeStr = mimeType ? String8(mimeType) : String8(""); + return drm->isCryptoSchemeSupported(uuid, mimeStr); +} + +AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) { + AMediaDrm *mObj = new AMediaDrm(); + mObj->mDrm = CreateDrmFromUUID(uuid); + return mObj; +} + +void AMediaDrm_release(AMediaDrm *mObj) { + if (mObj->mDrm != NULL) { + mObj->mDrm->setListener(NULL); + mObj->mDrm->destroyPlugin(); + mObj->mDrm.clear(); + } + delete mObj; +} + +#if 0 +void AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) { + mObj->mListener = listener; +} +#endif + + +static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List::iterator &iter) { + iter = mObj->mIds.begin(); + while (iter != mObj->mIds.end()) { + if (iter->array() == id.ptr && iter->size() == id.length) { + return true; + } + } + return false; +} + +mediadrm_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) { + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + Vector session; + status_t status = mObj->mDrm->openSession(session); + if (status == OK) { + mObj->mIds.push_front(session); + List::iterator iter = mObj->mIds.begin(); + sessionId.ptr = iter->array(); + sessionId.length = iter->size(); + } + return MEDIADRM_OK; +} + +mediadrm_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) { + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + + List::iterator iter; + if (!findId(mObj, sessionId, iter)) { + return MEDIADRM_SESSION_NOT_OPENED_ERROR; + } + mObj->mDrm->closeSession(*iter); + mObj->mIds.erase(iter); + return MEDIADRM_OK; +} + +mediadrm_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope, + const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType, + const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters, + const uint8_t *&keyRequest, size_t &keyRequestSize) { + + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + if (!mimeType) { + return MEDIADRM_INVALID_PARAMETER_ERROR; + } + + List::iterator iter; + if (!findId(mObj, scope, iter)) { + return MEDIADRM_SESSION_NOT_OPENED_ERROR; + } + + Vector mdInit; + mdInit.appendArray(init, initSize); + DrmPlugin::KeyType mdKeyType; + switch (keyType) { + case KEY_TYPE_STREAMING: + mdKeyType = DrmPlugin::kKeyType_Streaming; + break; + case KEY_TYPE_OFFLINE: + mdKeyType = DrmPlugin::kKeyType_Offline; + break; + case KEY_TYPE_RELEASE: + mdKeyType = DrmPlugin::kKeyType_Release; + break; + default: + return MEDIADRM_INVALID_PARAMETER_ERROR; + } + KeyedVector mdOptionalParameters; + for (size_t i = 0; i < numOptionalParameters; i++) { + mdOptionalParameters.add(String8(optionalParameters[i].mKey), + String8(optionalParameters[i].mValue)); + } + String8 defaultUrl; + status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType), + mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl); + if (status != OK) { + return translateStatus(status); + } else { + keyRequest = mObj->mKeyRequest.array(); + keyRequestSize = mObj->mKeyRequest.size(); + } + return MEDIADRM_OK; +} + +mediadrm_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope, + const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) { + + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + if (!response || !responseSize) { + return MEDIADRM_INVALID_PARAMETER_ERROR; + } + + List::iterator iter; + if (!findId(mObj, scope, iter)) { + return MEDIADRM_SESSION_NOT_OPENED_ERROR; + } + Vector mdResponse; + mdResponse.appendArray(response, responseSize); + + Vector mdKeySetId; + status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId); + if (status == OK) { + mObj->mIds.push_front(mdKeySetId); + List::iterator iter = mObj->mIds.begin(); + keySetId.ptr = iter->array(); + keySetId.length = iter->size(); + } else { + keySetId.ptr = NULL; + keySetId.length = 0; + } + return MEDIADRM_OK; +} + +mediadrm_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, + const AMediaDrmKeySetId &keySetId) { + + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + List::iterator iter; + if (!findId(mObj, sessionId, iter)) { + return MEDIADRM_SESSION_NOT_OPENED_ERROR; + } + Vector keySet; + keySet.appendArray(keySetId.ptr, keySetId.length); + return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet)); +} + +mediadrm_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) { + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + List::iterator iter; + status_t status; + if (!findId(mObj, keySetId, iter)) { + Vector keySet; + keySet.appendArray(keySetId.ptr, keySetId.length); + status = mObj->mDrm->removeKeys(keySet); + } else { + status = mObj->mDrm->removeKeys(*iter); + mObj->mIds.erase(iter); + } + return translateStatus(status); +} + +mediadrm_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, + AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) { + + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + List::iterator iter; + if (!findId(mObj, sessionId, iter)) { + return MEDIADRM_SESSION_NOT_OPENED_ERROR; + } + + status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults); + if (status != OK) { + numPairs = 0; + return translateStatus(status); + } + + if (mObj->mQueryResults.size() > numPairs) { + numPairs = mObj->mQueryResults.size(); + return MEDIADRM_SHORT_BUFFER; + } + + for (size_t i = 0; i < mObj->mQueryResults.size(); i++) { + keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string(); + keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string(); + } + numPairs = mObj->mQueryResults.size(); + return MEDIADRM_OK; +} + +mediadrm_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest, + size_t &provisionRequestSize, const char *&serverUrl) { + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + if (!provisionRequestSize || !serverUrl) { + return MEDIADRM_INVALID_PARAMETER_ERROR; + } + + status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""), + mObj->mProvisionRequest, mObj->mProvisionUrl); + if (status != OK) { + return translateStatus(status); + } else { + provisionRequest = mObj->mProvisionRequest.array(); + provisionRequestSize = mObj->mProvisionRequest.size(); + serverUrl = mObj->mProvisionUrl.string(); + } + return MEDIADRM_OK; +} + +mediadrm_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj, + const uint8_t *response, size_t responseSize) { + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + if (!response || !responseSize) { + return MEDIADRM_INVALID_PARAMETER_ERROR; + } + + Vector mdResponse; + mdResponse.appendArray(response, responseSize); + + Vector unused; + return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused)); +} + +mediadrm_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, + AMediaDrmSecureStop *secureStops, size_t &numSecureStops) { + + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops); + if (status != OK) { + numSecureStops = 0; + return translateStatus(status); + } + if (numSecureStops < mObj->mSecureStops.size()) { + return MEDIADRM_SHORT_BUFFER; + } + List >::iterator iter = mObj->mSecureStops.begin(); + size_t i = 0; + while (iter != mObj->mSecureStops.end()) { + secureStops[i].ptr = iter->array(); + secureStops[i].length = iter->size(); + ++iter; + ++i; + } + numSecureStops = mObj->mSecureStops.size(); + return MEDIADRM_OK; +} + +mediadrm_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj, + const AMediaDrmSecureStop &ssRelease) { + + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + + Vector release; + release.appendArray(ssRelease.ptr, ssRelease.length); + return translateStatus(mObj->mDrm->releaseSecureStops(release)); +} + + +mediadrm_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName, + const char *&propertyValue) { + + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + + status_t status = mObj->mDrm->getPropertyString(String8(propertyName), + mObj->mPropertyString); + + if (status == OK) { + propertyValue = mObj->mPropertyString.string(); + } else { + propertyValue = NULL; + } + return translateStatus(status); +} + +mediadrm_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj, + const char *propertyName, AMediaDrmByteArray &propertyValue) { + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + + status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName), + mObj->mPropertyByteArray); + + if (status == OK) { + propertyValue.ptr = mObj->mPropertyByteArray.array(); + propertyValue.length = mObj->mPropertyByteArray.size(); + } else { + propertyValue.ptr = NULL; + propertyValue.length = 0; + } + return translateStatus(status); +} + +mediadrm_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj, + const char *propertyName, const char *value) { + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + + return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName), + String8(value))); +} + +mediadrm_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj, + const char *propertyName, const uint8_t *value, size_t valueSize) { + + Vector byteArray; + byteArray.appendArray(value, valueSize); + + return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName), + byteArray)); +} + + +static mediadrm_status_t encrypt_decrypt_common(AMediaDrm *mObj, + const AMediaDrmSessionId &sessionId, + const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, + const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) { + + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + List::iterator iter; + if (!findId(mObj, sessionId, iter)) { + return MEDIADRM_SESSION_NOT_OPENED_ERROR; + } + + status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm)); + if (status != OK) { + return translateStatus(status); + } + + Vector keyIdVec; + const size_t kKeyIdSize = 16; + keyIdVec.appendArray(keyId, kKeyIdSize); + + Vector inputVec; + inputVec.appendArray(input, dataSize); + + Vector ivVec; + const size_t kIvSize = 16; + ivVec.appendArray(iv, kIvSize); + + Vector outputVec; + if (encrypt) { + status_t status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec); + } else { + status_t status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec); + } + if (status == OK) { + memcpy(output, outputVec.array(), outputVec.size()); + } + return translateStatus(status); +} + +mediadrm_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, + const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, + const uint8_t *input, uint8_t *output, size_t dataSize) { + return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv, + input, output, dataSize, true); +} + +mediadrm_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, + const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, + const uint8_t *input, uint8_t *output, size_t dataSize) { + return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv, + input, output, dataSize, false); +} + +mediadrm_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, + const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize, + uint8_t *signature, size_t *signatureSize) { + + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + List::iterator iter; + if (!findId(mObj, sessionId, iter)) { + return MEDIADRM_SESSION_NOT_OPENED_ERROR; + } + + status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm)); + if (status != OK) { + return translateStatus(status); + } + + Vector keyIdVec; + const size_t kKeyIdSize = 16; + keyIdVec.appendArray(keyId, kKeyIdSize); + + Vector messageVec; + messageVec.appendArray(message, messageSize); + + Vector signatureVec; + status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec); + if (signatureVec.size() > *signatureSize) { + return MEDIADRM_SHORT_BUFFER; + } + if (status == OK) { + memcpy(signature, signatureVec.array(), signatureVec.size()); + } + return translateStatus(status); +} + +mediadrm_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, + const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize, + const uint8_t *signature, size_t signatureSize) { + + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + List::iterator iter; + if (!findId(mObj, sessionId, iter)) { + return MEDIADRM_SESSION_NOT_OPENED_ERROR; + } + + status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm)); + if (status != OK) { + return translateStatus(status); + } + + Vector keyIdVec; + const size_t kKeyIdSize = 16; + keyIdVec.appendArray(keyId, kKeyIdSize); + + Vector messageVec; + messageVec.appendArray(message, messageSize); + + Vector signatureVec; + signatureVec.appendArray(signature, signatureSize); + + bool match; + status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match); + if (status == OK) { + return match ? MEDIADRM_OK : MEDIADRM_VERIFY_FAILED; + } + return translateStatus(status); +} + +} // extern "C" + -- cgit v1.1 From 829e097f832b4c4c41733f9b77121888204d993e Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 13 May 2014 16:22:19 -0700 Subject: Fix typos and pointer math. Change-Id: I07f33a57454d013844b56bc3e57fe0a271e8b38c --- media/ndk/NdkMediaCodec.cpp | 12 +++++------- media/ndk/NdkMediaCrypto.cpp | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index 1f62fa2..ac05920 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -369,7 +369,7 @@ int AMediaCodec_queueSecureInputBuffer( if (err != 0) { ALOGE("queSecureInputBuffer: %s", errormsg.c_str()); } - delete subSamples; + delete [] subSamples; return translate_error(err); } @@ -396,13 +396,11 @@ AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( ret->mode = mode; // clearbytes and encryptedbytes point at the actual data, which follows - ret->clearbytes = (size_t*) ((&ret->encryptedbytes) + sizeof(ret->encryptedbytes)); - ret->encryptedbytes = (size_t*) (ret->clearbytes + (sizeof(size_t) * numsubsamples)); + ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct + ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes - size_t *dst = ret->clearbytes; - memcpy(dst, clearbytes, numsubsamples * sizeof(size_t)); - dst += numsubsamples * sizeof(size_t); - memcpy(dst, encryptedbytes, numsubsamples * sizeof(size_t)); + memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t)); + memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t)); return ret; } diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp index 25dfe6a..d57f42b 100644 --- a/media/ndk/NdkMediaCrypto.cpp +++ b/media/ndk/NdkMediaCrypto.cpp @@ -74,7 +74,7 @@ struct AMediaCrypto { extern "C" { -bool AMediaCrypto_isCryptoSchemeSupport(const AMediaUUID uuid) { +bool AMediaCrypto_isCryptoSchemeSupported(const AMediaUUID uuid) { sp crypto = makeCrypto(); if (crypto == NULL) { return false; -- cgit v1.1 From 3425fd5a55dd31e261d2f2a9590c762d6d0a6b79 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 14 May 2014 11:12:46 -0700 Subject: Only export necessary symbols Change-Id: I869d7124c8cc555f4b09801a898f4dd3ecb072ec --- media/ndk/Android.mk | 2 ++ media/ndk/NdkMediaCodec.cpp | 26 ++++++++++++++++- media/ndk/NdkMediaCrypto.cpp | 4 +++ media/ndk/NdkMediaDrm.cpp | 22 +++++++++++++++ media/ndk/NdkMediaExtractor.cpp | 15 ++++++++++ media/ndk/NdkMediaFormat.cpp | 62 +++++++++++++++++++++++++---------------- media/ndk/NdkMediaMuxer.cpp | 8 ++++++ 7 files changed, 114 insertions(+), 25 deletions(-) (limited to 'media') diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk index 1f155f3..8f795cd 100644 --- a/media/ndk/Android.mk +++ b/media/ndk/Android.mk @@ -35,6 +35,8 @@ LOCAL_C_INCLUDES := \ frameworks/base/core/jni \ frameworks/av/include/ndk +LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))' + LOCAL_SHARED_LIBRARIES := \ libbinder \ libmedia \ diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index ac05920..a7c06d5 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -159,19 +159,22 @@ static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool return mData; } - +EXPORT AMediaCodec* AMediaCodec_createCodecByName(const char *name) { return createAMediaCodec(name, false, false); } +EXPORT AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) { return createAMediaCodec(mime_type, true, false); } +EXPORT AMediaCodec* AMediaCodec_createEncoderByType(const char *name) { return createAMediaCodec(name, true, true); } +EXPORT int AMediaCodec_delete(AMediaCodec *mData) { if (mData->mCodec != NULL) { mData->mCodec->release(); @@ -187,6 +190,7 @@ int AMediaCodec_delete(AMediaCodec *mData) { return OK; } +EXPORT int AMediaCodec_configure( AMediaCodec *mData, const AMediaFormat* format, @@ -205,6 +209,7 @@ int AMediaCodec_configure( crypto ? crypto->mCrypto : NULL, flags)); } +EXPORT int AMediaCodec_start(AMediaCodec *mData) { status_t ret = mData->mCodec->start(); if (ret != OK) { @@ -216,6 +221,7 @@ int AMediaCodec_start(AMediaCodec *mData) { return OK; } +EXPORT int AMediaCodec_stop(AMediaCodec *mData) { int ret = translate_error(mData->mCodec->stop()); @@ -227,10 +233,12 @@ int AMediaCodec_stop(AMediaCodec *mData) { return ret; } +EXPORT int AMediaCodec_flush(AMediaCodec *mData) { return translate_error(mData->mCodec->flush()); } +EXPORT ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { size_t idx; status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs); @@ -241,6 +249,7 @@ ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { return translate_error(ret); } +EXPORT uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { android::Vector > abufs; if (mData->mCodec->getInputBuffers(&abufs) == 0) { @@ -258,6 +267,7 @@ uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_ return NULL; } +EXPORT uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { android::Vector > abufs; if (mData->mCodec->getOutputBuffers(&abufs) == 0) { @@ -275,6 +285,7 @@ uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out return NULL; } +EXPORT int AMediaCodec_queueInputBuffer(AMediaCodec *mData, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { @@ -283,6 +294,7 @@ int AMediaCodec_queueInputBuffer(AMediaCodec *mData, return translate_error(ret); } +EXPORT ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData, AMediaCodecBufferInfo *info, int64_t timeoutUs) { size_t idx; @@ -312,12 +324,14 @@ ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData, return translate_error(ret); } +EXPORT AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { sp format; mData->mCodec->getOutputFormat(&format); return AMediaFormat_fromMsg(&format); } +EXPORT int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) { if (render) { return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx)); @@ -326,6 +340,7 @@ int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) } } +EXPORT int AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) { mData->mCallback = callback; mData->mCallbackUserData = userdata; @@ -341,6 +356,7 @@ typedef struct AMediaCodecCryptoInfo { size_t *encryptedbytes; } AMediaCodecCryptoInfo; +EXPORT int AMediaCodec_queueSecureInputBuffer( AMediaCodec* codec, size_t idx, @@ -375,6 +391,7 @@ int AMediaCodec_queueSecureInputBuffer( +EXPORT AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( int numsubsamples, uint8_t key[16], @@ -406,15 +423,18 @@ AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( } +EXPORT int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) { free(info); return OK; } +EXPORT size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) { return ci->numsubsamples; } +EXPORT int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) { if (!dst || !ci) { return AMEDIAERROR_UNSUPPORTED; @@ -423,6 +443,7 @@ int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) { return OK; } +EXPORT int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) { if (!dst || !ci) { return AMEDIAERROR_UNSUPPORTED; @@ -431,6 +452,7 @@ int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) { return OK; } +EXPORT uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) { if (!ci) { return AMEDIAERROR_UNSUPPORTED; @@ -438,6 +460,7 @@ uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) { return ci->mode; } +EXPORT int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { if (!dst || !ci) { return AMEDIAERROR_UNSUPPORTED; @@ -446,6 +469,7 @@ int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) return OK; } +EXPORT int AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { if (!dst || !ci) { return AMEDIAERROR_UNSUPPORTED; diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp index d57f42b..c686273 100644 --- a/media/ndk/NdkMediaCrypto.cpp +++ b/media/ndk/NdkMediaCrypto.cpp @@ -74,6 +74,7 @@ struct AMediaCrypto { extern "C" { +EXPORT bool AMediaCrypto_isCryptoSchemeSupported(const AMediaUUID uuid) { sp crypto = makeCrypto(); if (crypto == NULL) { @@ -82,6 +83,7 @@ bool AMediaCrypto_isCryptoSchemeSupported(const AMediaUUID uuid) { return crypto->isCryptoSchemeSupported(uuid); } +EXPORT bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime) { sp crypto = makeCrypto(); if (crypto == NULL) { @@ -90,6 +92,7 @@ bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime) { return crypto->requiresSecureDecoderComponent(mime); } +EXPORT AMediaCrypto* AMediaCrypto_new(const AMediaUUID uuid, const void *data, size_t datasize) { sp tmp = makeCrypto(); @@ -107,6 +110,7 @@ AMediaCrypto* AMediaCrypto_new(const AMediaUUID uuid, const void *data, size_t d return crypto; } +EXPORT void AMediaCrypto_delete(AMediaCrypto* crypto) { delete crypto; } diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp index c55cba2..5e50418 100644 --- a/media/ndk/NdkMediaDrm.cpp +++ b/media/ndk/NdkMediaDrm.cpp @@ -127,6 +127,7 @@ static sp CreateDrmFromUUID(const AMediaUUID uuid) { return drm; } +EXPORT bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) { sp drm = CreateDrm(); @@ -138,12 +139,14 @@ bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeTy return drm->isCryptoSchemeSupported(uuid, mimeStr); } +EXPORT AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) { AMediaDrm *mObj = new AMediaDrm(); mObj->mDrm = CreateDrmFromUUID(uuid); return mObj; } +EXPORT void AMediaDrm_release(AMediaDrm *mObj) { if (mObj->mDrm != NULL) { mObj->mDrm->setListener(NULL); @@ -170,6 +173,7 @@ static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List: return false; } +EXPORT mediadrm_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) { if (!mObj || mObj->mDrm == NULL) { return MEDIADRM_INVALID_OBJECT_ERROR; @@ -185,6 +189,7 @@ mediadrm_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &ses return MEDIADRM_OK; } +EXPORT mediadrm_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) { if (!mObj || mObj->mDrm == NULL) { return MEDIADRM_INVALID_OBJECT_ERROR; @@ -199,6 +204,7 @@ mediadrm_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSession return MEDIADRM_OK; } +EXPORT mediadrm_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope, const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType, const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters, @@ -249,6 +255,7 @@ mediadrm_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope return MEDIADRM_OK; } +EXPORT mediadrm_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope, const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) { @@ -280,6 +287,7 @@ mediadrm_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmS return MEDIADRM_OK; } +EXPORT mediadrm_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, const AMediaDrmKeySetId &keySetId) { @@ -295,6 +303,7 @@ mediadrm_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionI return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet)); } +EXPORT mediadrm_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) { if (!mObj || mObj->mDrm == NULL) { return MEDIADRM_INVALID_OBJECT_ERROR; @@ -312,6 +321,7 @@ mediadrm_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId return translateStatus(status); } +EXPORT mediadrm_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) { @@ -342,6 +352,7 @@ mediadrm_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessi return MEDIADRM_OK; } +EXPORT mediadrm_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest, size_t &provisionRequestSize, const char *&serverUrl) { if (!mObj || mObj->mDrm == NULL) { @@ -363,6 +374,7 @@ mediadrm_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t * return MEDIADRM_OK; } +EXPORT mediadrm_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj, const uint8_t *response, size_t responseSize) { if (!mObj || mObj->mDrm == NULL) { @@ -379,6 +391,7 @@ mediadrm_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj, return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused)); } +EXPORT mediadrm_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, AMediaDrmSecureStop *secureStops, size_t &numSecureStops) { @@ -405,6 +418,7 @@ mediadrm_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, return MEDIADRM_OK; } +EXPORT mediadrm_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj, const AMediaDrmSecureStop &ssRelease) { @@ -418,6 +432,7 @@ mediadrm_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj, } +EXPORT mediadrm_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName, const char *&propertyValue) { @@ -436,6 +451,7 @@ mediadrm_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *prope return translateStatus(status); } +EXPORT mediadrm_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj, const char *propertyName, AMediaDrmByteArray &propertyValue) { if (!mObj || mObj->mDrm == NULL) { @@ -455,6 +471,7 @@ mediadrm_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj, return translateStatus(status); } +EXPORT mediadrm_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj, const char *propertyName, const char *value) { if (!mObj || mObj->mDrm == NULL) { @@ -465,6 +482,7 @@ mediadrm_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj, String8(value))); } +EXPORT mediadrm_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj, const char *propertyName, const uint8_t *value, size_t valueSize) { @@ -517,6 +535,7 @@ static mediadrm_status_t encrypt_decrypt_common(AMediaDrm *mObj, return translateStatus(status); } +EXPORT mediadrm_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, const uint8_t *input, uint8_t *output, size_t dataSize) { @@ -524,6 +543,7 @@ mediadrm_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &s input, output, dataSize, true); } +EXPORT mediadrm_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, const uint8_t *input, uint8_t *output, size_t dataSize) { @@ -531,6 +551,7 @@ mediadrm_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &s input, output, dataSize, false); } +EXPORT mediadrm_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize, uint8_t *signature, size_t *signatureSize) { @@ -566,6 +587,7 @@ mediadrm_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sess return translateStatus(status); } +EXPORT mediadrm_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize, const uint8_t *signature, size_t signatureSize) { diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp index 0a66988..e23adf3 100644 --- a/media/ndk/NdkMediaExtractor.cpp +++ b/media/ndk/NdkMediaExtractor.cpp @@ -54,6 +54,7 @@ struct AMediaExtractor { extern "C" { +EXPORT AMediaExtractor* AMediaExtractor_new() { ALOGV("ctor"); AMediaExtractor *mData = new AMediaExtractor(); @@ -61,18 +62,21 @@ AMediaExtractor* AMediaExtractor_new() { return mData; } +EXPORT int AMediaExtractor_delete(AMediaExtractor *mData) { ALOGV("dtor"); delete mData; return OK; } +EXPORT int AMediaExtractor_setDataSourceFd(AMediaExtractor *mData, int fd, off64_t offset, off64_t length) { ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); mData->mImpl->setDataSource(fd, offset, length); return 0; } +EXPORT int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) { ALOGV("setDataSource(%s)", location); // TODO: add header support @@ -116,31 +120,37 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) return OK; } +EXPORT int AMediaExtractor_getTrackCount(AMediaExtractor *mData) { return mData->mImpl->countTracks(); } +EXPORT AMediaFormat* AMediaExtractor_getTrackFormat(AMediaExtractor *mData, size_t idx) { sp format; mData->mImpl->getTrackFormat(idx, &format); return AMediaFormat_fromMsg(&format); } +EXPORT int AMediaExtractor_selectTrack(AMediaExtractor *mData, size_t idx) { ALOGV("selectTrack(%z)", idx); return translate_error(mData->mImpl->selectTrack(idx)); } +EXPORT int AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx) { ALOGV("unselectTrack(%z)", idx); return translate_error(mData->mImpl->unselectTrack(idx)); } +EXPORT bool AMediaExtractor_advance(AMediaExtractor *mData) { //ALOGV("advance"); return mData->mImpl->advance(); } +EXPORT int AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size_t capacity) { //ALOGV("readSampleData"); sp tmp = new ABuffer(buffer, capacity); @@ -150,6 +160,7 @@ int AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size return -1; } +EXPORT int AMediaExtractor_getSampleFlags(AMediaExtractor *mData) { int sampleFlags = 0; sp meta; @@ -171,6 +182,7 @@ int AMediaExtractor_getSampleFlags(AMediaExtractor *mData) { return sampleFlags; } +EXPORT int AMediaExtractor_getSampleTrackIndex(AMediaExtractor *mData) { size_t idx; if (mData->mImpl->getSampleTrackIndex(&idx) != OK) { @@ -179,6 +191,7 @@ int AMediaExtractor_getSampleTrackIndex(AMediaExtractor *mData) { return idx; } +EXPORT int64_t AMediaExtractor_getSampletime(AMediaExtractor *mData) { int64_t time; if (mData->mImpl->getSampleTime(&time) != OK) { @@ -187,6 +200,7 @@ int64_t AMediaExtractor_getSampletime(AMediaExtractor *mData) { return time; } +EXPORT PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor *ex) { if (ex->mPsshBuf != NULL) { @@ -267,6 +281,7 @@ PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor *ex) { return (PsshInfo*) ex->mPsshBuf->data(); } +EXPORT AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *ex) { sp meta; if(ex->mImpl->getSampleMeta(&meta) != 0) { diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp index c08814f..e1d8c95 100644 --- a/media/ndk/NdkMediaFormat.cpp +++ b/media/ndk/NdkMediaFormat.cpp @@ -56,12 +56,14 @@ void AMediaFormat_getFormat(const AMediaFormat* mData, void* dest) { /* * public function follow */ +EXPORT AMediaFormat *AMediaFormat_new() { ALOGV("ctor"); sp msg = new AMessage(); return AMediaFormat_fromMsg(&msg); } +EXPORT int AMediaFormat_delete(AMediaFormat *mData) { ALOGV("dtor"); delete mData; @@ -69,6 +71,7 @@ int AMediaFormat_delete(AMediaFormat *mData) { } +EXPORT const char* AMediaFormat_toString(AMediaFormat *mData) { sp f = mData->mFormat; String8 ret; @@ -141,22 +144,27 @@ const char* AMediaFormat_toString(AMediaFormat *mData) { return mData->mDebug.string(); } +EXPORT bool AMediaFormat_getInt32(AMediaFormat* format, const char *name, int32_t *out) { return format->mFormat->findInt32(name, out); } +EXPORT bool AMediaFormat_getInt64(AMediaFormat* format, const char *name, int64_t *out) { return format->mFormat->findInt64(name, out); } +EXPORT bool AMediaFormat_getFloat(AMediaFormat* format, const char *name, float *out) { return format->mFormat->findFloat(name, out); } +EXPORT bool AMediaFormat_getSize(AMediaFormat* format, const char *name, size_t *out) { return format->mFormat->findSize(name, out); } +EXPORT bool AMediaFormat_getBuffer(AMediaFormat* format, const char *name, void** data, size_t *outsize) { sp buf; if (format->mFormat->findBuffer(name, &buf)) { @@ -167,6 +175,7 @@ bool AMediaFormat_getBuffer(AMediaFormat* format, const char *name, void** data, return false; } +EXPORT bool AMediaFormat_getString(AMediaFormat* mData, const char *name, const char **out) { for (size_t i = 0; i < mData->mStringCache.size(); i++) { @@ -186,23 +195,28 @@ bool AMediaFormat_getString(AMediaFormat* mData, const char *name, const char ** return false; } +EXPORT void AMediaFormat_setInt32(AMediaFormat* format, const char *name, int32_t value) { format->mFormat->setInt32(name, value); } +EXPORT void AMediaFormat_setInt64(AMediaFormat* format, const char *name, int64_t value) { format->mFormat->setInt64(name, value); } +EXPORT void AMediaFormat_setFloat(AMediaFormat* format, const char* name, float value) { format->mFormat->setFloat(name, value); } +EXPORT void AMediaFormat_setString(AMediaFormat* format, const char* name, const char* value) { // AMessage::setString() makes a copy of the string format->mFormat->setString(name, value, strlen(value)); } +EXPORT void AMediaFormat_setBuffer(AMediaFormat* format, const char* name, void* data, size_t size) { // the ABuffer(void*, size_t) constructor doesn't take ownership of the data, so create // a new buffer and copy the data into it @@ -214,30 +228,30 @@ void AMediaFormat_setBuffer(AMediaFormat* format, const char* name, void* data, } -const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile"; -const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate"; -const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count"; -const char* AMEDIAFORMAT_KEY_CHANNEL_MASK = "channel-mask"; -const char* AMEDIAFORMAT_KEY_COLOR_FORMAT = "color-format"; -const char* AMEDIAFORMAT_KEY_DURATION = "durationUs"; -const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level"; -const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate"; -const char* AMEDIAFORMAT_KEY_HEIGHT = "height"; -const char* AMEDIAFORMAT_KEY_IS_ADTS = "is-adts"; -const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT = "is-autoselect"; -const char* AMEDIAFORMAT_KEY_IS_DEFAULT = "is-default"; -const char* AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle"; -const char* AMEDIAFORMAT_KEY_I_FRAME_INTERVAL = "i-frame-interval"; -const char* AMEDIAFORMAT_KEY_LANGUAGE = "language"; -const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height"; -const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size"; -const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width"; -const char* AMEDIAFORMAT_KEY_MIME = "mime"; -const char* AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown"; -const char* AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after"; -const char* AMEDIAFORMAT_KEY_SAMPLE_RATE = "sample-rate"; -const char* AMEDIAFORMAT_KEY_WIDTH = "width"; -const char* AMEDIAFORMAT_KEY_STRIDE = "stride"; +EXPORT const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile"; +EXPORT const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate"; +EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count"; +EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_MASK = "channel-mask"; +EXPORT const char* AMEDIAFORMAT_KEY_COLOR_FORMAT = "color-format"; +EXPORT const char* AMEDIAFORMAT_KEY_DURATION = "durationUs"; +EXPORT const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level"; +EXPORT const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate"; +EXPORT const char* AMEDIAFORMAT_KEY_HEIGHT = "height"; +EXPORT const char* AMEDIAFORMAT_KEY_IS_ADTS = "is-adts"; +EXPORT const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT = "is-autoselect"; +EXPORT const char* AMEDIAFORMAT_KEY_IS_DEFAULT = "is-default"; +EXPORT const char* AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle"; +EXPORT const char* AMEDIAFORMAT_KEY_I_FRAME_INTERVAL = "i-frame-interval"; +EXPORT const char* AMEDIAFORMAT_KEY_LANGUAGE = "language"; +EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height"; +EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size"; +EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width"; +EXPORT const char* AMEDIAFORMAT_KEY_MIME = "mime"; +EXPORT const char* AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown"; +EXPORT const char* AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after"; +EXPORT const char* AMEDIAFORMAT_KEY_SAMPLE_RATE = "sample-rate"; +EXPORT const char* AMEDIAFORMAT_KEY_WIDTH = "width"; +EXPORT const char* AMEDIAFORMAT_KEY_STRIDE = "stride"; } // extern "C" diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp index 98129cb..aa78740 100644 --- a/media/ndk/NdkMediaMuxer.cpp +++ b/media/ndk/NdkMediaMuxer.cpp @@ -52,6 +52,7 @@ struct AMediaMuxer { extern "C" { +EXPORT AMediaMuxer* AMediaMuxer_new(int fd, OutputFormat format) { ALOGV("ctor"); AMediaMuxer *mData = new AMediaMuxer(); @@ -59,34 +60,41 @@ AMediaMuxer* AMediaMuxer_new(int fd, OutputFormat format) { return mData; } +EXPORT int AMediaMuxer_delete(AMediaMuxer *muxer) { ALOGV("dtor"); delete muxer; return OK; } +EXPORT int AMediaMuxer_setLocation(AMediaMuxer *muxer, float latitude, float longtitude) { return translate_error(muxer->mImpl->setLocation(latitude * 10000, longtitude * 10000)); } +EXPORT int AMediaMuxer_setOrientationHint(AMediaMuxer *muxer, int degrees) { return translate_error(muxer->mImpl->setOrientationHint(degrees)); } +EXPORT ssize_t AMediaMuxer_addTrack(AMediaMuxer *muxer, const AMediaFormat *format) { sp msg; AMediaFormat_getFormat(format, &msg); return translate_error(muxer->mImpl->addTrack(msg)); } +EXPORT int AMediaMuxer_start(AMediaMuxer *muxer) { return translate_error(muxer->mImpl->start()); } +EXPORT int AMediaMuxer_stop(AMediaMuxer *muxer) { return translate_error(muxer->mImpl->stop()); } +EXPORT int AMediaMuxer_writeSampleData(AMediaMuxer *muxer, size_t trackIdx, const uint8_t *data, const AMediaCodecBufferInfo &info) { sp buf = new ABuffer((void*)(data + info.offset), info.size); -- cgit v1.1 From 2472b1c0d63454e5d90a982bd6c555de6c3127bd Mon Sep 17 00:00:00 2001 From: Rachad Date: Mon, 5 May 2014 18:31:02 -0700 Subject: Add HEVC decoder support to ACodec bug: 14571712 Change-Id: I221625a42e143cb1c581059694f6730211e251ae --- media/libstagefright/ACodec.cpp | 3 +++ media/libstagefright/MediaDefs.cpp | 1 + 2 files changed, 4 insertions(+) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 0a3a3b6..b6db00c 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -985,6 +985,8 @@ status_t ACodec::setComponentRole( "audio_decoder.g711alaw", "audio_encoder.g711alaw" }, { MEDIA_MIMETYPE_VIDEO_AVC, "video_decoder.avc", "video_encoder.avc" }, + { MEDIA_MIMETYPE_VIDEO_HEVC, + "video_decoder.hevc", "video_encoder.hevc" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "video_decoder.mpeg4", "video_encoder.mpeg4" }, { MEDIA_MIMETYPE_VIDEO_H263, @@ -1806,6 +1808,7 @@ static const struct VideoCodingMapEntry { OMX_VIDEO_CODINGTYPE mVideoCodingType; } kVideoCodingMapEntry[] = { { MEDIA_MIMETYPE_VIDEO_AVC, OMX_VIDEO_CodingAVC }, + { MEDIA_MIMETYPE_VIDEO_HEVC, OMX_VIDEO_CodingHEVC }, { MEDIA_MIMETYPE_VIDEO_MPEG4, OMX_VIDEO_CodingMPEG4 }, { MEDIA_MIMETYPE_VIDEO_H263, OMX_VIDEO_CodingH263 }, { MEDIA_MIMETYPE_VIDEO_MPEG2, OMX_VIDEO_CodingMPEG2 }, diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp index c670bb4..8229e55 100644 --- a/media/libstagefright/MediaDefs.cpp +++ b/media/libstagefright/MediaDefs.cpp @@ -23,6 +23,7 @@ const char *MEDIA_MIMETYPE_IMAGE_JPEG = "image/jpeg"; const char *MEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8"; const char *MEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9"; const char *MEDIA_MIMETYPE_VIDEO_AVC = "video/avc"; +const char *MEDIA_MIMETYPE_VIDEO_HEVC = "video/hevc"; const char *MEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es"; const char *MEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp"; const char *MEDIA_MIMETYPE_VIDEO_MPEG2 = "video/mpeg2"; -- cgit v1.1 From 609b815a3131d22da38b2f452faa9f89daad4039 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Fri, 2 May 2014 11:05:04 -0700 Subject: Update OMX messages for 64 bit Change node_id and buffer_id to uint32_t. Ensure IOMX messages are fixed size. Remove 64 bit compile warnings in associated files. Change-Id: Icdbef00aca575e5dc502ebb52e3ce7d0d7883203 Signed-off-by: Andy Hung --- media/libmedia/IOMX.cpp | 132 +++++++++++++------------ media/libstagefright/ACodec.cpp | 59 ++++++----- media/libstagefright/MediaCodec.cpp | 4 +- media/libstagefright/OMXClient.cpp | 8 +- media/libstagefright/OMXCodec.cpp | 44 ++++----- media/libstagefright/include/OMX.h | 4 +- media/libstagefright/include/OMXNodeInstance.h | 13 +++ media/libstagefright/omx/OMX.cpp | 12 ++- media/libstagefright/omx/OMXNodeInstance.cpp | 108 ++++++++++++++++---- 9 files changed, 235 insertions(+), 149 deletions(-) (limited to 'media') diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index 9c13848..5df232f 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -65,7 +65,7 @@ public: virtual bool livesLocally(node_id node, pid_t pid) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(pid); remote()->transact(LIVES_LOCALLY, data, &reply); @@ -104,7 +104,7 @@ public: status_t err = reply.readInt32(); if (err == OK) { - *node = (void*)reply.readIntPtr(); + *node = (node_id)reply.readInt32(); } else { *node = 0; } @@ -115,7 +115,7 @@ public: virtual status_t freeNode(node_id node) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); remote()->transact(FREE_NODE, data, &reply); return reply.readInt32(); @@ -125,7 +125,7 @@ public: node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(cmd); data.writeInt32(param); remote()->transact(SEND_COMMAND, data, &reply); @@ -138,7 +138,7 @@ public: void *params, size_t size) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(index); data.writeInt64(size); data.write(params, size); @@ -159,7 +159,7 @@ public: const void *params, size_t size) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(index); data.writeInt64(size); data.write(params, size); @@ -173,7 +173,7 @@ public: void *params, size_t size) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(index); data.writeInt64(size); data.write(params, size); @@ -194,7 +194,7 @@ public: const void *params, size_t size) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(index); data.writeInt64(size); data.write(params, size); @@ -207,7 +207,7 @@ public: node_id node, OMX_STATETYPE* state) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); remote()->transact(GET_STATE, data, &reply); *state = static_cast(reply.readInt32()); @@ -218,7 +218,7 @@ public: node_id node, OMX_U32 port_index, OMX_BOOL enable) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(port_index); data.writeInt32((uint32_t)enable); remote()->transact(ENABLE_GRAPHIC_BUFFERS, data, &reply); @@ -231,7 +231,7 @@ public: node_id node, OMX_U32 port_index, OMX_U32* usage) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(port_index); remote()->transact(GET_GRAPHIC_BUFFER_USAGE, data, &reply); @@ -245,7 +245,7 @@ public: buffer_id *buffer) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(port_index); data.writeStrongBinder(params->asBinder()); remote()->transact(USE_BUFFER, data, &reply); @@ -257,7 +257,7 @@ public: return err; } - *buffer = (void*)reply.readIntPtr(); + *buffer = (buffer_id)reply.readInt32(); return err; } @@ -268,7 +268,7 @@ public: const sp &graphicBuffer, buffer_id *buffer) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(port_index); data.write(*graphicBuffer); remote()->transact(USE_GRAPHIC_BUFFER, data, &reply); @@ -280,7 +280,7 @@ public: return err; } - *buffer = (void*)reply.readIntPtr(); + *buffer = (buffer_id)reply.readInt32(); return err; } @@ -290,10 +290,10 @@ public: const sp &graphicBuffer, buffer_id buffer) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(port_index); data.write(*graphicBuffer); - data.writeIntPtr((intptr_t)buffer); + data.writeInt32((int32_t)buffer); remote()->transact(UPDATE_GRAPHIC_BUFFER_IN_META, data, &reply); status_t err = reply.readInt32(); @@ -306,7 +306,7 @@ public: Parcel data, reply; status_t err; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(port_index); err = remote()->transact(CREATE_INPUT_SURFACE, data, &reply); if (err != OK) { @@ -329,7 +329,7 @@ public: Parcel data, reply; status_t err; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); err = remote()->transact(SIGNAL_END_OF_INPUT_STREAM, data, &reply); if (err != OK) { ALOGW("binder transaction failed: %d", err); @@ -343,7 +343,7 @@ public: node_id node, OMX_U32 port_index, OMX_BOOL enable) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(port_index); data.writeInt32((uint32_t)enable); remote()->transact(STORE_META_DATA_IN_BUFFERS, data, &reply); @@ -357,7 +357,7 @@ public: OMX_U32 max_width, OMX_U32 max_height) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(port_index); data.writeInt32((int32_t)enable); data.writeInt32(max_width); @@ -373,7 +373,7 @@ public: buffer_id *buffer, void **buffer_data) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(port_index); data.writeInt64(size); remote()->transact(ALLOC_BUFFER, data, &reply); @@ -385,8 +385,8 @@ public: return err; } - *buffer = (void *)reply.readIntPtr(); - *buffer_data = (void *)reply.readIntPtr(); + *buffer = (buffer_id)reply.readInt32(); + *buffer_data = (void *)reply.readInt64(); return err; } @@ -396,7 +396,7 @@ public: buffer_id *buffer) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(port_index); data.writeStrongBinder(params->asBinder()); remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply); @@ -408,7 +408,7 @@ public: return err; } - *buffer = (void*)reply.readIntPtr(); + *buffer = (buffer_id)reply.readInt32(); return err; } @@ -417,9 +417,9 @@ public: node_id node, OMX_U32 port_index, buffer_id buffer) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(port_index); - data.writeIntPtr((intptr_t)buffer); + data.writeInt32((int32_t)buffer); remote()->transact(FREE_BUFFER, data, &reply); return reply.readInt32(); @@ -428,8 +428,8 @@ public: virtual status_t fillBuffer(node_id node, buffer_id buffer) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); - data.writeIntPtr((intptr_t)buffer); + data.writeInt32((int32_t)node); + data.writeInt32((int32_t)buffer); remote()->transact(FILL_BUFFER, data, &reply); return reply.readInt32(); @@ -442,8 +442,8 @@ public: OMX_U32 flags, OMX_TICKS timestamp) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); - data.writeIntPtr((intptr_t)buffer); + data.writeInt32((int32_t)node); + data.writeInt32((int32_t)buffer); data.writeInt32(range_offset); data.writeInt32(range_length); data.writeInt32(flags); @@ -459,7 +459,7 @@ public: OMX_INDEXTYPE *index) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeCString(parameter_name); remote()->transact(GET_EXTENSION_INDEX, data, &reply); @@ -482,7 +482,7 @@ public: size_t size) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); - data.writeIntPtr((intptr_t)node); + data.writeInt32((int32_t)node); data.writeInt32(port_index); data.writeInt64(size); data.write(optionData, size); @@ -509,7 +509,7 @@ status_t BnOMX::onTransact( case LIVES_LOCALLY: { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void *)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); pid_t pid = (pid_t)data.readInt32(); reply->writeInt32(livesLocally(node, pid)); @@ -553,7 +553,7 @@ status_t BnOMX::onTransact( status_t err = allocateNode(name, observer, &node); reply->writeInt32(err); if (err == OK) { - reply->writeIntPtr((intptr_t)node); + reply->writeInt32((int32_t)node); } return NO_ERROR; @@ -563,7 +563,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); reply->writeInt32(freeNode(node)); @@ -574,7 +574,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_COMMANDTYPE cmd = static_cast(data.readInt32()); @@ -593,7 +593,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_INDEXTYPE index = static_cast(data.readInt32()); size_t size = data.readInt64(); @@ -644,7 +644,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_STATETYPE state = OMX_StateInvalid; status_t err = getState(node, &state); @@ -658,7 +658,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); OMX_BOOL enable = (OMX_BOOL)data.readInt32(); @@ -672,7 +672,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); OMX_U32 usage = 0; @@ -687,7 +687,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); sp params = interface_cast(data.readStrongBinder()); @@ -697,7 +697,7 @@ status_t BnOMX::onTransact( reply->writeInt32(err); if (err == OK) { - reply->writeIntPtr((intptr_t)buffer); + reply->writeInt32((int32_t)buffer); } return NO_ERROR; @@ -707,7 +707,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); sp graphicBuffer = new GraphicBuffer(); data.read(*graphicBuffer); @@ -718,7 +718,7 @@ status_t BnOMX::onTransact( reply->writeInt32(err); if (err == OK) { - reply->writeIntPtr((intptr_t)buffer); + reply->writeInt32((int32_t)buffer); } return NO_ERROR; @@ -728,11 +728,11 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); sp graphicBuffer = new GraphicBuffer(); data.read(*graphicBuffer); - buffer_id buffer = (void*)data.readIntPtr(); + buffer_id buffer = (buffer_id)data.readInt32(); status_t err = updateGraphicBufferInMeta( node, port_index, graphicBuffer, buffer); @@ -745,7 +745,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); sp bufferProducer; @@ -765,7 +765,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); status_t err = signalEndOfInputStream(node); reply->writeInt32(err); @@ -777,7 +777,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); OMX_BOOL enable = (OMX_BOOL)data.readInt32(); @@ -791,7 +791,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); OMX_BOOL enable = (OMX_BOOL)data.readInt32(); OMX_U32 max_width = data.readInt32(); @@ -808,7 +808,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); size_t size = data.readInt64(); @@ -819,8 +819,8 @@ status_t BnOMX::onTransact( reply->writeInt32(err); if (err == OK) { - reply->writeIntPtr((intptr_t)buffer); - reply->writeIntPtr((intptr_t)buffer_data); + reply->writeInt32((int32_t)buffer); + reply->writeInt64((uintptr_t)buffer_data); } return NO_ERROR; @@ -830,7 +830,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); sp params = interface_cast(data.readStrongBinder()); @@ -842,7 +842,7 @@ status_t BnOMX::onTransact( reply->writeInt32(err); if (err == OK) { - reply->writeIntPtr((intptr_t)buffer); + reply->writeInt32((int32_t)buffer); } return NO_ERROR; @@ -852,9 +852,9 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); - buffer_id buffer = (void*)data.readIntPtr(); + buffer_id buffer = (buffer_id)data.readInt32(); reply->writeInt32(freeBuffer(node, port_index, buffer)); return NO_ERROR; @@ -864,8 +864,8 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); - buffer_id buffer = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); + buffer_id buffer = (buffer_id)data.readInt32(); reply->writeInt32(fillBuffer(node, buffer)); return NO_ERROR; @@ -875,8 +875,8 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); - buffer_id buffer = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); + buffer_id buffer = (buffer_id)data.readInt32(); OMX_U32 range_offset = data.readInt32(); OMX_U32 range_length = data.readInt32(); OMX_U32 flags = data.readInt32(); @@ -894,7 +894,7 @@ status_t BnOMX::onTransact( { CHECK_OMX_INTERFACE(IOMX, data, reply); - node_id node = (void*)data.readIntPtr(); + node_id node = (node_id)data.readInt32(); const char *parameter_name = data.readCString(); OMX_INDEXTYPE index; @@ -927,6 +927,8 @@ public: data.writeInterfaceToken(IOMXObserver::getInterfaceDescriptor()); data.write(&msg, sizeof(msg)); + ALOGV("onMessage writing message %d, size %zu", msg.type, sizeof(msg)); + remote()->transact(OBSERVER_ON_MSG, data, &reply, IBinder::FLAG_ONEWAY); } }; @@ -943,6 +945,8 @@ status_t BnOMXObserver::onTransact( omx_message msg; data.read(&msg, sizeof(msg)); + ALOGV("onTransact reading message %d, size %zu", msg.type, sizeof(msg)); + // XXX Could use readInplace maybe? onMessage(msg); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 0a3a3b6..0fe7ff2 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "ACodec" +#include #include #include @@ -67,7 +68,7 @@ struct CodecObserver : public BnOMXObserver { sp msg = mNotify->dup(); msg->setInt32("type", omx_msg.type); - msg->setPointer("node", omx_msg.node); + msg->setInt32("node", omx_msg.node); switch (omx_msg.type) { case omx_message::EVENT: @@ -80,13 +81,13 @@ struct CodecObserver : public BnOMXObserver { case omx_message::EMPTY_BUFFER_DONE: { - msg->setPointer("buffer", omx_msg.u.buffer_data.buffer); + msg->setInt32("buffer", omx_msg.u.buffer_data.buffer); break; } case omx_message::FILL_BUFFER_DONE: { - msg->setPointer( + msg->setInt32( "buffer", omx_msg.u.extended_buffer_data.buffer); msg->setInt32( "range_offset", @@ -355,7 +356,7 @@ private: ACodec::ACodec() : mQuirks(0), - mNode(NULL), + mNode(0), mSentFormat(false), mIsEncoder(false), mUseMetadataOnEncoderOutput(false), @@ -370,8 +371,8 @@ ACodec::ACodec() mMetaDataBuffersToSubmit(0), mRepeatFrameDelayUs(-1ll), mMaxPtsGapUs(-1ll), - mTimePerCaptureUs(-1ll), mTimePerFrameUs(-1ll), + mTimePerCaptureUs(-1ll), mCreateInputBuffersSuspended(false) { mUninitializedState = new UninitializedState(this); mLoadedState = new LoadedState(this); @@ -488,7 +489,7 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); if (err == OK) { - ALOGV("[%s] Allocating %lu buffers of size %lu on %s port", + ALOGV("[%s] Allocating %u buffers of size %u on %s port", mComponentName.c_str(), def.nBufferCountActual, def.nBufferSize, portIndex == kPortIndexInput ? "input" : "output"); @@ -662,7 +663,7 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( break; } - ALOGW("[%s] setting nBufferCountActual to %lu failed: %d", + ALOGW("[%s] setting nBufferCountActual to %u failed: %d", mComponentName.c_str(), newBufferCount, err); /* exit condition */ if (extraBuffers == 0) { @@ -692,7 +693,7 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { return err; mNumUndequeuedBuffers = minUndequeuedBuffers; - ALOGV("[%s] Allocating %lu buffers from a native window of size %lu on " + ALOGV("[%s] Allocating %u buffers from a native window of size %u on " "output port", mComponentName.c_str(), bufferCount, bufferSize); @@ -716,14 +717,14 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { err = mOMX->useGraphicBuffer(mNode, kPortIndexOutput, graphicBuffer, &bufferId); if (err != 0) { - ALOGE("registering GraphicBuffer %lu with OMX IL component failed: " + ALOGE("registering GraphicBuffer %u with OMX IL component failed: " "%d", i, err); break; } mBuffers[kPortIndexOutput].editItemAt(i).mBufferID = bufferId; - ALOGV("[%s] Registered graphic buffer with ID %p (pointer = %p)", + ALOGV("[%s] Registered graphic buffer with ID %u (pointer = %p)", mComponentName.c_str(), bufferId, graphicBuffer.get()); } @@ -758,7 +759,7 @@ status_t ACodec::allocateOutputMetaDataBuffers() { return err; mNumUndequeuedBuffers = minUndequeuedBuffers; - ALOGV("[%s] Allocating %lu meta buffers on output port", + ALOGV("[%s] Allocating %u meta buffers on output port", mComponentName.c_str(), bufferCount); size_t totalSize = bufferCount * 8; @@ -782,7 +783,7 @@ status_t ACodec::allocateOutputMetaDataBuffers() { mBuffers[kPortIndexOutput].push(info); - ALOGV("[%s] allocated meta buffer with ID %p (pointer = %p)", + ALOGV("[%s] allocated meta buffer with ID %u (pointer = %p)", mComponentName.c_str(), info.mBufferID, mem->pointer()); } @@ -799,7 +800,7 @@ status_t ACodec::submitOutputMetaDataBuffer() { if (info == NULL) return ERROR_IO; - ALOGV("[%s] submitting output meta buffer ID %p for graphic buffer %p", + ALOGV("[%s] submitting output meta buffer ID %u for graphic buffer %p", mComponentName.c_str(), info->mBufferID, info->mGraphicBuffer.get()); --mMetaDataBuffersToSubmit; @@ -813,7 +814,7 @@ status_t ACodec::submitOutputMetaDataBuffer() { status_t ACodec::cancelBufferToNativeWindow(BufferInfo *info) { CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US); - ALOGV("[%s] Calling cancelBuffer on buffer %p", + ALOGV("[%s] Calling cancelBuffer on buffer %u", mComponentName.c_str(), info->mBufferID); int err = mNativeWindow->cancelBuffer( @@ -2611,7 +2612,7 @@ bool ACodec::allYourBuffersAreBelongToUs( if (info->mStatus != BufferInfo::OWNED_BY_US && info->mStatus != BufferInfo::OWNED_BY_NATIVE_WINDOW) { - ALOGV("[%s] Buffer %p on port %ld still has status %d", + ALOGV("[%s] Buffer %u on port %u still has status %d", mComponentName.c_str(), info->mBufferID, portIndex, info->mStatus); return false; @@ -3177,7 +3178,7 @@ bool ACodec::BaseState::onOMXMessage(const sp &msg) { } IOMX::node_id nodeID; - CHECK(msg->findPointer("node", &nodeID)); + CHECK(msg->findInt32("node", (int32_t*)&nodeID)); CHECK_EQ(nodeID, mCodec->mNode); switch (type) { @@ -3208,7 +3209,7 @@ bool ACodec::BaseState::onOMXMessage(const sp &msg) { case omx_message::EMPTY_BUFFER_DONE: { IOMX::buffer_id bufferID; - CHECK(msg->findPointer("buffer", &bufferID)); + CHECK(msg->findInt32("buffer", (int32_t*)&bufferID)); return onOMXEmptyBufferDone(bufferID); } @@ -3216,7 +3217,7 @@ bool ACodec::BaseState::onOMXMessage(const sp &msg) { case omx_message::FILL_BUFFER_DONE: { IOMX::buffer_id bufferID; - CHECK(msg->findPointer("buffer", &bufferID)); + CHECK(msg->findInt32("buffer", (int32_t*)&bufferID)); int32_t rangeOffset, rangeLength, flags; int64_t timeUs; @@ -3313,13 +3314,13 @@ void ACodec::BaseState::postFillThisBuffer(BufferInfo *info) { sp notify = mCodec->mNotify->dup(); notify->setInt32("what", ACodec::kWhatFillThisBuffer); - notify->setPointer("buffer-id", info->mBufferID); + notify->setInt32("buffer-id", info->mBufferID); info->mData->meta()->clear(); notify->setBuffer("buffer", info->mData); sp reply = new AMessage(kWhatInputBufferFilled, mCodec->id()); - reply->setPointer("buffer-id", info->mBufferID); + reply->setInt32("buffer-id", info->mBufferID); notify->setMessage("reply", reply); @@ -3330,8 +3331,7 @@ void ACodec::BaseState::postFillThisBuffer(BufferInfo *info) { void ACodec::BaseState::onInputBufferFilled(const sp &msg) { IOMX::buffer_id bufferID; - CHECK(msg->findPointer("buffer-id", &bufferID)); - + CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID)); sp buffer; int32_t err = OK; bool eos = false; @@ -3530,7 +3530,7 @@ bool ACodec::BaseState::onOMXFillBufferDone( size_t rangeOffset, size_t rangeLength, OMX_U32 flags, int64_t timeUs) { - ALOGV("[%s] onOMXFillBufferDone %p time %lld us, flags = 0x%08lx", + ALOGV("[%s] onOMXFillBufferDone %u time %" PRId64 " us, flags = 0x%08x", mCodec->mComponentName.c_str(), bufferID, timeUs, flags); ssize_t index; @@ -3567,7 +3567,7 @@ bool ACodec::BaseState::onOMXFillBufferDone( case RESUBMIT_BUFFERS: { if (rangeLength == 0 && !(flags & OMX_BUFFERFLAG_EOS)) { - ALOGV("[%s] calling fillBuffer %p", + ALOGV("[%s] calling fillBuffer %u", mCodec->mComponentName.c_str(), info->mBufferID); CHECK_EQ(mCodec->mOMX->fillBuffer( @@ -3609,11 +3609,11 @@ bool ACodec::BaseState::onOMXFillBufferDone( sp notify = mCodec->mNotify->dup(); notify->setInt32("what", ACodec::kWhatDrainThisBuffer); - notify->setPointer("buffer-id", info->mBufferID); + notify->setInt32("buffer-id", info->mBufferID); notify->setBuffer("buffer", info->mData); notify->setInt32("flags", flags); - reply->setPointer("buffer-id", info->mBufferID); + reply->setInt32("buffer-id", info->mBufferID); notify->setMessage("reply", reply); @@ -3649,8 +3649,7 @@ bool ACodec::BaseState::onOMXFillBufferDone( void ACodec::BaseState::onOutputBufferDrained(const sp &msg) { IOMX::buffer_id bufferID; - CHECK(msg->findPointer("buffer-id", &bufferID)); - + CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID)); ssize_t index; BufferInfo *info = mCodec->findBufferByID(kPortIndexOutput, bufferID, &index); @@ -3735,7 +3734,7 @@ void ACodec::BaseState::onOutputBufferDrained(const sp &msg) { } if (info != NULL) { - ALOGV("[%s] calling fillBuffer %p", + ALOGV("[%s] calling fillBuffer %u", mCodec->mComponentName.c_str(), info->mBufferID); CHECK_EQ(mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID), @@ -5008,7 +5007,7 @@ bool ACodec::FlushingState::onOMXEvent( { sp msg = new AMessage(kWhatOMXMessage, mCodec->id()); msg->setInt32("type", omx_message::EVENT); - msg->setPointer("node", mCodec->mNode); + msg->setInt32("node", mCodec->mNode); msg->setInt32("event", event); msg->setInt32("data1", data1); msg->setInt32("data2", data2); diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 5b525f2..d8a8380 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -1555,8 +1555,8 @@ size_t MediaCodec::updateBuffers( int32_t portIndex, const sp &msg) { CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput); - void *bufferID; - CHECK(msg->findPointer("buffer-id", &bufferID)); + uint32_t bufferID; + CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID)); Vector *buffers = &mPortBuffers[portIndex]; diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp index 9f9352d..72f2306 100644 --- a/media/libstagefright/OMXClient.cpp +++ b/media/libstagefright/OMXClient.cpp @@ -141,7 +141,7 @@ private: const sp &getOMX(node_id node) const; const sp &getOMX_l(node_id node) const; - static bool IsSoftwareComponent(const char *name); + static bool CanLiveLocally(const char *name); DISALLOW_EVIL_CONSTRUCTORS(MuxOMX); }; @@ -164,7 +164,7 @@ bool MuxOMX::isLocalNode_l(node_id node) const { } // static -bool MuxOMX::IsSoftwareComponent(const char *name) { +bool MuxOMX::CanLiveLocally(const char *name) { return !strncasecmp(name, "OMX.google.", 11); } @@ -197,7 +197,7 @@ status_t MuxOMX::allocateNode( sp omx; - if (IsSoftwareComponent(name)) { + if (CanLiveLocally(name)) { if (mLocalOMX == NULL) { mLocalOMX = new OMX; } @@ -382,7 +382,7 @@ status_t OMXClient::connect() { mOMX = service->getOMX(); CHECK(mOMX.get() != NULL); - if (!mOMX->livesLocally(NULL /* node */, getpid())) { + if (!mOMX->livesLocally(0 /* node */, getpid())) { ALOGI("Using client-side OMX mux."); mOMX = new MuxOMX(mOMX); } diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 9a7f3db..f248861 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -689,7 +689,7 @@ status_t OMXCodec::setVideoPortFormatType( // CHECK_EQ(format.nIndex, index); #if 1 - CODEC_LOGV("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d", + CODEC_LOGV("portIndex: %u, index: %u, eCompressionFormat=%d eColorFormat=%d", portIndex, index, format.eCompressionFormat, format.eColorFormat); #endif @@ -791,7 +791,7 @@ status_t OMXCodec::isColorFormatSupported( portFormat.nIndex = index; if (index >= kMaxColorFormatSupported) { - CODEC_LOGE("More than %ld color formats are supported???", index); + CODEC_LOGE("More than %u color formats are supported???", index); break; } } @@ -1833,7 +1833,7 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { break; } - CODEC_LOGW("setting nBufferCountActual to %lu failed: %d", + CODEC_LOGW("setting nBufferCountActual to %u failed: %d", newBufferCount, err); /* exit condition */ if (extraBuffers == 0) { @@ -1851,7 +1851,7 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { return err; } - CODEC_LOGV("allocating %lu buffers from a native window of size %lu on " + CODEC_LOGV("allocating %u buffers from a native window of size %u on " "output port", def.nBufferCountActual, def.nBufferSize); // Dequeue buffers and send them to OMX @@ -1884,7 +1884,7 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { mPortBuffers[kPortIndexOutput].editItemAt(i).mBuffer = bufferId; - CODEC_LOGV("registered graphic buffer with ID %p (pointer = %p)", + CODEC_LOGV("registered graphic buffer with ID %u (pointer = %p)", bufferId, graphicBuffer.get()); } @@ -1911,7 +1911,7 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { status_t OMXCodec::cancelBufferToNativeWindow(BufferInfo *info) { CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US); - CODEC_LOGV("Calling cancelBuffer on buffer %p", info->mBuffer); + CODEC_LOGV("Calling cancelBuffer on buffer %u", info->mBuffer); int err = mNativeWindow->cancelBuffer( mNativeWindow.get(), info->mMediaBuffer->graphicBuffer().get(), -1); if (err != 0) { @@ -2149,7 +2149,7 @@ void OMXCodec::on_message(const omx_message &msg) { { IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer; - CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer); + CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %u)", buffer); Vector *buffers = &mPortBuffers[kPortIndexInput]; size_t i = 0; @@ -2159,7 +2159,7 @@ void OMXCodec::on_message(const omx_message &msg) { CHECK(i < buffers->size()); if ((*buffers)[i].mStatus != OWNED_BY_COMPONENT) { - ALOGW("We already own input buffer %p, yet received " + ALOGW("We already own input buffer %u, yet received " "an EMPTY_BUFFER_DONE.", buffer); } @@ -2173,7 +2173,7 @@ void OMXCodec::on_message(const omx_message &msg) { } if (mPortStatus[kPortIndexInput] == DISABLING) { - CODEC_LOGV("Port is disabled, freeing buffer %p", buffer); + CODEC_LOGV("Port is disabled, freeing buffer %u", buffer); status_t err = freeBuffer(kPortIndexInput, i); CHECK_EQ(err, (status_t)OK); @@ -2195,7 +2195,7 @@ void OMXCodec::on_message(const omx_message &msg) { IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer; OMX_U32 flags = msg.u.extended_buffer_data.flags; - CODEC_LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx, timestamp: %lld us (%.2f secs))", + CODEC_LOGV("FILL_BUFFER_DONE(buffer: %u, size: %u, flags: 0x%08x, timestamp: %lld us (%.2f secs))", buffer, msg.u.extended_buffer_data.range_length, flags, @@ -2212,14 +2212,14 @@ void OMXCodec::on_message(const omx_message &msg) { BufferInfo *info = &buffers->editItemAt(i); if (info->mStatus != OWNED_BY_COMPONENT) { - ALOGW("We already own output buffer %p, yet received " + ALOGW("We already own output buffer %u, yet received " "a FILL_BUFFER_DONE.", buffer); } info->mStatus = OWNED_BY_US; if (mPortStatus[kPortIndexOutput] == DISABLING) { - CODEC_LOGV("Port is disabled, freeing buffer %p", buffer); + CODEC_LOGV("Port is disabled, freeing buffer %u", buffer); status_t err = freeBuffer(kPortIndexOutput, i); CHECK_EQ(err, (status_t)OK); @@ -2268,7 +2268,7 @@ void OMXCodec::on_message(const omx_message &msg) { buffer->meta_data()->setInt32(kKeyIsUnreadable, true); } - buffer->meta_data()->setPointer( + buffer->meta_data()->setInt32( kKeyBufferID, msg.u.extended_buffer_data.buffer); @@ -2410,7 +2410,7 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { case OMX_EventError: { - CODEC_LOGE("ERROR(0x%08lx, %ld)", data1, data2); + CODEC_LOGE("OMX_EventError(0x%08x, %u)", data1, data2); setState(ERROR); break; @@ -2418,7 +2418,7 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { case OMX_EventPortSettingsChanged: { - CODEC_LOGV("OMX_EventPortSettingsChanged(port=%ld, data2=0x%08lx)", + CODEC_LOGV("OMX_EventPortSettingsChanged(port=%u, data2=0x%08x)", data1, data2); if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) { @@ -2458,7 +2458,7 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { // The scale is in 16.16 format. // scale 1.0 = 0x010000. When there is no // need to change the display, skip it. - ALOGV("Get OMX_IndexConfigScale: 0x%lx/0x%lx", + ALOGV("Get OMX_IndexConfigScale: 0x%x/0x%x", scale.xWidth, scale.xHeight); if (scale.xWidth != 0x010000) { @@ -2492,7 +2492,7 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { default: { - CODEC_LOGV("EVENT(%d, %ld, %ld)", event, data1, data2); + CODEC_LOGV("EVENT(%d, %u, %u)", event, data1, data2); break; } } @@ -2509,7 +2509,7 @@ void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) { case OMX_CommandPortDisable: { OMX_U32 portIndex = data; - CODEC_LOGV("PORT_DISABLED(%ld)", portIndex); + CODEC_LOGV("PORT_DISABLED(%u)", portIndex); CHECK(mState == EXECUTING || mState == RECONFIGURING); CHECK_EQ((int)mPortStatus[portIndex], (int)DISABLING); @@ -2533,7 +2533,7 @@ void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) { status_t err = enablePortAsync(portIndex); if (err != OK) { - CODEC_LOGE("enablePortAsync(%ld) failed (err = %d)", portIndex, err); + CODEC_LOGE("enablePortAsync(%u) failed (err = %d)", portIndex, err); setState(ERROR); } else { err = allocateBuffersOnPort(portIndex); @@ -2554,7 +2554,7 @@ void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) { case OMX_CommandPortEnable: { OMX_U32 portIndex = data; - CODEC_LOGV("PORT_ENABLED(%ld)", portIndex); + CODEC_LOGV("PORT_ENABLED(%u)", portIndex); CHECK(mState == EXECUTING || mState == RECONFIGURING); CHECK_EQ((int)mPortStatus[portIndex], (int)ENABLING); @@ -2575,7 +2575,7 @@ void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) { { OMX_U32 portIndex = data; - CODEC_LOGV("FLUSH_DONE(%ld)", portIndex); + CODEC_LOGV("FLUSH_DONE(%u)", portIndex); CHECK_EQ((int)mPortStatus[portIndex], (int)SHUTTING_DOWN); mPortStatus[portIndex] = ENABLED; @@ -3893,7 +3893,7 @@ status_t OMXCodec::read( return UNKNOWN_ERROR; } - CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6); + CODEC_LOGV("seeking to %" PRId64 " us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6); mSignalledEOS = false; diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h index 31a5077..cd51bbf 100644 --- a/media/libstagefright/include/OMX.h +++ b/media/libstagefright/include/OMX.h @@ -134,10 +134,10 @@ public: OMX_IN OMX_PTR pEventData); OMX_ERRORTYPE OnEmptyBufferDone( - node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer); + node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer); OMX_ERRORTYPE OnFillBufferDone( - node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer); + node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer); void invalidateNodeID(node_id node); diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h index 339179e..3967dc6 100644 --- a/media/libstagefright/include/OMXNodeInstance.h +++ b/media/libstagefright/include/OMXNodeInstance.h @@ -138,12 +138,25 @@ private: OMX::buffer_id mID; }; Vector mActiveBuffers; +#ifdef __LP64__ + Mutex mBufferIDLock; + uint32_t mBufferIDCount; + KeyedVector mBufferIDToBufferHeader; + KeyedVector mBufferHeaderToBufferID; +#endif ~OMXNodeInstance(); void addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id); void removeActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id); void freeActiveBuffers(); + + // For buffer id management + OMX::buffer_id makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader); + OMX_BUFFERHEADERTYPE *findBufferHeader(OMX::buffer_id buffer); + OMX::buffer_id findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader); + void invalidateBufferID(OMX::buffer_id buffer); + status_t useGraphicBuffer2_l( OMX_U32 portIndex, const sp &graphicBuffer, OMX::buffer_id *buffer); diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index b62d5f5..22b12d9 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -287,6 +287,7 @@ status_t OMX::sendCommand( status_t OMX::getParameter( node_id node, OMX_INDEXTYPE index, void *params, size_t size) { + ALOGV("getParameter(%u %#x %p %zd)", node, index, params, size); return findInstance(node)->getParameter( index, params, size); } @@ -294,6 +295,7 @@ status_t OMX::getParameter( status_t OMX::setParameter( node_id node, OMX_INDEXTYPE index, const void *params, size_t size) { + ALOGV("setParameter(%u %#x %p %zd)", node, index, params, size); return findInstance(node)->setParameter( index, params, size); } @@ -445,13 +447,13 @@ OMX_ERRORTYPE OMX::OnEvent( } OMX_ERRORTYPE OMX::OnEmptyBufferDone( - node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { + node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { ALOGV("OnEmptyBufferDone buffer=%p", pBuffer); omx_message msg; msg.type = omx_message::EMPTY_BUFFER_DONE; msg.node = node; - msg.u.buffer_data.buffer = pBuffer; + msg.u.buffer_data.buffer = buffer; findDispatcher(node)->post(msg); @@ -459,13 +461,13 @@ OMX_ERRORTYPE OMX::OnEmptyBufferDone( } OMX_ERRORTYPE OMX::OnFillBufferDone( - node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { + node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { ALOGV("OnFillBufferDone buffer=%p", pBuffer); omx_message msg; msg.type = omx_message::FILL_BUFFER_DONE; msg.node = node; - msg.u.extended_buffer_data.buffer = pBuffer; + msg.u.extended_buffer_data.buffer = buffer; msg.u.extended_buffer_data.range_offset = pBuffer->nOffset; msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; msg.u.extended_buffer_data.flags = pBuffer->nFlags; @@ -479,7 +481,7 @@ OMX_ERRORTYPE OMX::OnFillBufferDone( OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) { // mLock is already held. - node_id node = (node_id)(uintptr_t)++mNodeCounter; + node_id node = (node_id)++mNodeCounter; mNodeIDToInstance.add(node, instance); return node; diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index 0fb38fa..d6ab109 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -92,10 +92,14 @@ OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = { OMXNodeInstance::OMXNodeInstance( OMX *owner, const sp &observer) : mOwner(owner), - mNodeID(NULL), + mNodeID(0), mHandle(NULL), mObserver(observer), - mDying(false) { + mDying(false) +#ifdef __LP64__ + , mBufferIDCount(0) +#endif +{ } OMXNodeInstance::~OMXNodeInstance() { @@ -232,7 +236,7 @@ status_t OMXNodeInstance::freeNode(OMXMaster *master) { } mOwner->invalidateNodeID(mNodeID); - mNodeID = NULL; + mNodeID = 0; ALOGV("OMXNodeInstance going away."); delete this; @@ -270,7 +274,7 @@ status_t OMXNodeInstance::getParameter( Mutex::Autolock autoLock(mLock); OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params); - + ALOGE_IF(err != OMX_ErrorNone, "getParameter(%d) ERROR: %#x", index, err); return StatusFromOMXError(err); } @@ -280,7 +284,7 @@ status_t OMXNodeInstance::setParameter( OMX_ERRORTYPE err = OMX_SetParameter( mHandle, index, const_cast(params)); - + ALOGE_IF(err != OMX_ErrorNone, "setParameter(%d) ERROR: %#x", index, err); return StatusFromOMXError(err); } @@ -482,7 +486,7 @@ status_t OMXNodeInstance::useBuffer( CHECK_EQ(header->pAppPrivate, buffer_meta); - *buffer = header; + *buffer = makeBufferID(header); addActiveBuffer(portIndex, *buffer); @@ -538,7 +542,7 @@ status_t OMXNodeInstance::useGraphicBuffer2_l( CHECK_EQ(header->pBuffer, bufferHandle); CHECK_EQ(header->pAppPrivate, bufferMeta); - *buffer = header; + *buffer = makeBufferID(header); addActiveBuffer(portIndex, *buffer); @@ -602,7 +606,7 @@ status_t OMXNodeInstance::useGraphicBuffer( CHECK_EQ(header->pAppPrivate, bufferMeta); - *buffer = header; + *buffer = makeBufferID(header); addActiveBuffer(portIndex, *buffer); @@ -614,7 +618,7 @@ status_t OMXNodeInstance::updateGraphicBufferInMeta( OMX::buffer_id buffer) { Mutex::Autolock autoLock(mLock); - OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)(buffer); + OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer); VideoDecoderOutputMetaData *metadata = (VideoDecoderOutputMetaData *)(header->pBuffer); BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate); @@ -710,7 +714,7 @@ status_t OMXNodeInstance::allocateBuffer( CHECK_EQ(header->pAppPrivate, buffer_meta); - *buffer = header; + *buffer = makeBufferID(header); *buffer_data = header->pBuffer; addActiveBuffer(portIndex, *buffer); @@ -748,7 +752,7 @@ status_t OMXNodeInstance::allocateBufferWithBackup( CHECK_EQ(header->pAppPrivate, buffer_meta); - *buffer = header; + *buffer = makeBufferID(header); addActiveBuffer(portIndex, *buffer); @@ -766,13 +770,14 @@ status_t OMXNodeInstance::freeBuffer( removeActiveBuffer(portIndex, buffer); - OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; + OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer); BufferMeta *buffer_meta = static_cast(header->pAppPrivate); OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header); delete buffer_meta; buffer_meta = NULL; + invalidateBufferID(buffer); return StatusFromOMXError(err); } @@ -780,7 +785,7 @@ status_t OMXNodeInstance::freeBuffer( status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) { Mutex::Autolock autoLock(mLock); - OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; + OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer); header->nFilledLen = 0; header->nOffset = 0; header->nFlags = 0; @@ -796,7 +801,7 @@ status_t OMXNodeInstance::emptyBuffer( OMX_U32 flags, OMX_TICKS timestamp) { Mutex::Autolock autoLock(mLock); - OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; + OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer); header->nFilledLen = rangeLength; header->nOffset = rangeOffset; header->nFlags = flags; @@ -914,8 +919,7 @@ void OMXNodeInstance::onMessage(const omx_message &msg) { if (msg.type == omx_message::FILL_BUFFER_DONE) { OMX_BUFFERHEADERTYPE *buffer = - static_cast( - msg.u.extended_buffer_data.buffer); + findBufferHeader(msg.u.extended_buffer_data.buffer); BufferMeta *buffer_meta = static_cast(buffer->pAppPrivate); @@ -940,8 +944,7 @@ void OMXNodeInstance::onMessage(const omx_message &msg) { // be very confused. OMX_BUFFERHEADERTYPE *buffer = - static_cast( - msg.u.buffer_data.buffer); + findBufferHeader(msg.u.buffer_data.buffer); bufferSource->codecBufferEmptied(buffer); return; @@ -1001,7 +1004,8 @@ OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone( if (instance->mDying) { return OMX_ErrorNone; } - return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer); + return instance->owner()->OnEmptyBufferDone(instance->nodeID(), + instance->findBufferID(pBuffer), pBuffer); } // static @@ -1013,7 +1017,8 @@ OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone( if (instance->mDying) { return OMX_ErrorNone; } - return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer); + return instance->owner()->OnFillBufferDone(instance->nodeID(), + instance->findBufferID(pBuffer), pBuffer); } void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) { @@ -1048,4 +1053,67 @@ void OMXNodeInstance::freeActiveBuffers() { } } +#ifdef __LP64__ + +OMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) { + if (bufferHeader == NULL) { + return 0; + } + Mutex::Autolock autoLock(mBufferIDLock); + OMX::buffer_id buffer; + do { // handle the very unlikely case of ID overflow + if (++mBufferIDCount == 0) { + ++mBufferIDCount; + } + buffer = (OMX::buffer_id)mBufferIDCount; + } while (mBufferIDToBufferHeader.indexOfKey(buffer) >= 0); + mBufferIDToBufferHeader.add(buffer, bufferHeader); + mBufferHeaderToBufferID.add(bufferHeader, buffer); + return buffer; +} + +OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader(OMX::buffer_id buffer) { + if (buffer == 0) { + return NULL; + } + Mutex::Autolock autoLock(mBufferIDLock); + return mBufferIDToBufferHeader.valueFor(buffer); +} + +OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) { + if (bufferHeader == NULL) { + return 0; + } + Mutex::Autolock autoLock(mBufferIDLock); + return mBufferHeaderToBufferID.valueFor(bufferHeader); +} + +void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer) { + if (buffer == 0) { + return; + } + Mutex::Autolock autoLock(mBufferIDLock); + mBufferHeaderToBufferID.removeItem(mBufferIDToBufferHeader.valueFor(buffer)); + mBufferIDToBufferHeader.removeItem(buffer); +} + +#else + +OMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) { + return (OMX::buffer_id)bufferHeader; +} + +OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader(OMX::buffer_id buffer) { + return (OMX_BUFFERHEADERTYPE *)buffer; +} + +OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) { + return (OMX::buffer_id)bufferHeader; +} + +void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer __unused) { +} + +#endif + } // namespace android -- cgit v1.1 From f87e30fe71752dc431d8e8d5682c38271c03265a Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 13 May 2014 18:37:59 -0700 Subject: Send 64 bit OMX codec handling to 32 bit MediaServer This is a temporary fix for 64 bit OMX handling until 64 bit codecs are more robust. Bug: 13938273 Change-Id: Ifc79e360f9606f6c909b859d322b7dd5d416b26b Signed-off-by: Andy Hung --- media/libstagefright/ACodec.cpp | 4 ++++ media/libstagefright/OMXClient.cpp | 12 ++++++++++++ media/libstagefright/OMXCodec.cpp | 6 ++++++ 3 files changed, 22 insertions(+) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 0fe7ff2..4f66402 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -17,6 +17,10 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "ACodec" +#ifdef __LP64__ +#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS +#endif + #include #include diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp index 72f2306..aca21cf 100644 --- a/media/libstagefright/OMXClient.cpp +++ b/media/libstagefright/OMXClient.cpp @@ -16,6 +16,11 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "OMXClient" + +#ifdef __LP64__ +#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS +#endif + #include #include @@ -165,7 +170,14 @@ bool MuxOMX::isLocalNode_l(node_id node) const { // static bool MuxOMX::CanLiveLocally(const char *name) { +#ifdef __LP64__ + (void)name; // disable unused parameter warning + // 64 bit processes always run OMX remote on MediaServer + return false; +#else + // 32 bit processes run only OMX.google.* components locally return !strncasecmp(name, "OMX.google.", 11); +#endif } const sp &MuxOMX::getOMX(node_id node) const { diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index f248861..c028dbf 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -18,6 +18,11 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "OMXCodec" + +#ifdef __LP64__ +#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS +#endif + #include #include "include/AACEncoder.h" @@ -130,6 +135,7 @@ private: template static void InitOMXParams(T *params) { + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(OMX_PTR) == 4); // check OMX_PTR is 4 bytes. params->nSize = sizeof(T); params->nVersion.s.nVersionMajor = 1; params->nVersion.s.nVersionMinor = 0; -- cgit v1.1 From 3305b99ec3804c740aecd2ab6d1edd5c6137b7c6 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Wed, 14 May 2014 18:39:25 -0700 Subject: Hook up event handling in NDK MediaDrm API Change-Id: I48ac1d3ca5405c5909454c7a553917b31b9a50e5 --- media/ndk/NdkMediaDrm.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp index 5e50418..4967f42 100644 --- a/media/ndk/NdkMediaDrm.cpp +++ b/media/ndk/NdkMediaDrm.cpp @@ -35,10 +35,20 @@ using namespace android; typedef Vector idvec_t; +struct DrmListener: virtual public BnDrmClient +{ +private: + AMediaDrm *mObj; + AMediaDrmEventListener mListener; + +public: + DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), mListener(listener) {} + void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj); +}; + struct AMediaDrm { sp mDrm; sp mDrmClient; - AMediaDrmEventListener mListener; List mIds; KeyedVector mQueryResults; Vector mKeyRequest; @@ -47,8 +57,57 @@ struct AMediaDrm { String8 mPropertyString; Vector mPropertyByteArray; List > mSecureStops; + sp mListener; }; +void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) { + if (!mListener) { + return; + } + + AMediaDrmSessionId sessionId = {NULL, 0}; + int32_t sessionIdSize = obj->readInt32(); + if (sessionIdSize) { + uint8_t *sessionIdData = new uint8_t[sessionIdSize]; + sessionId.ptr = sessionIdData; + sessionId.length = sessionIdSize; + obj->read(sessionIdData, sessionId.length); + } + + int32_t dataSize = obj->readInt32(); + uint8_t *data = NULL; + if (dataSize) { + data = new uint8_t[dataSize]; + obj->read(data, dataSize); + } + + // translate DrmPlugin event types into their NDK equivalents + AMediaDrmEventType ndkEventType; + switch(eventType) { + case DrmPlugin::kDrmPluginEventProvisionRequired: + ndkEventType = EVENT_PROVISION_REQUIRED; + break; + case DrmPlugin::kDrmPluginEventKeyNeeded: + ndkEventType = EVENT_KEY_REQUIRED; + break; + case DrmPlugin::kDrmPluginEventKeyExpired: + ndkEventType = EVENT_KEY_EXPIRED; + break; + case DrmPlugin::kDrmPluginEventVendorDefined: + ndkEventType = EVENT_VENDOR_DEFINED; + break; + default: + ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType); + return; + } + + (*mListener)(mObj, sessionId, ndkEventType, extra, data, dataSize); + + delete [] sessionId.ptr; + delete [] data; +} + + extern "C" { static mediadrm_status_t translateStatus(status_t status) { @@ -156,11 +215,15 @@ void AMediaDrm_release(AMediaDrm *mObj) { delete mObj; } -#if 0 -void AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) { - mObj->mListener = listener; +EXPORT +mediadrm_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) { + if (!mObj || mObj->mDrm == NULL) { + return MEDIADRM_INVALID_OBJECT_ERROR; + } + mObj->mListener = new DrmListener(mObj, listener); + mObj->mDrm->setListener(mObj->mListener); + return MEDIADRM_OK; } -#endif static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List::iterator &iter) { -- cgit v1.1 From 47aea1f7c58f5302b16822f9e7e1763f2af04ef5 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 15 May 2014 10:26:08 -0700 Subject: ACodec: remove PTS log spam Bug: 14976517 Bug: 11784827 Change-Id: Ibc1bbd80e7aac30b0f8f1e9ca2be1bb3e5e2ebbb --- media/libstagefright/ACodec.cpp | 4 +--- media/libstagefright/MediaCodec.cpp | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 4f66402..2e8e412 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -3681,7 +3681,7 @@ void ACodec::BaseState::onOutputBufferDrained(const sp &msg) { // API 20. Perhaps check for target SDK version. #if 0 if (info->mData->meta()->findInt64("timeUs", ×tampNs)) { - ALOGI("using buffer PTS of %" PRId64, timestampNs); + ALOGV("using buffer PTS of %" PRId64, timestampNs); timestampNs *= 1000; } #endif @@ -3691,8 +3691,6 @@ void ACodec::BaseState::onOutputBufferDrained(const sp &msg) { err = native_window_set_buffers_timestamp(mCodec->mNativeWindow.get(), timestampNs); if (err != OK) { ALOGW("failed to set buffer timestamp: %d", err); - } else { - ALOGI("set PTS to %" PRId64, timestampNs); } if ((err = mCodec->mNativeWindow->queueBuffer( diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index d8a8380..b9c5904 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -1728,7 +1728,7 @@ status_t MediaCodec::onReleaseOutputBuffer(const sp &msg) { // API 20. Perhaps check for target SDK version. #if 0 if (info->mData->meta()->findInt64("timeUs", ×tampNs)) { - ALOGI("using buffer PTS of %" PRId64, timestampNs); + ALOGV("using buffer PTS of %" PRId64, timestampNs); timestampNs *= 1000; } #endif -- cgit v1.1 From e419d7cd5c62b4b5866a45d59c5770bb470193c1 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 15 May 2014 14:17:25 -0700 Subject: Unify error/status codes Change-Id: Ib90cc2f2adc07ff146256931c92c0ec4becb86f5 --- media/ndk/NdkMediaCodec.cpp | 84 +++++++++++++---------- media/ndk/NdkMediaCrypto.cpp | 6 +- media/ndk/NdkMediaDrm.cpp | 145 ++++++++++++++++++++-------------------- media/ndk/NdkMediaExtractor.cpp | 41 ++++++------ media/ndk/NdkMediaFormat.cpp | 4 +- media/ndk/NdkMediaMuxer.cpp | 20 +++--- 6 files changed, 155 insertions(+), 145 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index a7c06d5..9e2aa67 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -36,14 +36,14 @@ using namespace android; -static int translate_error(status_t err) { +static media_status_t translate_error(status_t err) { if (err == OK) { - return OK; + return AMEDIA_OK; } else if (err == -EAGAIN) { - return AMEDIACODEC_INFO_TRY_AGAIN_LATER; + return (media_status_t) AMEDIACODEC_INFO_TRY_AGAIN_LATER; } ALOGE("sf error code: %d", err); - return AMEDIAERROR_GENERIC; + return AMEDIA_ERROR_UNKNOWN; } enum { @@ -175,7 +175,7 @@ AMediaCodec* AMediaCodec_createEncoderByType(const char *name) { } EXPORT -int AMediaCodec_delete(AMediaCodec *mData) { +media_status_t AMediaCodec_delete(AMediaCodec *mData) { if (mData->mCodec != NULL) { mData->mCodec->release(); mData->mCodec.clear(); @@ -187,11 +187,11 @@ int AMediaCodec_delete(AMediaCodec *mData) { mData->mLooper.clear(); } delete mData; - return OK; + return AMEDIA_OK; } EXPORT -int AMediaCodec_configure( +media_status_t AMediaCodec_configure( AMediaCodec *mData, const AMediaFormat* format, ANativeWindow* window, @@ -210,7 +210,7 @@ int AMediaCodec_configure( } EXPORT -int AMediaCodec_start(AMediaCodec *mData) { +media_status_t AMediaCodec_start(AMediaCodec *mData) { status_t ret = mData->mCodec->start(); if (ret != OK) { return translate_error(ret); @@ -218,12 +218,12 @@ int AMediaCodec_start(AMediaCodec *mData) { mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler->id()); mData->mActivityNotification->setInt32("generation", mData->mGeneration); requestActivityNotification(mData); - return OK; + return AMEDIA_OK; } EXPORT -int AMediaCodec_stop(AMediaCodec *mData) { - int ret = translate_error(mData->mCodec->stop()); +media_status_t AMediaCodec_stop(AMediaCodec *mData) { + media_status_t ret = translate_error(mData->mCodec->stop()); sp msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler->id()); sp response; @@ -234,7 +234,7 @@ int AMediaCodec_stop(AMediaCodec *mData) { } EXPORT -int AMediaCodec_flush(AMediaCodec *mData) { +media_status_t AMediaCodec_flush(AMediaCodec *mData) { return translate_error(mData->mCodec->flush()); } @@ -286,7 +286,7 @@ uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out } EXPORT -int AMediaCodec_queueInputBuffer(AMediaCodec *mData, +media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { AString errorMsg; @@ -332,7 +332,7 @@ AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { } EXPORT -int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) { +media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) { if (render) { return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx)); } else { @@ -341,10 +341,10 @@ int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) } EXPORT -int AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) { +media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) { mData->mCallback = callback; mData->mCallbackUserData = userdata; - return OK; + return AMEDIA_OK; } typedef struct AMediaCodecCryptoInfo { @@ -357,7 +357,7 @@ typedef struct AMediaCodecCryptoInfo { } AMediaCodecCryptoInfo; EXPORT -int AMediaCodec_queueSecureInputBuffer( +media_status_t AMediaCodec_queueSecureInputBuffer( AMediaCodec* codec, size_t idx, off_t offset, @@ -424,9 +424,9 @@ AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( EXPORT -int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) { +media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) { free(info); - return OK; + return AMEDIA_OK; } EXPORT @@ -435,47 +435,59 @@ size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) { } EXPORT -int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) { - if (!dst || !ci) { - return AMEDIAERROR_UNSUPPORTED; +media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) { + if (!ci) { + return AMEDIA_ERROR_INVALID_OBJECT; + } + if (!dst) { + return AMEDIA_ERROR_INVALID_PARAMETER; } memcpy(dst, ci->key, 16); - return OK; + return AMEDIA_OK; } EXPORT -int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) { - if (!dst || !ci) { - return AMEDIAERROR_UNSUPPORTED; +media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) { + if (!ci) { + return AMEDIA_ERROR_INVALID_OBJECT; + } + if (!dst) { + return AMEDIA_ERROR_INVALID_PARAMETER; } memcpy(dst, ci->iv, 16); - return OK; + return AMEDIA_OK; } EXPORT uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) { if (!ci) { - return AMEDIAERROR_UNSUPPORTED; + return AMEDIA_ERROR_INVALID_OBJECT; } return ci->mode; } EXPORT -int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { - if (!dst || !ci) { - return AMEDIAERROR_UNSUPPORTED; +media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { + if (!ci) { + return AMEDIA_ERROR_INVALID_OBJECT; + } + if (!dst) { + return AMEDIA_ERROR_INVALID_PARAMETER; } memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples); - return OK; + return AMEDIA_OK; } EXPORT -int AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { - if (!dst || !ci) { - return AMEDIAERROR_UNSUPPORTED; +media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { + if (!ci) { + return AMEDIA_ERROR_INVALID_OBJECT; + } + if (!dst) { + return AMEDIA_ERROR_INVALID_PARAMETER; } memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples); - return OK; + return AMEDIA_OK; } } // extern "C" diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp index c686273..cbadea5 100644 --- a/media/ndk/NdkMediaCrypto.cpp +++ b/media/ndk/NdkMediaCrypto.cpp @@ -35,12 +35,12 @@ using namespace android; -static int translate_error(status_t err) { +static media_status_t translate_error(status_t err) { if (err == OK) { - return OK; + return AMEDIA_OK; } ALOGE("sf error code: %d", err); - return -1000; + return AMEDIA_ERROR_UNKNOWN; } diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp index 5e50418..2f068be 100644 --- a/media/ndk/NdkMediaDrm.cpp +++ b/media/ndk/NdkMediaDrm.cpp @@ -51,38 +51,37 @@ struct AMediaDrm { extern "C" { -static mediadrm_status_t translateStatus(status_t status) { - mediadrm_status_t result = MEDIADRM_UNKNOWN_ERROR; +static media_status_t translateStatus(status_t status) { + media_status_t result = AMEDIA_ERROR_UNKNOWN; switch (status) { case OK: - result = MEDIADRM_OK; + result = AMEDIA_OK; break; case android::ERROR_DRM_NOT_PROVISIONED: - result = MEDIADRM_NOT_PROVISIONED_ERROR; + result = AMEDIA_DRM_NOT_PROVISIONED; break; case android::ERROR_DRM_RESOURCE_BUSY: - result = MEDIADRM_RESOURCE_BUSY_ERROR; + result = AMEDIA_DRM_RESOURCE_BUSY; break; case android::ERROR_DRM_DEVICE_REVOKED: - result = MEDIADRM_DEVICE_REVOKED_ERROR; + result = AMEDIA_DRM_DEVICE_REVOKED; break; case android::ERROR_DRM_CANNOT_HANDLE: - result = MEDIADRM_INVALID_PARAMETER_ERROR; + result = AMEDIA_ERROR_INVALID_PARAMETER; break; case android::ERROR_DRM_TAMPER_DETECTED: - result = MEDIADRM_TAMPER_DETECTED_ERROR; + result = AMEDIA_DRM_TAMPER_DETECTED; break; case android::ERROR_DRM_SESSION_NOT_OPENED: - result = MEDIADRM_SESSION_NOT_OPENED_ERROR; + result = AMEDIA_DRM_SESSION_NOT_OPENED; break; case android::ERROR_DRM_NO_LICENSE: - result = MEDIADRM_NEED_KEY_ERROR; + result = AMEDIA_DRM_NEED_KEY; break; case android::ERROR_DRM_LICENSE_EXPIRED: - result = MEDIADRM_LICENSE_EXPIRED_ERROR; + result = AMEDIA_DRM_LICENSE_EXPIRED; break; default: - result = MEDIADRM_UNKNOWN_ERROR; break; } return result; @@ -174,9 +173,9 @@ static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List: } EXPORT -mediadrm_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) { +media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } Vector session; status_t status = mObj->mDrm->openSession(session); @@ -186,40 +185,40 @@ mediadrm_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &ses sessionId.ptr = iter->array(); sessionId.length = iter->size(); } - return MEDIADRM_OK; + return AMEDIA_OK; } EXPORT -mediadrm_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) { +media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } List::iterator iter; if (!findId(mObj, sessionId, iter)) { - return MEDIADRM_SESSION_NOT_OPENED_ERROR; + return AMEDIA_DRM_SESSION_NOT_OPENED; } mObj->mDrm->closeSession(*iter); mObj->mIds.erase(iter); - return MEDIADRM_OK; + return AMEDIA_OK; } EXPORT -mediadrm_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope, +media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope, const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType, const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters, const uint8_t *&keyRequest, size_t &keyRequestSize) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } if (!mimeType) { - return MEDIADRM_INVALID_PARAMETER_ERROR; + return AMEDIA_ERROR_INVALID_PARAMETER; } List::iterator iter; if (!findId(mObj, scope, iter)) { - return MEDIADRM_SESSION_NOT_OPENED_ERROR; + return AMEDIA_DRM_SESSION_NOT_OPENED; } Vector mdInit; @@ -236,7 +235,7 @@ mediadrm_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope mdKeyType = DrmPlugin::kKeyType_Release; break; default: - return MEDIADRM_INVALID_PARAMETER_ERROR; + return AMEDIA_ERROR_INVALID_PARAMETER; } KeyedVector mdOptionalParameters; for (size_t i = 0; i < numOptionalParameters; i++) { @@ -252,23 +251,23 @@ mediadrm_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope keyRequest = mObj->mKeyRequest.array(); keyRequestSize = mObj->mKeyRequest.size(); } - return MEDIADRM_OK; + return AMEDIA_OK; } EXPORT -mediadrm_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope, +media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope, const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } if (!response || !responseSize) { - return MEDIADRM_INVALID_PARAMETER_ERROR; + return AMEDIA_ERROR_INVALID_PARAMETER; } List::iterator iter; if (!findId(mObj, scope, iter)) { - return MEDIADRM_SESSION_NOT_OPENED_ERROR; + return AMEDIA_DRM_SESSION_NOT_OPENED; } Vector mdResponse; mdResponse.appendArray(response, responseSize); @@ -284,19 +283,19 @@ mediadrm_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmS keySetId.ptr = NULL; keySetId.length = 0; } - return MEDIADRM_OK; + return AMEDIA_OK; } EXPORT -mediadrm_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, +media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, const AMediaDrmKeySetId &keySetId) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } List::iterator iter; if (!findId(mObj, sessionId, iter)) { - return MEDIADRM_SESSION_NOT_OPENED_ERROR; + return AMEDIA_DRM_SESSION_NOT_OPENED; } Vector keySet; keySet.appendArray(keySetId.ptr, keySetId.length); @@ -304,9 +303,9 @@ mediadrm_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionI } EXPORT -mediadrm_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) { +media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } List::iterator iter; status_t status; @@ -322,15 +321,15 @@ mediadrm_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId } EXPORT -mediadrm_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, +media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } List::iterator iter; if (!findId(mObj, sessionId, iter)) { - return MEDIADRM_SESSION_NOT_OPENED_ERROR; + return AMEDIA_DRM_SESSION_NOT_OPENED; } status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults); @@ -341,7 +340,7 @@ mediadrm_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessi if (mObj->mQueryResults.size() > numPairs) { numPairs = mObj->mQueryResults.size(); - return MEDIADRM_SHORT_BUFFER; + return AMEDIA_DRM_SHORT_BUFFER; } for (size_t i = 0; i < mObj->mQueryResults.size(); i++) { @@ -349,17 +348,17 @@ mediadrm_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessi keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string(); } numPairs = mObj->mQueryResults.size(); - return MEDIADRM_OK; + return AMEDIA_OK; } EXPORT -mediadrm_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest, +media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest, size_t &provisionRequestSize, const char *&serverUrl) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } if (!provisionRequestSize || !serverUrl) { - return MEDIADRM_INVALID_PARAMETER_ERROR; + return AMEDIA_ERROR_INVALID_PARAMETER; } status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""), @@ -371,17 +370,17 @@ mediadrm_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t * provisionRequestSize = mObj->mProvisionRequest.size(); serverUrl = mObj->mProvisionUrl.string(); } - return MEDIADRM_OK; + return AMEDIA_OK; } EXPORT -mediadrm_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj, +media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj, const uint8_t *response, size_t responseSize) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } if (!response || !responseSize) { - return MEDIADRM_INVALID_PARAMETER_ERROR; + return AMEDIA_ERROR_INVALID_PARAMETER; } Vector mdResponse; @@ -392,11 +391,11 @@ mediadrm_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj, } EXPORT -mediadrm_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, +media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, AMediaDrmSecureStop *secureStops, size_t &numSecureStops) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops); if (status != OK) { @@ -404,7 +403,7 @@ mediadrm_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, return translateStatus(status); } if (numSecureStops < mObj->mSecureStops.size()) { - return MEDIADRM_SHORT_BUFFER; + return AMEDIA_DRM_SHORT_BUFFER; } List >::iterator iter = mObj->mSecureStops.begin(); size_t i = 0; @@ -415,15 +414,15 @@ mediadrm_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, ++i; } numSecureStops = mObj->mSecureStops.size(); - return MEDIADRM_OK; + return AMEDIA_OK; } EXPORT -mediadrm_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj, +media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj, const AMediaDrmSecureStop &ssRelease) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } Vector release; @@ -433,11 +432,11 @@ mediadrm_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj, EXPORT -mediadrm_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName, +media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName, const char *&propertyValue) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } status_t status = mObj->mDrm->getPropertyString(String8(propertyName), @@ -452,10 +451,10 @@ mediadrm_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *prope } EXPORT -mediadrm_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj, +media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj, const char *propertyName, AMediaDrmByteArray &propertyValue) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName), @@ -472,10 +471,10 @@ mediadrm_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj, } EXPORT -mediadrm_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj, +media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj, const char *propertyName, const char *value) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName), @@ -483,7 +482,7 @@ mediadrm_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj, } EXPORT -mediadrm_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj, +media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj, const char *propertyName, const uint8_t *value, size_t valueSize) { Vector byteArray; @@ -494,17 +493,17 @@ mediadrm_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj, } -static mediadrm_status_t encrypt_decrypt_common(AMediaDrm *mObj, +static media_status_t encrypt_decrypt_common(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } List::iterator iter; if (!findId(mObj, sessionId, iter)) { - return MEDIADRM_SESSION_NOT_OPENED_ERROR; + return AMEDIA_DRM_SESSION_NOT_OPENED; } status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm)); @@ -536,7 +535,7 @@ static mediadrm_status_t encrypt_decrypt_common(AMediaDrm *mObj, } EXPORT -mediadrm_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, +media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, const uint8_t *input, uint8_t *output, size_t dataSize) { return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv, @@ -544,7 +543,7 @@ mediadrm_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &s } EXPORT -mediadrm_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, +media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, const uint8_t *input, uint8_t *output, size_t dataSize) { return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv, @@ -552,16 +551,16 @@ mediadrm_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &s } EXPORT -mediadrm_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, +media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize, uint8_t *signature, size_t *signatureSize) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } List::iterator iter; if (!findId(mObj, sessionId, iter)) { - return MEDIADRM_SESSION_NOT_OPENED_ERROR; + return AMEDIA_DRM_SESSION_NOT_OPENED; } status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm)); @@ -579,7 +578,7 @@ mediadrm_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sess Vector signatureVec; status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec); if (signatureVec.size() > *signatureSize) { - return MEDIADRM_SHORT_BUFFER; + return AMEDIA_DRM_SHORT_BUFFER; } if (status == OK) { memcpy(signature, signatureVec.array(), signatureVec.size()); @@ -588,16 +587,16 @@ mediadrm_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sess } EXPORT -mediadrm_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, +media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize, const uint8_t *signature, size_t signatureSize) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } List::iterator iter; if (!findId(mObj, sessionId, iter)) { - return MEDIADRM_SESSION_NOT_OPENED_ERROR; + return AMEDIA_DRM_SESSION_NOT_OPENED; } status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm)); @@ -618,7 +617,7 @@ mediadrm_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &se bool match; status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match); if (status == OK) { - return match ? MEDIADRM_OK : MEDIADRM_VERIFY_FAILED; + return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED; } return translateStatus(status); } diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp index e23adf3..563358f 100644 --- a/media/ndk/NdkMediaExtractor.cpp +++ b/media/ndk/NdkMediaExtractor.cpp @@ -38,12 +38,12 @@ using namespace android; -static int translate_error(status_t err) { +static media_status_t translate_error(status_t err) { if (err == OK) { - return OK; + return AMEDIA_OK; } ALOGE("sf error code: %d", err); - return AMEDIAERROR_GENERIC; + return AMEDIA_ERROR_UNKNOWN; } struct AMediaExtractor { @@ -63,21 +63,20 @@ AMediaExtractor* AMediaExtractor_new() { } EXPORT -int AMediaExtractor_delete(AMediaExtractor *mData) { +media_status_t AMediaExtractor_delete(AMediaExtractor *mData) { ALOGV("dtor"); delete mData; - return OK; + return AMEDIA_OK; } EXPORT -int AMediaExtractor_setDataSourceFd(AMediaExtractor *mData, int fd, off64_t offset, off64_t length) { +media_status_t AMediaExtractor_setDataSourceFd(AMediaExtractor *mData, int fd, off64_t offset, off64_t length) { ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); - mData->mImpl->setDataSource(fd, offset, length); - return 0; + return translate_error(mData->mImpl->setDataSource(fd, offset, length)); } EXPORT -int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) { +media_status_t AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) { ALOGV("setDataSource(%s)", location); // TODO: add header support @@ -86,14 +85,14 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) if (env == NULL) { ALOGE("setDataSource(path) must be called from Java thread"); env->ExceptionClear(); - return AMEDIAERROR_UNSUPPORTED; + return AMEDIA_ERROR_UNSUPPORTED; } jclass mediahttpclass = env->FindClass("android/media/MediaHTTPService"); if (mediahttpclass == NULL) { ALOGE("can't find MediaHttpService"); env->ExceptionClear(); - return AMEDIAERROR_UNSUPPORTED; + return AMEDIA_ERROR_UNSUPPORTED; } jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass, @@ -101,7 +100,7 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) if (mediaHttpCreateMethod == NULL) { ALOGE("can't find method"); env->ExceptionClear(); - return AMEDIAERROR_UNSUPPORTED; + return AMEDIA_ERROR_UNSUPPORTED; } jstring jloc = env->NewStringUTF(location); @@ -115,13 +114,13 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) httpService = interface_cast(binder); } - mData->mImpl->setDataSource(httpService, location, NULL); + status_t err = mData->mImpl->setDataSource(httpService, location, NULL); env->ExceptionClear(); - return OK; + return translate_error(err); } EXPORT -int AMediaExtractor_getTrackCount(AMediaExtractor *mData) { +size_t AMediaExtractor_getTrackCount(AMediaExtractor *mData) { return mData->mImpl->countTracks(); } @@ -133,13 +132,13 @@ AMediaFormat* AMediaExtractor_getTrackFormat(AMediaExtractor *mData, size_t idx) } EXPORT -int AMediaExtractor_selectTrack(AMediaExtractor *mData, size_t idx) { +media_status_t AMediaExtractor_selectTrack(AMediaExtractor *mData, size_t idx) { ALOGV("selectTrack(%z)", idx); return translate_error(mData->mImpl->selectTrack(idx)); } EXPORT -int AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx) { +media_status_t AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx) { ALOGV("unselectTrack(%z)", idx); return translate_error(mData->mImpl->unselectTrack(idx)); } @@ -151,7 +150,7 @@ bool AMediaExtractor_advance(AMediaExtractor *mData) { } EXPORT -int AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size_t capacity) { +ssize_t AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size_t capacity) { //ALOGV("readSampleData"); sp tmp = new ABuffer(buffer, capacity); if (mData->mImpl->readSampleData(tmp) == OK) { @@ -161,7 +160,7 @@ int AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size } EXPORT -int AMediaExtractor_getSampleFlags(AMediaExtractor *mData) { +uint32_t AMediaExtractor_getSampleFlags(AMediaExtractor *mData) { int sampleFlags = 0; sp meta; status_t err = mData->mImpl->getSampleMeta(&meta); @@ -170,14 +169,14 @@ int AMediaExtractor_getSampleFlags(AMediaExtractor *mData) { } int32_t val; if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) { - sampleFlags |= NuMediaExtractor::SAMPLE_FLAG_SYNC; + sampleFlags |= AMEDIAEXTRACTOR_SAMPLE_FLAG_SYNC; } uint32_t type; const void *data; size_t size; if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) { - sampleFlags |= NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED; + sampleFlags |= AMEDIAEXTRACTOR_SAMPLE_FLAG_ENCRYPTED; } return sampleFlags; } diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp index e1d8c95..77018ec 100644 --- a/media/ndk/NdkMediaFormat.cpp +++ b/media/ndk/NdkMediaFormat.cpp @@ -64,10 +64,10 @@ AMediaFormat *AMediaFormat_new() { } EXPORT -int AMediaFormat_delete(AMediaFormat *mData) { +media_status_t AMediaFormat_delete(AMediaFormat *mData) { ALOGV("dtor"); delete mData; - return OK; + return AMEDIA_OK; } diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp index aa78740..19b9fc4 100644 --- a/media/ndk/NdkMediaMuxer.cpp +++ b/media/ndk/NdkMediaMuxer.cpp @@ -37,12 +37,12 @@ using namespace android; -static int translate_error(status_t err) { +static media_status_t translate_error(status_t err) { if (err == OK) { - return OK; + return AMEDIA_OK; } ALOGE("sf error code: %d", err); - return -1000; + return AMEDIA_ERROR_UNKNOWN; } struct AMediaMuxer { @@ -61,19 +61,19 @@ AMediaMuxer* AMediaMuxer_new(int fd, OutputFormat format) { } EXPORT -int AMediaMuxer_delete(AMediaMuxer *muxer) { +media_status_t AMediaMuxer_delete(AMediaMuxer *muxer) { ALOGV("dtor"); delete muxer; - return OK; + return AMEDIA_OK; } EXPORT -int AMediaMuxer_setLocation(AMediaMuxer *muxer, float latitude, float longtitude) { +media_status_t AMediaMuxer_setLocation(AMediaMuxer *muxer, float latitude, float longtitude) { return translate_error(muxer->mImpl->setLocation(latitude * 10000, longtitude * 10000)); } EXPORT -int AMediaMuxer_setOrientationHint(AMediaMuxer *muxer, int degrees) { +media_status_t AMediaMuxer_setOrientationHint(AMediaMuxer *muxer, int degrees) { return translate_error(muxer->mImpl->setOrientationHint(degrees)); } @@ -85,17 +85,17 @@ ssize_t AMediaMuxer_addTrack(AMediaMuxer *muxer, const AMediaFormat *format) { } EXPORT -int AMediaMuxer_start(AMediaMuxer *muxer) { +media_status_t AMediaMuxer_start(AMediaMuxer *muxer) { return translate_error(muxer->mImpl->start()); } EXPORT -int AMediaMuxer_stop(AMediaMuxer *muxer) { +media_status_t AMediaMuxer_stop(AMediaMuxer *muxer) { return translate_error(muxer->mImpl->stop()); } EXPORT -int AMediaMuxer_writeSampleData(AMediaMuxer *muxer, +media_status_t AMediaMuxer_writeSampleData(AMediaMuxer *muxer, size_t trackIdx, const uint8_t *data, const AMediaCodecBufferInfo &info) { sp buf = new ABuffer((void*)(data + info.offset), info.size); return translate_error( -- cgit v1.1 From 7c96d53a65085f42ac2b6d416cbc16fd36ed72ff Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 15 May 2014 15:26:14 -0700 Subject: Fix build. Change-Id: I2b0a3049c81b99ba233d5945e16dcddd975aa4f9 --- media/ndk/NdkMediaDrm.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp index 3638613..f982275 100644 --- a/media/ndk/NdkMediaDrm.cpp +++ b/media/ndk/NdkMediaDrm.cpp @@ -215,13 +215,13 @@ void AMediaDrm_release(AMediaDrm *mObj) { } EXPORT -mediadrm_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) { +media_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) { if (!mObj || mObj->mDrm == NULL) { - return MEDIADRM_INVALID_OBJECT_ERROR; + return AMEDIA_ERROR_INVALID_OBJECT; } mObj->mListener = new DrmListener(mObj, listener); mObj->mDrm->setListener(mObj->mListener); - return MEDIADRM_OK; + return AMEDIA_OK; } -- cgit v1.1 From e541269be94f3a1072932d51537905b120ef4733 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Fri, 16 May 2014 11:25:07 -0700 Subject: Use new channel count functions for audio masks Change-Id: Ia658ab4b6320d19fdb50f123c930918724ff0ef3 Signed-off-by: Andy Hung --- media/libeffects/downmix/EffectDownmix.c | 7 ++++--- media/libeffects/preprocessing/PreProcessing.cpp | 6 +++--- media/libeffects/visualizer/EffectVisualizer.cpp | 3 ++- media/libmedia/AudioRecord.cpp | 5 +++-- media/libmedia/AudioTrack.cpp | 2 +- media/libnbaio/AudioStreamInSource.cpp | 3 ++- media/libnbaio/AudioStreamOutSink.cpp | 3 ++- 7 files changed, 17 insertions(+), 12 deletions(-) (limited to 'media') diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c index 661fde9..6686f27 100644 --- a/media/libeffects/downmix/EffectDownmix.c +++ b/media/libeffects/downmix/EffectDownmix.c @@ -118,7 +118,7 @@ void Downmix_testIndexComputation(uint32_t mask) { hasBacks = true; } - const int numChan = popcount(mask); + const int numChan = audio_channel_count_from_out_mask(mask); const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER); const bool hasLFE = ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY); @@ -629,7 +629,8 @@ int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bo ALOGE("Downmix_Configure error: input channel mask can't be 0"); return -EINVAL; } - pDownmixer->input_channel_count = popcount(pConfig->inputCfg.channels); + pDownmixer->input_channel_count = + audio_channel_count_from_out_mask(pConfig->inputCfg.channels); } Downmix_Reset(pDownmixer, init); @@ -997,7 +998,7 @@ bool Downmix_foldGeneric( hasBacks = true; } - const int numChan = popcount(mask); + const int numChan = audio_channel_count_from_out_mask(mask); const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER); const bool hasLFE = ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY); diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp index a96a703..cf98f56 100644 --- a/media/libeffects/preprocessing/PreProcessing.cpp +++ b/media/libeffects/preprocessing/PreProcessing.cpp @@ -879,8 +879,8 @@ int Session_ReleaseEffect(preproc_session_t *session, int Session_SetConfig(preproc_session_t *session, effect_config_t *config) { uint32_t sr; - uint32_t inCnl = popcount(config->inputCfg.channels); - uint32_t outCnl = popcount(config->outputCfg.channels); + uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels); + uint32_t outCnl = audio_channel_count_from_out_mask(config->outputCfg.channels); if (config->inputCfg.samplingRate != config->outputCfg.samplingRate || config->inputCfg.format != config->outputCfg.format || @@ -1035,7 +1035,7 @@ int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) { return -EINVAL; } - uint32_t inCnl = popcount(config->inputCfg.channels); + uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels); int status = session->apm->set_num_reverse_channels(inCnl); if (status < 0) { return -EINVAL; diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp index 47cab62..e5089da 100644 --- a/media/libeffects/visualizer/EffectVisualizer.cpp +++ b/media/libeffects/visualizer/EffectVisualizer.cpp @@ -207,7 +207,8 @@ int Visualizer_init(VisualizerContext *pContext) pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED; // measurement initialization - pContext->mChannelCount = popcount(pContext->mConfig.inputCfg.channels); + pContext->mChannelCount = + audio_channel_count_from_out_mask(pContext->mConfig.inputCfg.channels); pContext->mMeasurementMode = MEASUREMENT_MODE_NONE; pContext->mMeasurementWindowSizeInBuffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS; pContext->mMeasurementBufferIdx = 0; diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 97ab8f8..1c808d0 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -51,7 +51,8 @@ status_t AudioRecord::getMinFrameCount( // We double the size of input buffer for ping pong use of record buffer. // Assumes audio_is_linear_pcm(format) - if ((*frameCount = (size * 2) / (popcount(channelMask) * audio_bytes_per_sample(format))) == 0) { + if ((*frameCount = (size * 2) / (audio_channel_count_from_in_mask(channelMask) * + audio_bytes_per_sample(format))) == 0) { ALOGE("Unsupported configuration: sampleRate %u, format %#x, channelMask %#x", sampleRate, format, channelMask); return BAD_VALUE; @@ -193,7 +194,7 @@ status_t AudioRecord::set( return BAD_VALUE; } mChannelMask = channelMask; - uint32_t channelCount = popcount(channelMask); + uint32_t channelCount = audio_channel_count_from_in_mask(channelMask); mChannelCount = channelCount; if (audio_is_linear_pcm(format)) { diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index aaaa3f1..b4d6d76 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -290,7 +290,7 @@ status_t AudioTrack::set( return BAD_VALUE; } mChannelMask = channelMask; - uint32_t channelCount = popcount(channelMask); + uint32_t channelCount = audio_channel_count_from_out_mask(channelMask); mChannelCount = channelCount; // AudioFlinger does not currently support 8-bit data in shared memory diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp index af8f365..6aab48a 100644 --- a/media/libnbaio/AudioStreamInSource.cpp +++ b/media/libnbaio/AudioStreamInSource.cpp @@ -46,7 +46,8 @@ ssize_t AudioStreamInSource::negotiate(const NBAIO_Format offers[], size_t numOf uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common); audio_channel_mask_t channelMask = (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); - mFormat = Format_from_SR_C(sampleRate, popcount(channelMask), streamFormat); + mFormat = Format_from_SR_C(sampleRate, + audio_channel_count_from_in_mask(channelMask), streamFormat); mFrameSize = Format_frameSize(mFormat); } return NBAIO_Source::negotiate(offers, numOffers, counterOffers, numCounterOffers); diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp index c28d34d..0d5f935 100644 --- a/media/libnbaio/AudioStreamOutSink.cpp +++ b/media/libnbaio/AudioStreamOutSink.cpp @@ -43,7 +43,8 @@ ssize_t AudioStreamOutSink::negotiate(const NBAIO_Format offers[], size_t numOff uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common); audio_channel_mask_t channelMask = (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); - mFormat = Format_from_SR_C(sampleRate, popcount(channelMask), streamFormat); + mFormat = Format_from_SR_C(sampleRate, + audio_channel_count_from_out_mask(channelMask), streamFormat); mFrameSize = Format_frameSize(mFormat); } return NBAIO_Sink::negotiate(offers, numOffers, counterOffers, numCounterOffers); -- cgit v1.1 From e507721000647a7d8afe44c63ef7fd04ef8971b1 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Mon, 28 Apr 2014 16:39:12 -0700 Subject: camera2: Adding TIFF writing utilities. Adds a native image utilities library with support for: - Writing TIFF 6.0 and TIFF EP compliant file headers. - Additional tags defined in EXIF 2.3 and DNG 1.4 specs. Change-Id: I7a4fef74bd5254d92baf08a3cf61af5de1b7ca83 --- media/img_utils/Android.mk | 15 + .../img_utils/include/img_utils/ByteArrayOutput.h | 82 ++ media/img_utils/include/img_utils/DngUtils.h | 132 +++ media/img_utils/include/img_utils/EndianUtils.h | 250 +++++ media/img_utils/include/img_utils/FileInput.h | 76 ++ media/img_utils/include/img_utils/FileOutput.h | 46 + media/img_utils/include/img_utils/Input.h | 63 ++ media/img_utils/include/img_utils/Orderable.h | 57 + media/img_utils/include/img_utils/Output.h | 61 ++ media/img_utils/include/img_utils/Pair.h | 44 + .../include/img_utils/SortedEntryVector.h | 53 + media/img_utils/include/img_utils/TagDefinitions.h | 1139 ++++++++++++++++++++ media/img_utils/include/img_utils/TiffEntry.h | 129 +++ media/img_utils/include/img_utils/TiffEntryImpl.h | 190 ++++ media/img_utils/include/img_utils/TiffHelpers.h | 132 +++ media/img_utils/include/img_utils/TiffIfd.h | 124 +++ media/img_utils/include/img_utils/TiffWritable.h | 60 ++ media/img_utils/include/img_utils/TiffWriter.h | 267 +++++ media/img_utils/src/Android.mk | 61 ++ media/img_utils/src/ByteArrayOutput.cpp | 54 + media/img_utils/src/DngUtils.cpp | 280 +++++ media/img_utils/src/EndianUtils.cpp | 83 ++ media/img_utils/src/FileInput.cpp | 80 ++ media/img_utils/src/FileOutput.cpp | 79 ++ media/img_utils/src/Input.cpp | 29 + media/img_utils/src/Orderable.cpp | 39 + media/img_utils/src/Output.cpp | 28 + media/img_utils/src/SortedEntryVector.cpp | 44 + media/img_utils/src/TiffEntry.cpp | 238 ++++ media/img_utils/src/TiffEntryImpl.cpp | 44 + media/img_utils/src/TiffIfd.cpp | 182 ++++ media/img_utils/src/TiffWritable.cpp | 31 + media/img_utils/src/TiffWriter.cpp | 232 ++++ 33 files changed, 4424 insertions(+) create mode 100644 media/img_utils/Android.mk create mode 100644 media/img_utils/include/img_utils/ByteArrayOutput.h create mode 100644 media/img_utils/include/img_utils/DngUtils.h create mode 100644 media/img_utils/include/img_utils/EndianUtils.h create mode 100644 media/img_utils/include/img_utils/FileInput.h create mode 100644 media/img_utils/include/img_utils/FileOutput.h create mode 100644 media/img_utils/include/img_utils/Input.h create mode 100644 media/img_utils/include/img_utils/Orderable.h create mode 100644 media/img_utils/include/img_utils/Output.h create mode 100644 media/img_utils/include/img_utils/Pair.h create mode 100644 media/img_utils/include/img_utils/SortedEntryVector.h create mode 100644 media/img_utils/include/img_utils/TagDefinitions.h create mode 100644 media/img_utils/include/img_utils/TiffEntry.h create mode 100644 media/img_utils/include/img_utils/TiffEntryImpl.h create mode 100644 media/img_utils/include/img_utils/TiffHelpers.h create mode 100644 media/img_utils/include/img_utils/TiffIfd.h create mode 100644 media/img_utils/include/img_utils/TiffWritable.h create mode 100644 media/img_utils/include/img_utils/TiffWriter.h create mode 100644 media/img_utils/src/Android.mk create mode 100644 media/img_utils/src/ByteArrayOutput.cpp create mode 100644 media/img_utils/src/DngUtils.cpp create mode 100644 media/img_utils/src/EndianUtils.cpp create mode 100644 media/img_utils/src/FileInput.cpp create mode 100644 media/img_utils/src/FileOutput.cpp create mode 100644 media/img_utils/src/Input.cpp create mode 100644 media/img_utils/src/Orderable.cpp create mode 100644 media/img_utils/src/Output.cpp create mode 100644 media/img_utils/src/SortedEntryVector.cpp create mode 100644 media/img_utils/src/TiffEntry.cpp create mode 100644 media/img_utils/src/TiffEntryImpl.cpp create mode 100644 media/img_utils/src/TiffIfd.cpp create mode 100644 media/img_utils/src/TiffWritable.cpp create mode 100644 media/img_utils/src/TiffWriter.cpp (limited to 'media') diff --git a/media/img_utils/Android.mk b/media/img_utils/Android.mk new file mode 100644 index 0000000..1cd00bd --- /dev/null +++ b/media/img_utils/Android.mk @@ -0,0 +1,15 @@ +# Copyright 2014 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 $(call all-subdir-makefiles) diff --git a/media/img_utils/include/img_utils/ByteArrayOutput.h b/media/img_utils/include/img_utils/ByteArrayOutput.h new file mode 100644 index 0000000..ba73977 --- /dev/null +++ b/media/img_utils/include/img_utils/ByteArrayOutput.h @@ -0,0 +1,82 @@ +/* + * Copyright 2014 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 IMG_UTILS_BYTE_ARRAY_OUTPUT_H +#define IMG_UTILS_BYTE_ARRAY_OUTPUT_H + +#include + +#include +#include + +#include +#include + +namespace android { +namespace img_utils { + +/** + * Utility class that accumulates written bytes into a buffer. + */ +class ANDROID_API ByteArrayOutput : public Output { + public: + + ByteArrayOutput(); + + virtual ~ByteArrayOutput(); + + /** + * Open this ByteArrayOutput. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t open(); + + /** + * Write bytes from the given buffer. The number of bytes given in the count + * argument will be written. Bytes will be written from the given buffer starting + * at the index given in the offset argument. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t write(const uint8_t* buf, size_t offset, size_t count); + + /** + * Close this ByteArrayOutput. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t close(); + + /** + * Get current size of the array of bytes written. + */ + virtual size_t getSize() const; + + /** + * Get pointer to array of bytes written. It is not valid to use this pointer if + * open, write, or close is called after this method. + */ + virtual const uint8_t* getArray() const; + + protected: + Vector mByteArray; +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_BYTE_ARRAY_OUTPUT_H*/ diff --git a/media/img_utils/include/img_utils/DngUtils.h b/media/img_utils/include/img_utils/DngUtils.h new file mode 100644 index 0000000..4389b02 --- /dev/null +++ b/media/img_utils/include/img_utils/DngUtils.h @@ -0,0 +1,132 @@ +/* + * Copyright 2014 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 IMG_UTILS_DNG_UTILS_H +#define IMG_UTILS_DNG_UTILS_H + +#include +#include + +#include +#include +#include + +#include +#include + +namespace android { +namespace img_utils { + +#define NELEMS(x) ((int) (sizeof(x) / sizeof((x)[0]))) + +/** + * Utility class for building values for the OpcodeList tags specified + * in the Adobe DNG 1.4 spec. + */ +class ANDROID_API OpcodeListBuilder : public LightRefBase { + public: + enum CfaLayout { + CFA_RGGB = 0, + CFA_GRBG, + CFA_GBRG, + CFA_BGGR, + }; + + OpcodeListBuilder(); + virtual ~OpcodeListBuilder(); + + /** + * Get the total size of this opcode list in bytes. + */ + virtual size_t getSize() const; + + /** + * Get the number of opcodes defined in this list. + */ + virtual uint32_t getCount() const; + + /** + * Write the opcode list into the given buffer. This buffer + * must be able to hold at least as many elements as returned + * by calling the getSize() method. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t buildOpList(/*out*/ uint8_t* buf) const; + + /** + * Add GainMap opcode(s) for the given metadata parameters. The given + * CFA layout must match the layout of the shading map passed into the + * lensShadingMap parameter. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t addGainMapsForMetadata(uint32_t lsmWidth, + uint32_t lsmHeight, + uint32_t activeAreaTop, + uint32_t activeAreaLeft, + uint32_t activeAreaBottom, + uint32_t activeAreaRight, + CfaLayout cfa, + const float* lensShadingMap); + + + /** + * Add a GainMap opcode with the given fields. The mapGains array + * must have mapPointsV * mapPointsH * mapPlanes elements. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t addGainMap(uint32_t top, + uint32_t left, + uint32_t bottom, + uint32_t right, + uint32_t plane, + uint32_t planes, + uint32_t rowPitch, + uint32_t colPitch, + uint32_t mapPointsV, + uint32_t mapPointsH, + double mapSpacingV, + double mapSpacingH, + double mapOriginV, + double mapOriginH, + uint32_t mapPlanes, + const float* mapGains); + + // TODO: Add other Opcode methods + protected: + static const uint32_t FLAG_OPTIONAL = 0x1u; + static const uint32_t FLAG_OPTIONAL_FOR_PREVIEW = 0x2u; + + enum { + GAIN_MAP_ID = 9, + LSM_R_IND = 0, + LSM_GE_IND = 1, + LSM_GO_IND = 2, + LSM_B_IND = 3, + }; + + uint32_t mCount; + ByteArrayOutput mOpList; + EndianOutput mEndianOut; + +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_DNG_UTILS_H*/ diff --git a/media/img_utils/include/img_utils/EndianUtils.h b/media/img_utils/include/img_utils/EndianUtils.h new file mode 100644 index 0000000..e99be1a --- /dev/null +++ b/media/img_utils/include/img_utils/EndianUtils.h @@ -0,0 +1,250 @@ +/* + * Copyright 2014 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 IMG_UTILS_ENDIAN_UTILS +#define IMG_UTILS_ENDIAN_UTILS + +#include + +#include +#include +#include +#include +#include + +namespace android { +namespace img_utils { + +/** + * Endianness types supported. + */ +enum ANDROID_API Endianness { + UNDEFINED_ENDIAN, // Default endianness will be used. + BIG, + LITTLE +}; + +/** + * Convert from the native device endianness to big endian. + */ +template +T convertToBigEndian(T in); + +/** + * Convert from the native device endianness to little endian. + */ +template +T convertToLittleEndian(T in); + +/** + * A utility class for writing to an Output with the given endianness. + */ +class ANDROID_API EndianOutput : public Output { + public: + /** + * Wrap the given Output. Calling write methods will result in + * writes to this output. + */ + EndianOutput(Output* out, Endianness end=LITTLE); + + virtual ~EndianOutput(); + + /** + * Call open on the wrapped output. + */ + virtual status_t open(); + + /** + * Call close on the wrapped output. + */ + virtual status_t close(); + + /** + * Set the endianness to use when writing. + */ + virtual void setEndianness(Endianness end); + + /** + * Get the currently configured endianness. + */ + virtual Endianness getEndianness() const; + + /** + * Get the current number of bytes written by this EndianOutput. + */ + virtual uint32_t getCurrentOffset() const; + + + // TODO: switch write methods to uint32_t instead of size_t, + // the max size of a TIFF files is bounded + + /** + * The following methods will write elements from given input buffer to the output. + * Count elements in the buffer will be written with the endianness set for this + * EndianOutput. If the given offset is greater than zero, that many elements will + * be skipped in the buffer before writing. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t write(const uint8_t* buf, size_t offset, size_t count); + + virtual status_t write(const int8_t* buf, size_t offset, size_t count); + + virtual status_t write(const uint16_t* buf, size_t offset, size_t count); + + virtual status_t write(const int16_t* buf, size_t offset, size_t count); + + virtual status_t write(const uint32_t* buf, size_t offset, size_t count); + + virtual status_t write(const int32_t* buf, size_t offset, size_t count); + + virtual status_t write(const uint64_t* buf, size_t offset, size_t count); + + virtual status_t write(const int64_t* buf, size_t offset, size_t count); + + virtual status_t write(const float* buf, size_t offset, size_t count); + + virtual status_t write(const double* buf, size_t offset, size_t count); + + protected: + template + inline status_t writeHelper(const T* buf, size_t offset, size_t count); + + uint32_t mOffset; + Output* mOutput; + Endianness mEndian; +}; + +template +inline status_t EndianOutput::writeHelper(const T* buf, size_t offset, size_t count) { + assert(offset <= count); + status_t res = OK; + size_t size = sizeof(T); + switch(mEndian) { + case BIG: { + for (size_t i = offset; i < count; ++i) { + T tmp = convertToBigEndian(buf[offset + i]); + if ((res = mOutput->write(reinterpret_cast(&tmp), 0, size)) + != OK) { + return res; + } + mOffset += size; + } + break; + } + case LITTLE: { + for (size_t i = offset; i < count; ++i) { + T tmp = convertToLittleEndian(buf[offset + i]); + if ((res = mOutput->write(reinterpret_cast(&tmp), 0, size)) + != OK) { + return res; + } + mOffset += size; + } + break; + } + default: { + return BAD_VALUE; + } + } + return res; +} + +template<> +inline uint8_t convertToBigEndian(uint8_t in) { + return in; +} + +template<> +inline int8_t convertToBigEndian(int8_t in) { + return in; +} + +template<> +inline uint16_t convertToBigEndian(uint16_t in) { + return htobe16(in); +} + +template<> +inline int16_t convertToBigEndian(int16_t in) { + return htobe16(in); +} + +template<> +inline uint32_t convertToBigEndian(uint32_t in) { + return htobe32(in); +} + +template<> +inline int32_t convertToBigEndian(int32_t in) { + return htobe32(in); +} + +template<> +inline uint64_t convertToBigEndian(uint64_t in) { + return htobe64(in); +} + +template<> +inline int64_t convertToBigEndian(int64_t in) { + return htobe64(in); +} + +template<> +inline uint8_t convertToLittleEndian(uint8_t in) { + return in; +} + +template<> +inline int8_t convertToLittleEndian(int8_t in) { + return in; +} + +template<> +inline uint16_t convertToLittleEndian(uint16_t in) { + return htole16(in); +} + +template<> +inline int16_t convertToLittleEndian(int16_t in) { + return htole16(in); +} + +template<> +inline uint32_t convertToLittleEndian(uint32_t in) { + return htole32(in); +} + +template<> +inline int32_t convertToLittleEndian(int32_t in) { + return htole32(in); +} + +template<> +inline uint64_t convertToLittleEndian(uint64_t in) { + return htole64(in); +} + +template<> +inline int64_t convertToLittleEndian(int64_t in) { + return htole64(in); +} + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_ENDIAN_UTILS*/ + diff --git a/media/img_utils/include/img_utils/FileInput.h b/media/img_utils/include/img_utils/FileInput.h new file mode 100644 index 0000000..d3c5ec1 --- /dev/null +++ b/media/img_utils/include/img_utils/FileInput.h @@ -0,0 +1,76 @@ +/* + * Copyright 2014 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 IMG_UTILS_FILE_INPUT_H +#define IMG_UTILS_FILE_INPUT_H + +#include + +#include +#include +#include +#include +#include + +namespace android { +namespace img_utils { + +/** + * Utility class for reading from a file. + */ +class ANDROID_API FileInput : public Input { + public: + /** + * Create a file input for the given path. + */ + FileInput(String8 path); + + virtual ~FileInput(); + + /** + * Open a file descriptor to the path given in the constructor. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t open(); + + /** + * Read bytes from the file into the given buffer. At most, the number + * of bytes given in the count argument will be read. Bytes will be written + * into the given buffer starting at the index given in the offset argument. + * + * Returns the number of bytes read. If an error has occurred, the value pointed + * to by the given status_t pointer will be set to a negative error code. + */ + virtual size_t read(uint8_t* buf, size_t offset, size_t count, status_t* err); + + /** + * Close the file descriptor to the path given in the constructor. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t close(); + private: + FILE *mFp; + String8 mPath; + bool mOpen; +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + + +#endif /*IMG_UTILS_INPUT_H*/ diff --git a/media/img_utils/include/img_utils/FileOutput.h b/media/img_utils/include/img_utils/FileOutput.h new file mode 100644 index 0000000..fd5be27 --- /dev/null +++ b/media/img_utils/include/img_utils/FileOutput.h @@ -0,0 +1,46 @@ +/* + * Copyright 2014 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 IMG_UTILS_FILE_OUTPUT_H +#define IMG_UTILS_FILE_OUTPUT_H + +#include +#include +#include +#include +#include +#include + +namespace android { +namespace img_utils { + +class ANDROID_API FileOutput : public Output { + public: + FileOutput(String8 path); + virtual ~FileOutput(); + virtual status_t open(); + virtual status_t write(const uint8_t* buf, size_t offset, size_t count); + virtual status_t close(); + private: + FILE *mFp; + String8 mPath; + bool mOpen; +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_FILE_OUTPUT_H*/ diff --git a/media/img_utils/include/img_utils/Input.h b/media/img_utils/include/img_utils/Input.h new file mode 100644 index 0000000..2166601 --- /dev/null +++ b/media/img_utils/include/img_utils/Input.h @@ -0,0 +1,63 @@ +/* + * Copyright 2014 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 IMG_UTILS_INPUT_H +#define IMG_UTILS_INPUT_H + +#include +#include +#include + +namespace android { +namespace img_utils { + +/** + * Utility class used as a source of bytes. + */ +class ANDROID_API Input { + public: + virtual ~Input(); + + /** + * Open this Input. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t open(); + + /** + * Read bytes into the given buffer. At most, the number of bytes given in the + * count argument will be read. Bytes will be written into the given buffer starting + * at the index given in the offset argument. + * + * Returns the number of bytes read. If an error has occurred, the value pointed + * to by the given status_t pointer will be set to a negative error code. + */ + virtual size_t read(uint8_t* buf, size_t offset, size_t count, status_t* err) = 0; + + /** + * Close the Input. It is not valid to call open on a previously closed Input. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t close(); +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + + +#endif /*IMG_UTILS_INPUT_H*/ diff --git a/media/img_utils/include/img_utils/Orderable.h b/media/img_utils/include/img_utils/Orderable.h new file mode 100644 index 0000000..87253a4 --- /dev/null +++ b/media/img_utils/include/img_utils/Orderable.h @@ -0,0 +1,57 @@ +/* + * Copyright 2014 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 IMG_UTILS_ORDERABLE +#define IMG_UTILS_ORDERABLE + +#include +#include + +namespace android { +namespace img_utils { + +#define COMPARE_DEF(op) \ +inline bool operator op (const Orderable& orderable) const; + +/** + * Subclasses of Orderable can be compared and sorted. This is + * intended to be used to create sorted arrays of TIFF entries + * and IFDs. + */ +class ANDROID_API Orderable { + public: + virtual ~Orderable(); + + /** + * Comparison operatotors are based on the value returned + * from this method. + */ + virtual uint32_t getComparableValue() const = 0; + + COMPARE_DEF(>) + COMPARE_DEF(<) + COMPARE_DEF(>=) + COMPARE_DEF(<=) + COMPARE_DEF(==) + COMPARE_DEF(!=) +}; + +#undef COMPARE_DEF + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_ORDERABLE*/ diff --git a/media/img_utils/include/img_utils/Output.h b/media/img_utils/include/img_utils/Output.h new file mode 100644 index 0000000..35fae23 --- /dev/null +++ b/media/img_utils/include/img_utils/Output.h @@ -0,0 +1,61 @@ +/* + * Copyright 2014 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 IMG_UTILS_OUTPUT_H +#define IMG_UTILS_OUTPUT_H + +#include +#include +#include + +namespace android { +namespace img_utils { + +/** + * Utility class used to output bytes. + */ +class ANDROID_API Output { + public: + virtual ~Output(); + + /** + * Open this Output. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t open(); + + /** + * Write bytes from the given buffer. The number of bytes given in the count + * argument will be written. Bytes will be written from the given buffer starting + * at the index given in the offset argument. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t write(const uint8_t* buf, size_t offset, size_t count) = 0; + + /** + * Close this Output. It is not valid to call open on a previously closed Output. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t close(); +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_OUTPUT_H*/ diff --git a/media/img_utils/include/img_utils/Pair.h b/media/img_utils/include/img_utils/Pair.h new file mode 100644 index 0000000..d651cac --- /dev/null +++ b/media/img_utils/include/img_utils/Pair.h @@ -0,0 +1,44 @@ +/* + * Copyright 2014 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 IMG_UTILS_PAIR_H +#define IMG_UTILS_PAIR_H + +#include + +namespace android { +namespace img_utils { + +/** + * Generic pair utility class. Nothing special here. + */ +template +class ANDROID_API Pair { + public: + F first; + S second; + + Pair() {} + + Pair(const Pair& o) : first(o.first), second(o.second) {} + + Pair(const F& f, const S& s) : first(f), second(s) {} +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_PAIR_H*/ diff --git a/media/img_utils/include/img_utils/SortedEntryVector.h b/media/img_utils/include/img_utils/SortedEntryVector.h new file mode 100644 index 0000000..f059a82 --- /dev/null +++ b/media/img_utils/include/img_utils/SortedEntryVector.h @@ -0,0 +1,53 @@ +/* + * Copyright 2014 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 IMG_UTILS_SORTED_ENTRY_VECTOR_H +#define IMG_UTILS_SORTED_ENTRY_VECTOR_H + +#include + +#include +#include + +namespace android { +namespace img_utils { + +/** + * Subclass of SortedVector that has been extended to + * do comparisons/lookups based on the tag ID of the entries. + */ +class SortedEntryVector : public SortedVector > { + public: + virtual ~SortedEntryVector(); + + /** + * Returns the index of the entry with the given tag ID, or + * -1 if none exists. + */ + ssize_t indexOfTag(uint16_t tag) const; + + protected: + /** + * Compare tag ID. + */ + virtual int do_compare(const void* lhs, const void* rhs) const; +}; + + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_SORTED_ENTRY_VECTOR_H*/ diff --git a/media/img_utils/include/img_utils/TagDefinitions.h b/media/img_utils/include/img_utils/TagDefinitions.h new file mode 100644 index 0000000..9232e58 --- /dev/null +++ b/media/img_utils/include/img_utils/TagDefinitions.h @@ -0,0 +1,1139 @@ +/* + * Copyright 2014 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 IMG_UTILS_TIFF_TAG_DEFINITION_H +#define IMG_UTILS_TIFF_TAG_DEFINITION_H + +#include +#include +#include +#include + +namespace android { +namespace img_utils { + +/** + * Tag definitions contain information about standard TIFF compatible tags. + */ +typedef struct TagDefinition { + // The specified tag ID. + uint16_t tagId; + // The default type for this tag. This must be a valid TIFF type. + TagType defaultType; + // The default Image File Directory (IFD) for this tag. + uint32_t defaultIfd; + // The valid count for this tag, or 0 if the count is not fixed. + uint32_t fixedCount; + // The endianness of the tag value, or UNDEFINED_ENDIAN if there is no fixed endian + Endianness fixedEndian; +} TagDefinition_t; + +/** + * Convenience defines for tag ids. + */ +enum { + TAG_RAWTOPREVIEWGAIN = 0xC7A8u, + TAG_NEWRAWIMAGEDIGEST = 0xC7A7u, + TAG_ORIGINALDEFAULTCROPSIZE = 0xC793u, + TAG_ORIGINALBESTQUALITYFINALSIZE = 0xC792u, + TAG_ORIGINALDEFAULTFINALSIZE = 0xC791u, + TAG_PROFILEHUESATMAPENCODING = 0xC7A3u, + TAG_PROFILELOOKTABLEENCODING = 0xC7A4u, + TAG_BASELINEEXPOSUREOFFSET = 0xC7A5u, + TAG_DEFAULTBLACKRENDER = 0xC7A6u, + TAG_DEFAULTUSERCROP = 0xC7B5u, + TAG_NOISEPROFILE = 0xC761u, + TAG_OPCODELIST3 = 0xC74Eu, + TAG_OPCODELIST2 = 0xC741u, + TAG_OPCODELIST1 = 0xC740u, + TAG_PROFILELOOKTABLEDATA = 0xC726u, + TAG_PROFILELOOKTABLEDIMS = 0xC725u, + TAG_ROWINTERLEAVEFACTOR = 0xC71Fu, + TAG_SUBTILEBLOCKSIZE = 0xC71Eu, + TAG_ORIGINALRAWFILEDIGEST = 0xC71Du, + TAG_RAWIMAGEDIGEST = 0xC71Cu, + TAG_PREVIEWDATETIME = 0xC71Bu, + TAG_PREVIEWCOLORSPACE = 0xC71Au, + TAG_PREVIEWSETTINGSDIGEST = 0xC719u, + TAG_PREVIEWSETTINGSNAME = 0xC718u, + TAG_PREVIEWAPPLICATIONVERSION = 0xC717u, + TAG_PREVIEWAPPLICATIONNAME = 0xC716u, + TAG_FORWARDMATRIX2 = 0xC715u, + TAG_FORWARDMATRIX1 = 0xC714u, + TAG_PROFILECOPYRIGHT = 0xC6FEu, + TAG_PROFILEEMBEDPOLICY = 0xC6FDu, + TAG_PROFILETONECURVE = 0xC6FCu, + TAG_PROFILEHUESATMAPDATA2 = 0xC6FBu, + TAG_PROFILEHUESATMAPDATA1 = 0xC6FAu, + TAG_PROFILEHUESATMAPDIMS = 0xC6F9u, + TAG_PROFILENAME = 0xC6F8u, + TAG_NOISEREDUCTIONAPPLIED = 0xC6F7u, + TAG_ASSHOTPROFILENAME = 0xC6F6u, + TAG_EXTRACAMERAPROFILES = 0xC6F5u, + TAG_PROFILECALIBRATIONSIGNATURE = 0xC6F4u, + TAG_CAMERACALIBRATIONSIGNATURE = 0xC6F3u, + TAG_COLORIMETRICREFERENCE = 0xC6BFu, + TAG_CURRENTPREPROFILEMATRIX = 0xC692u, + TAG_CURRENTICCPROFILE = 0xC691u, + TAG_ASSHOTPREPROFILEMATRIX = 0xC690u, + TAG_ASSHOTICCPROFILE = 0xC68Fu, + TAG_MASKEDAREAS = 0xC68Eu, + TAG_ACTIVEAREA = 0xC68Du, + TAG_ORIGINALRAWFILEDATA = 0xC68Cu, + TAG_ORIGINALRAWFILENAME = 0xC68Bu, + TAG_RAWDATAUNIQUEID = 0xC65Du, + TAG_MAKERNOTESAFETY = 0xC635u, + TAG_DNGPRIVATEDATA = 0xC634u, + TAG_SHADOWSCALE = 0xC633u, + TAG_ANTIALIASSTRENGTH = 0xC632u, + TAG_CHROMABLURRADIUS = 0xC631u, + TAG_LENSINFO = 0xC630u, + TAG_CAMERASERIALNUMBER = 0xC62Fu, + TAG_LINEARRESPONSELIMIT = 0xC62Eu, + TAG_BAYERGREENSPLIT = 0xC62Du, + TAG_BASELINESHARPNESS = 0xC62Cu, + TAG_BASELINENOISE = 0xC62Bu, + TAG_BASELINEEXPOSURE = 0xC62Au, + TAG_ASSHOTWHITEXY = 0xC629u, + TAG_ASSHOTNEUTRAL = 0xC628u, + TAG_ANALOGBALANCE = 0xC627u, + TAG_REDUCTIONMATRIX2 = 0xC626u, + TAG_REDUCTIONMATRIX1 = 0xC625u, + TAG_CAMERACALIBRATION2 = 0xC624u, + TAG_CAMERACALIBRATION1 = 0xC623u, + TAG_COLORMATRIX2 = 0xC622u, + TAG_COLORMATRIX1 = 0xC621u, + TAG_CALIBRATIONILLUMINANT2 = 0xC65Bu, + TAG_CALIBRATIONILLUMINANT1 = 0xC65Au, + TAG_DEFAULTCROPSIZE = 0xC620u, + TAG_DEFAULTCROPORIGIN = 0xC61Fu, + TAG_BESTQUALITYSCALE = 0xC65Cu, + TAG_DEFAULTSCALE = 0xC61Eu, + TAG_WHITELEVEL = 0xC61Du, + TAG_BLACKLEVELDELTAV = 0xC61Cu, + TAG_BLACKLEVELDELTAH = 0xC61Bu, + TAG_BLACKLEVEL = 0xC61Au, + TAG_BLACKLEVELREPEATDIM = 0xC619u, + TAG_LINEARIZATIONTABLE = 0xC618u, + TAG_CFALAYOUT = 0xC617u, + TAG_CFAPLANECOLOR = 0xC616u, + TAG_LOCALIZEDCAMERAMODEL = 0xC615u, + TAG_UNIQUECAMERAMODEL = 0xC614u, + TAG_DNGBACKWARDVERSION = 0xC613u, + TAG_DNGVERSION = 0xC612u, + TAG_SUBFILETYPE = 0x00FFu, + TAG_YRESOLUTION = 0x011Bu, + TAG_XRESOLUTION = 0x011Au, + TAG_THRESHHOLDING = 0x0107u, + TAG_STRIPOFFSETS = 0x0111u, + TAG_STRIPBYTECOUNTS = 0x0117u, + TAG_SOFTWARE = 0x0131u, + TAG_SAMPLESPERPIXEL = 0x0115u, + TAG_ROWSPERSTRIP = 0x0116u, + TAG_RESOLUTIONUNIT = 0x0128u, + TAG_PLANARCONFIGURATION = 0x011Cu, + TAG_PHOTOMETRICINTERPRETATION = 0x0106u, + TAG_ORIENTATION = 0x0112u, + TAG_NEWSUBFILETYPE = 0x00FEu, + TAG_MODEL = 0x0110u, + TAG_MINSAMPLEVALUE = 0x0118u, + TAG_MAXSAMPLEVALUE = 0x0119u, + TAG_MAKE = 0x010Fu, + TAG_IMAGEWIDTH = 0x0100u, + TAG_IMAGELENGTH = 0x0101u, + TAG_IMAGEDESCRIPTION = 0x010Eu, + TAG_HOSTCOMPUTER = 0x013Cu, + TAG_GRAYRESPONSEUNIT = 0x0122u, + TAG_GRAYRESPONSECURVE = 0x0123u, + TAG_FREEOFFSETS = 0x0120u, + TAG_FREEBYTECOUNTS = 0x0121u, + TAG_FILLORDER = 0x010Au, + TAG_EXTRASAMPLES = 0x0152u, + TAG_DATETIME = 0x0132u, + TAG_COPYRIGHT = 0x8298u, + TAG_COMPRESSION = 0x0103u, + TAG_COLORMAP = 0x0140u, + TAG_CELLWIDTH = 0x0108u, + TAG_CELLLENGTH = 0x0109u, + TAG_BITSPERSAMPLE = 0x0102u, + TAG_ARTIST = 0x013Bu, + TAG_EXIFVERSION = 0x9000u, + TAG_CFAREPEATPATTERNDIM = 0x828Du, + TAG_CFAPATTERN = 0x828Eu, + TAG_SUBIFDS = 0x014Au, +}; + +/** + * TIFF_EP_TAG_DEFINITIONS contains tags defined in the TIFF EP spec + */ +const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { + { // PhotometricInterpretation + 0x0106u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // SubIfds + 0x014Au, + LONG, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CFAPattern + 0x828Eu, + BYTE, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CFARepeatPatternDim + 0x828Du, + SHORT, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + /*TODO: Remaining TIFF EP tags*/ +}; + +/** + * EXIF_2_3_TAG_DEFINITIONS contains tags defined in the Jeita EXIF 2.3 spec + */ +const TagDefinition_t EXIF_2_3_TAG_DEFINITIONS[] = { + { // ExifVersion + 0x9000u, + UNDEFINED, + IFD_0, + 4, + UNDEFINED_ENDIAN + }, + /*TODO: Remaining EXIF 2.3 tags*/ +}; + +/** + * TIFF_6_TAG_DEFINITIONS contains tags defined in the TIFF 6.0 spec + */ +const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { + { // SubFileType + 0x00FFu, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // Artist + 0x013Bu, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // BitsPerSample + 0x0102u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CellLength + 0x0109u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // CellWidth + 0x0108u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // ColorMap + 0x0140u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // Compression + 0x0103u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // Copyright + 0x8298u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // DateTime + 0x0132u, + ASCII, + IFD_0, + 20, + UNDEFINED_ENDIAN + }, + { // ExtraSamples + 0x0152u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // FillOrder + 0x010Au, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // FreeByteCounts + 0x0121u, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // FreeOffsets + 0x0120u, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // GrayResponseCurve + 0x0123u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // GrayResponseUnit + 0x0122u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // HostComputer + 0x013Cu, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // ImageDescription + 0x010Eu, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // ImageLength + 0x0101u, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // ImageWidth + 0x0100u, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // Make + 0x010Fu, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // MaxSampleValue + 0x0119u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // MinSampleValue + 0x0118u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // Model + 0x0110u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // NewSubfileType + 0x00FEu, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // Orientation + 0x0112u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // PhotoMetricInterpretation + 0x0106u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // PlanarConfiguration + 0x011Cu, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // ResolutionUnit + 0x0128u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // RowsPerStrip + 0x0116u, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // SamplesPerPixel + 0x0115u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // Software + 0x0131u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // StripByteCounts + 0x0117u, + LONG, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // StripOffsets + 0x0111u, + LONG, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // SubfileType + 0x00FFu, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // Threshholding + 0x0107u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // XResolution + 0x011Au, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // YResolution + 0x011Bu, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // YResolution + 0x011Bu, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + } +}; + +/** + * DNG_TAG_DEFINITIONS contains tags defined in the DNG 1.4 spec + */ +const TagDefinition_t DNG_TAG_DEFINITIONS[] = { + { // DNGVersion + 0xC612u, + BYTE, + IFD_0, + 4, + UNDEFINED_ENDIAN + }, + { // DNGBackwardVersion + 0xC613u, + BYTE, + IFD_0, + 4, + UNDEFINED_ENDIAN + }, + { // UniqueCameraModel + 0xC614u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // LocalizedCameraModel + 0xC615u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CFAPlaneColor + 0xC616u, + BYTE, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // CFALayout + 0xC617u, + SHORT, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // LinearizationTable + 0xC618u, + SHORT, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // BlackLevelRepeatDim + 0xC619u, + SHORT, + RAW_IFD, + 2, + UNDEFINED_ENDIAN + }, + { // BlackLevel + 0xC61Au, + LONG, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // BlackLevelDeltaH + 0xC61Bu, + SRATIONAL, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // BlackLevelDeltaV + 0xC61Cu, + SRATIONAL, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // WhiteLevel + 0xC61Du, + LONG, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // DefaultScale + 0xC61Eu, + RATIONAL, + RAW_IFD, + 2, + UNDEFINED_ENDIAN + }, + { // BestQualityScale + 0xC65Cu, + RATIONAL, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // DefaultCropOrigin + 0xC61Fu, + LONG, + RAW_IFD, + 2, + UNDEFINED_ENDIAN + }, + { // DefaultCropSize + 0xC620u, + LONG, + RAW_IFD, + 2, + UNDEFINED_ENDIAN + }, + { // CalibrationIlluminant1 + 0xC65Au, + SHORT, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // CalibrationIlluminant2 + 0xC65Bu, + SHORT, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ColorMatrix1 + 0xC621u, + SRATIONAL, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ColorMatrix2 + 0xC622u, + SRATIONAL, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // CameraCalibration1 + 0xC623u, + SRATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CameraCalibration2 + 0xC624u, + SRATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // ReductionMatrix1 + 0xC625u, + SRATIONAL, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ReductionMatrix2 + 0xC626u, + SRATIONAL, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // AnalogBalance + 0xC627u, + RATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // AsShotNeutral + 0xC628u, + RATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // AsShotWhiteXY + 0xC629u, + RATIONAL, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + { // BaselineExposure + 0xC62Au, + SRATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // BaselineNoise + 0xC62Bu, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // BaselineSharpness + 0xC62Cu, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // BayerGreenSplit + 0xC62Du, + LONG, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // LinearResponseLimit + 0xC62Eu, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // CameraSerialNumber + 0xC62Fu, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // LensInfo + 0xC630u, + RATIONAL, + IFD_0, + 4, + UNDEFINED_ENDIAN + }, + { // ChromaBlurRadius + 0xC631u, + RATIONAL, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // AntiAliasStrength + 0xC632u, + RATIONAL, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ShadowScale + 0xC633u, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // DNGPrivateData + 0xC634u, + BYTE, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // MakerNoteSafety + 0xC635u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // RawDataUniqueID + 0xC65Du, + BYTE, + IFD_0, + 16, + UNDEFINED_ENDIAN + }, + { // OriginalRawFileName + 0xC68Bu, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // OriginalRawFileData + 0xC68Cu, + UNDEFINED, + IFD_0, + 0, + BIG + }, + { // ActiveArea + 0xC68Du, + LONG, + RAW_IFD, + 4, + UNDEFINED_ENDIAN + }, + { // MaskedAreas + 0xC68Eu, + LONG, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // AsShotICCProfile + 0xC68Fu, + UNDEFINED, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // AsShotPreProfileMatrix + 0xC690u, + SRATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CurrentICCProfile + 0xC691u, + UNDEFINED, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CurrentICCProfile + 0xC691u, + UNDEFINED, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CurrentPreProfileMatrix + 0xC692u, + SRATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // ColorimetricReference + 0xC6BFu, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // CameraCalibrationSignature + 0xC6F3u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // ProfileCalibrationSignature + 0xC6F4u, + ASCII, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ExtraCameraProfiles + 0xC6F5u, + LONG, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // AsShotProfileName + 0xC6F6u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // NoiseReductionApplied + 0xC6F7u, + RATIONAL, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ProfileName + 0xC6F8u, + ASCII, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ProfileHueSatMapDims + 0xC6F9u, + LONG, + PROFILE_IFD, + 3, + UNDEFINED_ENDIAN + }, + { // ProfileHueSatMapData1 + 0xC6FAu, + FLOAT, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ProfileHueSatMapData2 + 0xC6FBu, + FLOAT, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ProfileToneCurve + 0xC6FCu, + FLOAT, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ProfileEmbedPolicy + 0xC6FDu, + LONG, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ProfileCopyright + 0xC6FEu, + ASCII, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ForwardMatrix1 + 0xC714u, + SRATIONAL, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ForwardMatrix2 + 0xC715u, + SRATIONAL, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // PreviewApplicationName + 0xC716u, + ASCII, + PREVIEW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // PreviewApplicationVersion + 0xC717u, + ASCII, + PREVIEW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // PreviewSettingsName + 0xC718u, + ASCII, + PREVIEW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // PreviewSettingsDigest + 0xC719u, + BYTE, + PREVIEW_IFD, + 16, + UNDEFINED_ENDIAN + }, + { // PreviewColorSpace + 0xC71Au, + LONG, + PREVIEW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // PreviewDateTime + 0xC71Bu, + ASCII, + PREVIEW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // RawImageDigest + 0xC71Cu, + BYTE, + IFD_0, + 16, + UNDEFINED_ENDIAN + }, + { // OriginalRawFileDigest + 0xC71Du, + BYTE, + IFD_0, + 16, + UNDEFINED_ENDIAN + }, + { // SubTileBlockSize + 0xC71Eu, + LONG, + RAW_IFD, + 2, + UNDEFINED_ENDIAN + }, + { // RowInterleaveFactor + 0xC71Fu, + LONG, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ProfileLookTableDims + 0xC725u, + LONG, + PROFILE_IFD, + 3, + UNDEFINED_ENDIAN + }, + { // ProfileLookTableData + 0xC726u, + FLOAT, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // OpcodeList1 + 0xC740u, + UNDEFINED, + RAW_IFD, + 0, + BIG + }, + { // OpcodeList2 + 0xC741u, + UNDEFINED, + RAW_IFD, + 0, + BIG + }, + { // OpcodeList3 + 0xC74Eu, + UNDEFINED, + RAW_IFD, + 0, + BIG + }, + { // NoiseProfile + 0xC761u, + DOUBLE, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // DefaultUserCrop + 0xC7B5u, + RATIONAL, + RAW_IFD, + 4, + UNDEFINED_ENDIAN + }, + { // DefaultBlackRender + 0xC7A6u, + LONG, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // BaselineExposureOffset + 0xC7A5u, + RATIONAL, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ProfileLookTableEncoding + 0xC7A4u, + LONG, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ProfileHueSatMapEncoding + 0xC7A3u, + LONG, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // OriginalDefaultFinalSize + 0xC791u, + LONG, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + { // OriginalBestQualityFinalSize + 0xC792u, + LONG, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + { // OriginalDefaultCropSize + 0xC793u, + LONG, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + { // NewRawImageDigest + 0xC7A7u, + BYTE, + IFD_0, + 16, + UNDEFINED_ENDIAN + }, + { // RawToPreviewGain + 0xC7A8u, + DOUBLE, + PREVIEW_IFD, + 1, + UNDEFINED_ENDIAN + }, +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_TIFF_TAG_DEFINITION_H*/ diff --git a/media/img_utils/include/img_utils/TiffEntry.h b/media/img_utils/include/img_utils/TiffEntry.h new file mode 100644 index 0000000..cd01640 --- /dev/null +++ b/media/img_utils/include/img_utils/TiffEntry.h @@ -0,0 +1,129 @@ +/* + * Copyright 2014 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 IMG_UTILS_TIFF_ENTRY +#define IMG_UTILS_TIFF_ENTRY + +#include +#include +#include + +#include +#include +#include +#include + +namespace android { +namespace img_utils { + +#define COMPARE_DEF(op) \ +inline bool operator op (const TiffEntry& entry) const; + +/** + * This class holds a single TIFF IFD entry. + */ +class ANDROID_API TiffEntry : public TiffWritable { + public: + // TODO: Copy constructor/equals here. + virtual ~TiffEntry(); + + /** + * Write the 12-byte IFD entry to the output. The given offset will be + * set as the tag value if the size of the tag value exceeds the max + * size for the TIFF Value field (4 bytes), and should be word aligned. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t writeTagInfo(uint32_t offset, /*out*/EndianOutput* out) const = 0; + + /** + * Get the count set for this entry. This corresponds to the TIFF Count + * field. + */ + virtual uint32_t getCount() const = 0; + + /** + * Get the tag id set for this entry. This corresponds to the TIFF Tag + * field. + */ + virtual uint16_t getTag() const = 0; + + /** + * Get the type set for this entry. This corresponds to the TIFF Type + * field. + */ + virtual TagType getType() const = 0; + + /** + * Get the defined endianness for this entry. If this is defined, + * the tag value will be written with the given byte order. + */ + virtual Endianness getEndianness() const = 0; + + /** + * Get the value for this entry. This corresponds to the TIFF Value + * field. + * + * Returns NULL if the value is NULL, or if the type used does not + * match the type of this tag. + */ + template + const T* getData() const; + + String8 toString() const; + + /** + * Force the type used here to be a valid TIFF type. + * + * Returns NULL if the given value is NULL, or if the type given does + * not match the type of the value given. + */ + template + static const T* forceValidType(TagType type, const T* value); + + virtual const void* getDataHelper() const = 0; + + COMPARE_DEF(>) + COMPARE_DEF(<) + + protected: + enum { + MAX_PRINT_STRING_LENGTH = 256 + }; +}; + +#define COMPARE(op) \ +bool TiffEntry::operator op (const TiffEntry& entry) const { \ + return getComparableValue() op entry.getComparableValue(); \ +} + +COMPARE(>) +COMPARE(<) + + +template +const T* TiffEntry::getData() const { + const T* value = reinterpret_cast(getDataHelper()); + return forceValidType(getType(), value); +} + +#undef COMPARE +#undef COMPARE_DEF + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_TIFF_ENTRY*/ diff --git a/media/img_utils/include/img_utils/TiffEntryImpl.h b/media/img_utils/include/img_utils/TiffEntryImpl.h new file mode 100644 index 0000000..0e713dc --- /dev/null +++ b/media/img_utils/include/img_utils/TiffEntryImpl.h @@ -0,0 +1,190 @@ +/* + * Copyright 2014 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 IMG_UTILS_TIFF_ENTRY_IMPL +#define IMG_UTILS_TIFF_ENTRY_IMPL + +#include +#include +#include +#include + +#include +#include +#include + +namespace android { +namespace img_utils { + +template +class TiffEntryImpl : public TiffEntry { + public: + // TODO: Copy constructor/equals here. + TiffEntryImpl(uint16_t tag, TagType type, uint32_t count, Endianness end, const T* data); + virtual ~TiffEntryImpl(); + + status_t writeData(uint32_t offset, /*out*/EndianOutput* out) const; + status_t writeTagInfo(uint32_t offset, /*out*/EndianOutput* out) const; + + uint32_t getCount() const; + uint16_t getTag() const; + TagType getType() const; + Endianness getEndianness() const; + uint32_t getSize() const; + uint32_t getComparableValue() const; + + protected: + const void* getDataHelper() const; + uint32_t getActualSize() const; + + uint16_t mTag; + uint16_t mType; + uint32_t mCount; + Endianness mEnd; + T* mData; + +}; + +template +TiffEntryImpl::TiffEntryImpl(uint16_t tag, TagType type, uint32_t count, Endianness end, + const T* data) + : mTag(tag), mType(static_cast(type)), mCount(count), mEnd(end) { + count = (type == RATIONAL || type == SRATIONAL) ? count * 2 : count; + mData = new T[count](); + for (uint32_t i = 0; i < count; ++i) { + mData[i] = data[i]; + } +} + +template +TiffEntryImpl::~TiffEntryImpl() { + if (mData) { + delete[] mData; + } +} + +template +uint32_t TiffEntryImpl::getCount() const { + return mCount; +} + +template +uint16_t TiffEntryImpl::getTag() const { + return mTag; +} + +template +TagType TiffEntryImpl::getType() const { + return static_cast(mType); +} + +template +const void* TiffEntryImpl::getDataHelper() const { + return reinterpret_cast(mData); +} + +template +uint32_t TiffEntryImpl::getSize() const { + uint32_t total = getActualSize(); + WORD_ALIGN(total) + return (total <= OFFSET_SIZE) ? 0 : total; +} + +template +uint32_t TiffEntryImpl::getActualSize() const { + uint32_t total = sizeof(T) * mCount; + if (getType() == RATIONAL || getType() == SRATIONAL) { + // 2 ints stored for each rational, multiply by 2 + total <<= 1; + } + return total; +} + +template +Endianness TiffEntryImpl::getEndianness() const { + return mEnd; +} + +template +uint32_t TiffEntryImpl::getComparableValue() const { + return mTag; +} + +template +status_t TiffEntryImpl::writeTagInfo(uint32_t offset, /*out*/EndianOutput* out) const { + assert((offset % TIFF_WORD_SIZE) == 0); + status_t ret = OK; + BAIL_ON_FAIL(out->write(&mTag, 0, 1), ret); + BAIL_ON_FAIL(out->write(&mType, 0, 1), ret); + BAIL_ON_FAIL(out->write(&mCount, 0, 1), ret); + + uint32_t dataSize = getActualSize(); + if (dataSize > OFFSET_SIZE) { + BAIL_ON_FAIL(out->write(&offset, 0, 1), ret); + } else { + uint32_t count = mCount; + if (getType() == RATIONAL || getType() == SRATIONAL) { + /** + * Rationals are stored as an array of ints. Each + * rational is represented by 2 ints. To recover the + * size of the array here, multiply the count by 2. + */ + count <<= 1; + } + BAIL_ON_FAIL(out->write(mData, 0, count), ret); + ZERO_TILL_WORD(out, dataSize, ret); + } + return ret; +} + +template +status_t TiffEntryImpl::writeData(uint32_t offset, EndianOutput* out) const { + status_t ret = OK; + + // Some tags have fixed-endian value output + Endianness tmp = UNDEFINED_ENDIAN; + if (mEnd != UNDEFINED_ENDIAN) { + tmp = out->getEndianness(); + out->setEndianness(mEnd); + } + + uint32_t count = mCount; + if (getType() == RATIONAL || getType() == SRATIONAL) { + /** + * Rationals are stored as an array of ints. Each + * rational is represented by 2 ints. To recover the + * size of the array here, multiply the count by 2. + */ + count <<= 1; + } + + BAIL_ON_FAIL(out->write(mData, 0, count), ret); + + if (mEnd != UNDEFINED_ENDIAN) { + out->setEndianness(tmp); + } + + // Write to next word alignment + ZERO_TILL_WORD(out, sizeof(T) * count, ret); + return ret; +} + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_TIFF_ENTRY_IMPL*/ + + diff --git a/media/img_utils/include/img_utils/TiffHelpers.h b/media/img_utils/include/img_utils/TiffHelpers.h new file mode 100644 index 0000000..fd0ea7a --- /dev/null +++ b/media/img_utils/include/img_utils/TiffHelpers.h @@ -0,0 +1,132 @@ +/* + * Copyright 2014 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 IMG_UTILS_TIFF_HELPERS_H +#define IMG_UTILS_TIFF_HELPERS_H + +#include + +namespace android { +namespace img_utils { + +const uint8_t ZERO_WORD[] = {0, 0, 0, 0}; + +#define BAIL_ON_FAIL(x, flag) \ + if ((flag = (x)) != OK) return flag; + +#define BYTES_TILL_WORD(index) \ + ((TIFF_WORD_SIZE - ((index) % TIFF_WORD_SIZE)) % TIFF_WORD_SIZE) + +#define WORD_ALIGN(count) \ + count += BYTES_TILL_WORD(count); + +#define ZERO_TILL_WORD(output, index, ret) \ + { \ + size_t remaining = BYTES_TILL_WORD(index); \ + if (remaining > 0) { \ + BAIL_ON_FAIL(output->write(ZERO_WORD, 0, remaining), ret); \ + } \ + } + +/** + * Basic TIFF header constants. + */ +enum { + BAD_OFFSET = 0, + TIFF_WORD_SIZE = 4, // Size in bytes + IFD_HEADER_SIZE = 2, // Size in bytes + IFD_FOOTER_SIZE = 4, // Size in bytes + TIFF_ENTRY_SIZE = 12, // Size in bytes + MAX_IFD_ENTRIES = UINT16_MAX, + FILE_HEADER_SIZE = 8, // Size in bytes + ENDIAN_MARKER_SIZE = 2, // Size in bytes + TIFF_MARKER_SIZE = 2, // Size in bytes + OFFSET_MARKER_SIZE = 4, // Size in bytes + TIFF_FILE_MARKER = 42, + BIG_ENDIAN_MARKER = 0x4D4Du, + LITTLE_ENDIAN_MARKER = 0x4949u +}; + +/** + * Constants for the TIFF tag types. + */ +enum TagType { + UNKNOWN_TAGTYPE = 0, + BYTE=1, + ASCII, + SHORT, + LONG, + RATIONAL, + SBYTE, + UNDEFINED, + SSHORT, + SLONG, + SRATIONAL, + FLOAT, + DOUBLE +}; + +/** + * Sizes of the TIFF entry fields (in bytes). + */ +enum { + TAG_SIZE = 2, + TYPE_SIZE = 2, + COUNT_SIZE = 4, + OFFSET_SIZE = 4 +}; + +/** + * Convenience IFD id constants. + */ +enum { + IFD_0 = 0, + RAW_IFD, + PROFILE_IFD, + PREVIEW_IFD +}; + +inline size_t getTypeSize(TagType type) { + switch(type) { + case UNDEFINED: + case ASCII: + case BYTE: + case SBYTE: + return 1; + case SHORT: + case SSHORT: + return 2; + case LONG: + case SLONG: + case FLOAT: + return 4; + case RATIONAL: + case SRATIONAL: + case DOUBLE: + return 8; + default: + return 0; + } +} + +inline uint32_t calculateIfdSize(size_t numberOfEntries) { + return IFD_HEADER_SIZE + IFD_FOOTER_SIZE + TIFF_ENTRY_SIZE * numberOfEntries; +} + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_TIFF_HELPERS_H*/ diff --git a/media/img_utils/include/img_utils/TiffIfd.h b/media/img_utils/include/img_utils/TiffIfd.h new file mode 100644 index 0000000..c35f858 --- /dev/null +++ b/media/img_utils/include/img_utils/TiffIfd.h @@ -0,0 +1,124 @@ +/* + * Copyright 2014 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 IMG_UTILS_TIFF_IFD_H +#define IMG_UTILS_TIFF_IFD_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace android { +namespace img_utils { + +/** + * This class holds a single TIFF Image File Directory (IFD) structure. + * + * This maps to the TIFF IFD structure that is logically composed of: + * - A 2-byte field listing the number of entries. + * - A list of 12-byte TIFF entries. + * - A 4-byte offset to the next IFD. + */ +class ANDROID_API TiffIfd : public TiffWritable { + public: + // TODO: Copy constructor/equals here - needed for SubIfds. + TiffIfd(uint32_t ifdId); + virtual ~TiffIfd(); + + /** + * Add a TiffEntry to this IFD or replace an existing entry with the + * same tag ID. No validation is done. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t addEntry(const sp& entry); + + /** + * Set the pointer to the next IFD. This is used to create a linked + * list of IFDs as defined by the TIFF 6.0 spec., and is not included + * when calculating the size of IFD and entries for the getSize() + * method (unlike SubIFDs). + */ + virtual void setNextIfd(const sp& ifd); + + /** + * Get the pointer to the next IFD, or NULL if none exists. + */ + virtual sp getNextIfd() const; + + /** + * Write the IFD data. This includes the IFD header, entries, footer, + * and the corresponding values for each entry (recursively including + * sub-IFDs). The written amount should end on a word boundary, and + * the given offset should be word aligned. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t writeData(uint32_t offset, /*out*/EndianOutput* out) const; + + /** + * Get the size of the IFD. This includes the IFD header, entries, footer, + * and the corresponding values for each entry (recursively including + * any sub-IFDs). + */ + virtual uint32_t getSize() const; + + /** + * Get the id of this IFD. + */ + virtual uint32_t getId() const; + + /** + * Get an entry with the given tag ID. + * + * Returns a strong pointer to the entry if it exists, or an empty strong + * pointer. + */ + virtual sp getEntry(uint16_t tag) const; + + /** + * Get a formatted string representing this IFD. + */ + String8 toString() const; + + /** + * Print a formatted string representing this IFD to logcat. + */ + void log() const; + + /** + * Get value used to determine sort order. + */ + virtual uint32_t getComparableValue() const; + protected: + virtual uint32_t checkAndGetOffset(uint32_t offset) const; + SortedEntryVector mEntries; + sp mNextIfd; + uint32_t mIfdId; +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_TIFF_IFD_H*/ diff --git a/media/img_utils/include/img_utils/TiffWritable.h b/media/img_utils/include/img_utils/TiffWritable.h new file mode 100644 index 0000000..a72cecc --- /dev/null +++ b/media/img_utils/include/img_utils/TiffWritable.h @@ -0,0 +1,60 @@ +/* + * Copyright 2014 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 IMG_UTILS_TIFF_WRITABLE +#define IMG_UTILS_TIFF_WRITABLE + +#include +#include +#include + +#include +#include +#include +#include + +namespace android { +namespace img_utils { + +/** + * TiffWritable subclasses represent TIFF metadata objects that can be written + * to an EndianOutput object. This is used for TIFF entries and IFDs. + */ +class ANDROID_API TiffWritable : public Orderable, public LightRefBase { + public: + TiffWritable(); + virtual ~TiffWritable(); + + /** + * Write the data to the output. The given offset is used to calculate + * the header offset for values written. The offset is defined + * relative to the beginning of the TIFF header, and is word aligned. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t writeData(uint32_t offset, /*out*/EndianOutput* out) const = 0; + + /** + * Get the size of the data to write. + */ + virtual size_t getSize() const = 0; + +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_TIFF_WRITABLE*/ diff --git a/media/img_utils/include/img_utils/TiffWriter.h b/media/img_utils/include/img_utils/TiffWriter.h new file mode 100644 index 0000000..ec27fc3 --- /dev/null +++ b/media/img_utils/include/img_utils/TiffWriter.h @@ -0,0 +1,267 @@ +/* + * Copyright 2014 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 IMG_UTILS_TIFF_WRITER_H +#define IMG_UTILS_TIFF_WRITER_H + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace android { +namespace img_utils { + +class TiffEntry; +class TiffIfd; +class Output; + +/** + * This class holds a collection of TIFF IFDs that can be written as a + * complete DNG file header. + * + * This maps to the TIFF header structure that is logically composed of: + * - An 8-byte file header containing an endianness indicator, the TIFF + * file marker, and the offset to the first IFD. + * - A list of TIFF IFD structures. + */ +class ANDROID_API TiffWriter : public LightRefBase { + public: + + /** + * Constructs a TiffWriter with the default tag mappings. This enables + * all of the tags defined in TagDefinitions.h, and uses the following + * mapping precedence to resolve collisions: + * (highest precedence) TIFF/EP > DNG > EXIF 2.3 > TIFF 6.0 + */ + TiffWriter(); + + /** + * Constructs a TiffWriter with the given tag mappings. The mapping + * precedence will be in the order that the definition maps are given, + * where the lower index map gets precedence. + * + * This can be used with user-defined definitions, or definitions form + * TagDefinitions.h + * + * The enabledDefinitions mapping object is owned by the caller, and must + * stay alive for the lifespan of the constructed TiffWriter object. + */ + TiffWriter(KeyedVector* enabledDefinitions, + size_t length); + + virtual ~TiffWriter(); + + /** + * Write a TIFF header containing each IFD set. This will recursively + * write all SubIFDs and tags. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t write(Output* out, Endianness end = LITTLE); + + /** + * Get the total size in bytes of the TIFF header. This includes all + * IFDs, tags, and values set for this TiffWriter. + */ + virtual uint32_t getTotalSize() const; + + /** + * Add the given entry to its default IFD. If that IFD does not + * exist, it will be created. + */ + virtual status_t addEntry(const sp& entry); + + /** + * Build an entry for a known tag. This tag must be one of the tags + * defined in one of the definition vectors this TIFF writer was constructed + * with. The count and type are validated. If this succeeds, the resulting + * entry will be placed in the outEntry pointer. + * + * Returns OK on success, or a negative error code on failure. Valid + * error codes for this method are: + * - BAD_INDEX - The given tag doesn't exist. + * - BAD_VALUE - The given count doesn't match the required count for + * this tag. + * - BAD_TYPE - The type of the given data isn't compatible with the + * type required for this tag. + */ + template + status_t buildEntry(uint16_t tag, uint32_t count, const T* data, + /*out*/sp* outEntry) const; + + /** + * Build an entry for a known tag and add it to the IFD with the given ID. + * This tag must be defined in one of the definition vectors this TIFF writer + * was constructed with. The count and type are validated. If this succeeds, + * the resulting entry will be placed in the outEntry pointer. + * + * Returns OK on success, or a negative error code on failure. Valid + * error codes for this method are: + * - BAD_INDEX - The given tag doesn't exist. + * - BAD_VALUE - The given count doesn't match the required count for + * this tag. + * - BAD_TYPE - The type of the given data isn't compatible with the + * type required for this tag. + * - NAME_NOT_FOUND - No ifd exists with the given ID. + */ + template + status_t addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd); + + /** + * Return the TIFF entry with the given tag ID in the IFD with the given ID, + * or an empty pointer if none exists. + */ + virtual sp getEntry(uint16_t tag, uint32_t ifd) const; + + /** + * Add the given IFD to the end of the top-level IFD chain. No + * validation is done. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t uncheckedAddIfd(const sp& ifd); + + /** + * Create an empty IFD with the given ID and add it to the end of the + * list of IFDs. + */ + virtual status_t addIfd(uint32_t ifd); + + /** + * Build an entry. No validation is done. + * + * WARNING: Using this method can result in creating poorly formatted + * TIFF files. + * + * Returns a TiffEntry with the given tag, type, count, endianness, + * and data. + */ + template + static sp uncheckedBuildEntry(uint16_t tag, TagType type, + uint32_t count, Endianness end, const T* data); + + /** + * Utility function to build atag-to-definition mapping from a given + * array of tag definitions. + */ + static KeyedVector buildTagMap( + const TagDefinition_t* definitions, size_t length); + + /** + * Returns the default type for the given tag ID. + */ + virtual TagType getDefaultType(uint16_t tag) const; + + /** + * Returns the default count for a given tag ID, or 0 if this + * tag normally has a variable count. + */ + virtual uint32_t getDefaultCount(uint16_t tag) const; + + /** + * Returns true if a definition exist for the given tag ID. + */ + virtual bool checkIfDefined(uint16_t tag) const; + + /** + * Print the currently configured IFDs and entries to logcat. + */ + virtual void log() const; + + protected: + enum { + DEFAULT_NUM_TAG_MAPS = 4, + }; + + sp findLastIfd(); + status_t writeFileHeader(EndianOutput& out); + const TagDefinition_t* lookupDefinition(uint16_t tag) const; + status_t calculateOffsets(); + + sp mIfd; + KeyedVector > mNamedIfds; + KeyedVector* mTagMaps; + size_t mNumTagMaps; + + static KeyedVector sTagMaps[]; +}; + +template +status_t TiffWriter::buildEntry(uint16_t tag, uint32_t count, const T* data, + /*out*/sp* outEntry) const { + const TagDefinition_t* definition = lookupDefinition(tag); + + if (definition == NULL) { + ALOGE("%s: No such tag exists for id %x.", __FUNCTION__, tag); + return BAD_INDEX; + } + + uint32_t fixedCount = definition->fixedCount; + if (fixedCount > 0 && fixedCount != count) { + ALOGE("%s: Invalid count %d for tag %x (expects %d).", __FUNCTION__, count, tag, + fixedCount); + return BAD_VALUE; + } + + TagType fixedType = definition->defaultType; + if (TiffEntry::forceValidType(fixedType, data) == NULL) { + ALOGE("%s: Invalid type used for tag value for tag %x.", __FUNCTION__, tag); + return BAD_TYPE; + } + + *outEntry = new TiffEntryImpl(tag, fixedType, count, + definition->fixedEndian, data); + + return OK; +} + +template +status_t TiffWriter::addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd) { + sp outEntry; + status_t ret = buildEntry(tag, count, data, &outEntry); + if (ret != OK) { + ALOGE("%s: Could not build entry for tag %x.", __FUNCTION__, tag); + return ret; + } + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index < 0) { + ALOGE("%s: No IFD %d set for this writer.", __FUNCTION__, ifd); + return NAME_NOT_FOUND; + } + return mNamedIfds[index]->addEntry(outEntry); +} + +template +sp TiffWriter::uncheckedBuildEntry(uint16_t tag, TagType type, uint32_t count, + Endianness end, const T* data) { + TiffEntryImpl* entry = new TiffEntryImpl(tag, type, count, end, data); + return sp(entry); +} + +} /*namespace img_utils*/ +} /*namespace android*/ + + +#endif /*IMG_UTILS_TIFF_WRITER_H*/ diff --git a/media/img_utils/src/Android.mk b/media/img_utils/src/Android.mk new file mode 100644 index 0000000..80893be --- /dev/null +++ b/media/img_utils/src/Android.mk @@ -0,0 +1,61 @@ +# Copyright 2014 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + EndianUtils.cpp \ + FileInput.cpp \ + FileOutput.cpp \ + SortedEntryVector.cpp \ + Input.cpp \ + Output.cpp \ + Orderable.cpp \ + TiffIfd.cpp \ + TiffWritable.cpp \ + TiffWriter.cpp \ + TiffEntry.cpp \ + TiffEntryImpl.cpp \ + ByteArrayOutput.cpp \ + DngUtils.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libexpat \ + libutils \ + libcutils \ + libcamera_metadata \ + libcamera_client + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/../include \ + system/media/camera/include + +LOCAL_CFLAGS += \ + -Wall \ + -Wextra \ + -Werror \ + -fvisibility=hidden + +ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),) + # Enable assert() in eng builds + LOCAL_CFLAGS += -UNDEBUG -DLOG_NDEBUG=1 +endif + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include + +LOCAL_MODULE := libimg_utils + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/img_utils/src/ByteArrayOutput.cpp b/media/img_utils/src/ByteArrayOutput.cpp new file mode 100644 index 0000000..db2d248 --- /dev/null +++ b/media/img_utils/src/ByteArrayOutput.cpp @@ -0,0 +1,54 @@ +/* + * Copyright 2014 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 + +#include + +namespace android { +namespace img_utils { + +ByteArrayOutput::ByteArrayOutput() {} + +ByteArrayOutput::~ByteArrayOutput() {} + +status_t ByteArrayOutput::open() { + return OK; +} + +status_t ByteArrayOutput::write(const uint8_t* buf, size_t offset, size_t count) { + if (mByteArray.appendArray(buf + offset, count) < 0) { + ALOGE("%s: Failed to write to ByteArrayOutput.", __FUNCTION__); + return BAD_VALUE; + } + return OK; +} + +status_t ByteArrayOutput::close() { + mByteArray.clear(); + return OK; +} + +size_t ByteArrayOutput::getSize() const { + return mByteArray.size(); +} + +const uint8_t* ByteArrayOutput::getArray() const { + return mByteArray.array(); +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp new file mode 100644 index 0000000..788dfc8 --- /dev/null +++ b/media/img_utils/src/DngUtils.cpp @@ -0,0 +1,280 @@ +/* + * Copyright 2014 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 + +namespace android { +namespace img_utils { + +OpcodeListBuilder::OpcodeListBuilder() : mOpList(), mEndianOut(&mOpList, BIG) { + if(mEndianOut.open() != OK) { + ALOGE("%s: Open failed.", __FUNCTION__); + } +} + +OpcodeListBuilder::~OpcodeListBuilder() { + if(mEndianOut.close() != OK) { + ALOGE("%s: Close failed.", __FUNCTION__); + } +} + +size_t OpcodeListBuilder::getSize() const { + return mOpList.getSize() + sizeof(mCount); +} + +uint32_t OpcodeListBuilder::getCount() const { + return mCount; +} + +status_t OpcodeListBuilder::buildOpList(uint8_t* buf) const { + uint32_t count = convertToBigEndian(mCount); + memcpy(buf, &count, sizeof(count)); + memcpy(buf + sizeof(count), mOpList.getArray(), mOpList.getSize()); + return OK; +} + +status_t OpcodeListBuilder::addGainMapsForMetadata(uint32_t lsmWidth, + uint32_t lsmHeight, + uint32_t activeAreaTop, + uint32_t activeAreaLeft, + uint32_t activeAreaBottom, + uint32_t activeAreaRight, + CfaLayout cfa, + const float* lensShadingMap) { + uint32_t activeAreaWidth = activeAreaRight - activeAreaLeft; + uint32_t activeAreaHeight = activeAreaBottom - activeAreaTop; + double spacingV = 1.0 / lsmHeight; + double spacingH = 1.0 / lsmWidth; + + float redMap[lsmWidth * lsmHeight]; + float greenEvenMap[lsmWidth * lsmHeight]; + float greenOddMap[lsmWidth * lsmHeight]; + float blueMap[lsmWidth * lsmHeight]; + + size_t lsmMapSize = lsmWidth * lsmHeight * 4; + + // Split lens shading map channels into separate arrays + size_t j = 0; + for (size_t i = 0; i < lsmMapSize; i += 4, ++j) { + redMap[j] = lensShadingMap[i + LSM_R_IND]; + greenEvenMap[j] = lensShadingMap[i + LSM_GE_IND]; + greenOddMap[j] = lensShadingMap[i + LSM_GO_IND]; + blueMap[j] = lensShadingMap[i + LSM_B_IND]; + } + + uint32_t redTop = 0; + uint32_t redLeft = 0; + uint32_t greenEvenTop = 0; + uint32_t greenEvenLeft = 1; + uint32_t greenOddTop = 1; + uint32_t greenOddLeft = 0; + uint32_t blueTop = 1; + uint32_t blueLeft = 1; + + switch(cfa) { + case CFA_RGGB: + redTop = 0; + redLeft = 0; + greenEvenTop = 0; + greenEvenLeft = 1; + greenOddTop = 1; + greenOddLeft = 0; + blueTop = 1; + blueLeft = 1; + break; + case CFA_GRBG: + redTop = 0; + redLeft = 1; + greenEvenTop = 0; + greenEvenLeft = 0; + greenOddTop = 1; + greenOddLeft = 1; + blueTop = 1; + blueLeft = 0; + break; + case CFA_GBRG: + redTop = 1; + redLeft = 0; + greenEvenTop = 0; + greenEvenLeft = 0; + greenOddTop = 1; + greenOddLeft = 1; + blueTop = 0; + blueLeft = 1; + break; + case CFA_BGGR: + redTop = 1; + redLeft = 1; + greenEvenTop = 0; + greenEvenLeft = 1; + greenOddTop = 1; + greenOddLeft = 0; + blueTop = 0; + blueLeft = 0; + break; + default: + ALOGE("%s: Unknown CFA layout %d", __FUNCTION__, cfa); + return BAD_VALUE; + } + + status_t err = addGainMap(/*top*/redTop, + /*left*/redLeft, + /*bottom*/activeAreaHeight - 1, + /*right*/activeAreaWidth - 1, + /*plane*/0, + /*planes*/1, + /*rowPitch*/2, + /*colPitch*/2, + /*mapPointsV*/lsmHeight, + /*mapPointsH*/lsmWidth, + /*mapSpacingV*/spacingV, + /*mapSpacingH*/spacingH, + /*mapOriginV*/0, + /*mapOriginH*/0, + /*mapPlanes*/1, + /*mapGains*/redMap); + if (err != OK) return err; + + err = addGainMap(/*top*/greenEvenTop, + /*left*/greenEvenLeft, + /*bottom*/activeAreaHeight - 1, + /*right*/activeAreaWidth - 1, + /*plane*/0, + /*planes*/1, + /*rowPitch*/2, + /*colPitch*/2, + /*mapPointsV*/lsmHeight, + /*mapPointsH*/lsmWidth, + /*mapSpacingV*/spacingV, + /*mapSpacingH*/spacingH, + /*mapOriginV*/0, + /*mapOriginH*/0, + /*mapPlanes*/1, + /*mapGains*/greenEvenMap); + if (err != OK) return err; + + err = addGainMap(/*top*/greenOddTop, + /*left*/greenOddLeft, + /*bottom*/activeAreaHeight - 1, + /*right*/activeAreaWidth - 1, + /*plane*/0, + /*planes*/1, + /*rowPitch*/2, + /*colPitch*/2, + /*mapPointsV*/lsmHeight, + /*mapPointsH*/lsmWidth, + /*mapSpacingV*/spacingV, + /*mapSpacingH*/spacingH, + /*mapOriginV*/0, + /*mapOriginH*/0, + /*mapPlanes*/1, + /*mapGains*/greenOddMap); + if (err != OK) return err; + + err = addGainMap(/*top*/blueTop, + /*left*/blueLeft, + /*bottom*/activeAreaHeight - 1, + /*right*/activeAreaWidth - 1, + /*plane*/0, + /*planes*/1, + /*rowPitch*/2, + /*colPitch*/2, + /*mapPointsV*/lsmHeight, + /*mapPointsH*/lsmWidth, + /*mapSpacingV*/spacingV, + /*mapSpacingH*/spacingH, + /*mapOriginV*/0, + /*mapOriginH*/0, + /*mapPlanes*/1, + /*mapGains*/blueMap); + return err; +} + +status_t OpcodeListBuilder::addGainMap(uint32_t top, + uint32_t left, + uint32_t bottom, + uint32_t right, + uint32_t plane, + uint32_t planes, + uint32_t rowPitch, + uint32_t colPitch, + uint32_t mapPointsV, + uint32_t mapPointsH, + double mapSpacingV, + double mapSpacingH, + double mapOriginV, + double mapOriginH, + uint32_t mapPlanes, + const float* mapGains) { + + uint32_t opcodeId = GAIN_MAP_ID; + + status_t err = mEndianOut.write(&opcodeId, 0, 1); + if (err != OK) return err; + + uint8_t version[] = {1, 3, 0, 0}; + err = mEndianOut.write(version, 0, NELEMS(version)); + if (err != OK) return err; + + uint32_t flags = FLAG_OPTIONAL | FLAG_OPTIONAL_FOR_PREVIEW; + err = mEndianOut.write(&flags, 0, 1); + if (err != OK) return err; + + const uint32_t NUMBER_INT_ARGS = 11; + const uint32_t NUMBER_DOUBLE_ARGS = 4; + + uint32_t totalSize = NUMBER_INT_ARGS * sizeof(uint32_t) + NUMBER_DOUBLE_ARGS * sizeof(double) + + mapPointsV * mapPointsH * mapPlanes * sizeof(float); + + err = mEndianOut.write(&totalSize, 0, 1); + if (err != OK) return err; + + // Batch writes as much as possible + uint32_t settings1[] = { top, + left, + bottom, + right, + plane, + planes, + rowPitch, + colPitch, + mapPointsV, + mapPointsH }; + + err = mEndianOut.write(settings1, 0, NELEMS(settings1)); + if (err != OK) return err; + + double settings2[] = { mapSpacingV, + mapSpacingH, + mapOriginV, + mapOriginH }; + + err = mEndianOut.write(settings2, 0, NELEMS(settings2)); + if (err != OK) return err; + + err = mEndianOut.write(&mapPlanes, 0, 1); + if (err != OK) return err; + + err = mEndianOut.write(mapGains, 0, mapPointsV * mapPointsH * mapPlanes); + if (err != OK) return err; + + mCount++; + + return OK; +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/EndianUtils.cpp b/media/img_utils/src/EndianUtils.cpp new file mode 100644 index 0000000..8681cbe --- /dev/null +++ b/media/img_utils/src/EndianUtils.cpp @@ -0,0 +1,83 @@ +/* + * Copyright 2014 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 + +namespace android { +namespace img_utils { + +EndianOutput::EndianOutput(Output* out, Endianness end) + : mOffset(0), mOutput(out), mEndian(end) {} + +EndianOutput::~EndianOutput() {} + +status_t EndianOutput::open() { + mOffset = 0; + return mOutput->open(); +} + +status_t EndianOutput::close() { + return mOutput->close(); +} + +void EndianOutput::setEndianness(Endianness end) { + mEndian = end; +} + +uint32_t EndianOutput::getCurrentOffset() const { + return mOffset; +} + +Endianness EndianOutput::getEndianness() const { + return mEndian; +} + +status_t EndianOutput::write(const uint8_t* buf, size_t offset, size_t count) { + status_t res = OK; + if((res = mOutput->write(buf, offset, count)) == OK) { + mOffset += count; + } + return res; +} + +status_t EndianOutput::write(const int8_t* buf, size_t offset, size_t count) { + return write(reinterpret_cast(buf), offset, count); +} + +#define DEFINE_WRITE(_type_) \ +status_t EndianOutput::write(const _type_* buf, size_t offset, size_t count) { \ + return writeHelper<_type_>(buf, offset, count); \ +} + +DEFINE_WRITE(uint16_t) +DEFINE_WRITE(int16_t) +DEFINE_WRITE(uint32_t) +DEFINE_WRITE(int32_t) +DEFINE_WRITE(uint64_t) +DEFINE_WRITE(int64_t) + +status_t EndianOutput::write(const float* buf, size_t offset, size_t count) { + assert(sizeof(float) == sizeof(uint32_t)); + return writeHelper(reinterpret_cast(buf), offset, count); +} + +status_t EndianOutput::write(const double* buf, size_t offset, size_t count) { + assert(sizeof(double) == sizeof(uint64_t)); + return writeHelper(reinterpret_cast(buf), offset, count); +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/FileInput.cpp b/media/img_utils/src/FileInput.cpp new file mode 100644 index 0000000..e43fd53 --- /dev/null +++ b/media/img_utils/src/FileInput.cpp @@ -0,0 +1,80 @@ +/* + * Copyright 2014 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 + +#include + +namespace android { +namespace img_utils { + +FileInput::FileInput(String8 path) : mFp(NULL), mPath(path), mOpen(false) {} + +FileInput::~FileInput() { + if (mOpen) { + ALOGE("%s: FileInput destroyed without calling close!", __FUNCTION__); + close(); + } + +} + +status_t FileInput::open() { + if (mOpen) { + ALOGW("%s: Open called when file %s already open.", __FUNCTION__, mPath.string()); + return OK; + } + mFp = ::fopen(mPath, "rb"); + if (!mFp) { + ALOGE("%s: Could not open file %s", __FUNCTION__, mPath.string()); + return BAD_VALUE; + } + mOpen = true; + return OK; +} + +size_t FileInput::read(uint8_t* buf, size_t offset, size_t count, status_t* err) { + if (!mOpen) { + ALOGE("%s: Could not read file %s, file not open.", __FUNCTION__, mPath.string()); + if (err != NULL) *err = BAD_VALUE; + return 0; + } + + size_t bytesRead = ::fread(buf + offset, sizeof(uint8_t), count, mFp); + int error = ::ferror(mFp); + if (error != 0) { + ALOGE("%s: Error %d occurred while reading file %s.", __FUNCTION__, error, mPath.string()); + if (err != NULL) *err = BAD_VALUE; + } + return bytesRead; +} + +status_t FileInput::close() { + if(!mOpen) { + ALOGW("%s: Close called when file %s already close.", __FUNCTION__, mPath.string()); + return OK; + } + + status_t ret = OK; + if(::fclose(mFp) != 0) { + ALOGE("%s: Failed to close file %s.", __FUNCTION__, mPath.string()); + ret = BAD_VALUE; + } + mOpen = false; + return OK; +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/FileOutput.cpp b/media/img_utils/src/FileOutput.cpp new file mode 100644 index 0000000..ce763ff --- /dev/null +++ b/media/img_utils/src/FileOutput.cpp @@ -0,0 +1,79 @@ +/* + * Copyright 2014 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 + +#include + +namespace android { +namespace img_utils { + +FileOutput::FileOutput(String8 path) : mFp(NULL), mPath(path), mOpen(false) {} + +FileOutput::~FileOutput() { + if (mOpen) { + ALOGW("%s: Destructor called with %s still open.", __FUNCTION__, mPath.string()); + close(); + } +} + +status_t FileOutput::open() { + if (mOpen) { + ALOGW("%s: Open called when file %s already open.", __FUNCTION__, mPath.string()); + return OK; + } + mFp = ::fopen(mPath, "wb"); + if (!mFp) { + ALOGE("%s: Could not open file %s", __FUNCTION__, mPath.string()); + return BAD_VALUE; + } + mOpen = true; + return OK; +} + +status_t FileOutput::write(const uint8_t* buf, size_t offset, size_t count) { + if (!mOpen) { + ALOGE("%s: Could not write file %s, file not open.", __FUNCTION__, mPath.string()); + return BAD_VALUE; + } + + ::fwrite(buf + offset, sizeof(uint8_t), count, mFp); + + int error = ::ferror(mFp); + if (error != 0) { + ALOGE("%s: Error %d occurred while writing file %s.", __FUNCTION__, error, mPath.string()); + return BAD_VALUE; + } + return OK; +} + +status_t FileOutput::close() { + if(!mOpen) { + ALOGW("%s: Close called when file %s already close.", __FUNCTION__, mPath.string()); + return OK; + } + + status_t ret = OK; + if(::fclose(mFp) != 0) { + ALOGE("%s: Failed to close file %s.", __FUNCTION__, mPath.string()); + ret = BAD_VALUE; + } + mOpen = false; + return OK; +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/Input.cpp b/media/img_utils/src/Input.cpp new file mode 100644 index 0000000..1e51e10 --- /dev/null +++ b/media/img_utils/src/Input.cpp @@ -0,0 +1,29 @@ +/* + * Copyright 2014 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 + +namespace android { +namespace img_utils { + +Input::~Input() {} +status_t Input::open() { return OK; } +status_t Input::close() { return OK; } + + +} /*namespace img_utils*/ +} /*namespace android*/ + diff --git a/media/img_utils/src/Orderable.cpp b/media/img_utils/src/Orderable.cpp new file mode 100644 index 0000000..300f122 --- /dev/null +++ b/media/img_utils/src/Orderable.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2014 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 + +#include + +namespace android { +namespace img_utils { + +#define COMPARE(op) \ +bool Orderable::operator op (const Orderable& orderable) const { \ + return getComparableValue() op orderable.getComparableValue(); \ +} + +COMPARE(>) +COMPARE(<) +COMPARE(>=) +COMPARE(<=) +COMPARE(==) +COMPARE(!=) + +Orderable::~Orderable() {} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/Output.cpp b/media/img_utils/src/Output.cpp new file mode 100644 index 0000000..0e395b9 --- /dev/null +++ b/media/img_utils/src/Output.cpp @@ -0,0 +1,28 @@ +/* + * Copyright 2014 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 + +namespace android { +namespace img_utils { + +Output::~Output() {} +status_t Output::open() { return OK; } +status_t Output::close() { return OK; } + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/SortedEntryVector.cpp b/media/img_utils/src/SortedEntryVector.cpp new file mode 100644 index 0000000..f0e1fa1 --- /dev/null +++ b/media/img_utils/src/SortedEntryVector.cpp @@ -0,0 +1,44 @@ +/* + * Copyright 2014 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 + +#include +#include + +namespace android { +namespace img_utils { + +SortedEntryVector::~SortedEntryVector() {} + +ssize_t SortedEntryVector::indexOfTag(uint16_t tag) const { + // TODO: Use binary search here. + for (size_t i = 0; i < size(); ++i) { + if (itemAt(i)->getTag() == tag) { + return i; + } + } + return -1; +} + +int SortedEntryVector::do_compare(const void* lhs, const void* rhs) const { + const sp* lEntry = reinterpret_cast*>(lhs); + const sp* rEntry = reinterpret_cast*>(rhs); + return compare_type(**lEntry, **rEntry); +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/TiffEntry.cpp b/media/img_utils/src/TiffEntry.cpp new file mode 100644 index 0000000..e028827 --- /dev/null +++ b/media/img_utils/src/TiffEntry.cpp @@ -0,0 +1,238 @@ +/* + * Copyright 2014 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 +#include +#include + +#include +#include +#include + +namespace android { +namespace img_utils { + +TiffEntry::~TiffEntry() {} + +/** + * Specialize for each valid type, including sub-IFDs. + * + * Values with types other than the ones given here should not compile. + */ +template<> +const Vector >* TiffEntry::forceValidType > >(TagType type, + const Vector >* value) { + if (type == LONG) { + return value; + } + ALOGE("%s: Value of type 'ifd vector' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const sp* TiffEntry::forceValidType >(TagType type, const sp* value) { + if (type == LONG) { + return value; + } + ALOGE("%s: Value of type 'ifd' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const uint8_t* TiffEntry::forceValidType(TagType type, const uint8_t* value) { + if (type == BYTE || type == ASCII || type == UNDEFINED) { + return value; + } + ALOGE("%s: Value of type 'uint8_t' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const int8_t* TiffEntry::forceValidType(TagType type, const int8_t* value) { + if (type == SBYTE || type == ASCII || type == UNDEFINED) { + return value; + } + ALOGE("%s: Value of type 'int8_t' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const uint16_t* TiffEntry::forceValidType(TagType type, const uint16_t* value) { + if (type == SHORT) { + return value; + } + ALOGE("%s: Value of type 'uint16_t' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const int16_t* TiffEntry::forceValidType(TagType type, const int16_t* value) { + if (type == SSHORT) { + return value; + } + ALOGE("%s: Value of type 'int16_t' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const uint32_t* TiffEntry::forceValidType(TagType type, const uint32_t* value) { + if (type == LONG || type == RATIONAL) { + return value; + } + ALOGE("%s: Value of type 'uint32_t' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const int32_t* TiffEntry::forceValidType(TagType type, const int32_t* value) { + if (type == SLONG || type == SRATIONAL) { + return value; + } + ALOGE("%s: Value of type 'int32_t' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const double* TiffEntry::forceValidType(TagType type, const double* value) { + if (type == DOUBLE) { + return value; + } + ALOGE("%s: Value of type 'double' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const float* TiffEntry::forceValidType(TagType type, const float* value) { + if (type == FLOAT) { + return value; + } + ALOGE("%s: Value of type 'float' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +String8 TiffEntry::toString() const { + String8 output; + uint32_t count = getCount(); + output.appendFormat("[id: %x, type: %d, count: %u, value: '", getTag(), getType(), count); + + size_t cappedCount = count; + if (count > MAX_PRINT_STRING_LENGTH) { + cappedCount = MAX_PRINT_STRING_LENGTH; + } + + TagType type = getType(); + switch (type) { + case UNDEFINED: + case BYTE: { + const uint8_t* typed_data = getData(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%u ", typed_data[i]); + } + break; + } + case ASCII: { + const char* typed_data = reinterpret_cast(getData()); + size_t len = count; + if (count > MAX_PRINT_STRING_LENGTH) { + len = MAX_PRINT_STRING_LENGTH; + } + output.append(typed_data, len); + break; + } + case SHORT: { + const uint16_t* typed_data = getData(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%u ", typed_data[i]); + } + break; + } + case LONG: { + const uint32_t* typed_data = getData(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%u ", typed_data[i]); + } + break; + } + case RATIONAL: { + const uint32_t* typed_data = getData(); + cappedCount <<= 1; + for (size_t i = 0; i < cappedCount; i+=2) { + output.appendFormat("%u/%u ", typed_data[i], typed_data[i + 1]); + } + break; + } + case SBYTE: { + const int8_t* typed_data = getData(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%d ", typed_data[i]); + } + break; + } + case SSHORT: { + const int16_t* typed_data = getData(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%d ", typed_data[i]); + } + break; + } + case SLONG: { + const int32_t* typed_data = getData(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%d ", typed_data[i]); + } + break; + } + case SRATIONAL: { + const int32_t* typed_data = getData(); + cappedCount <<= 1; + for (size_t i = 0; i < cappedCount; i+=2) { + output.appendFormat("%d/%d ", typed_data[i], typed_data[i + 1]); + } + break; + } + case FLOAT: + case DOUBLE: { + const float* typed_data = getData(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%f ", typed_data[i]); + } + break; + } + default: { + output.append("unknown type "); + break; + } + } + + if (count > MAX_PRINT_STRING_LENGTH) { + output.append("..."); + } + output.append("']"); + return output; +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/TiffEntryImpl.cpp b/media/img_utils/src/TiffEntryImpl.cpp new file mode 100644 index 0000000..2052ceb --- /dev/null +++ b/media/img_utils/src/TiffEntryImpl.cpp @@ -0,0 +1,44 @@ +/* + * Copyright 2014 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 +#include + +#include + +namespace android { +namespace img_utils { + +template<> +uint32_t TiffEntryImpl::getSize() const { + uint32_t total = 0; + for (uint32_t i = 0; i < mCount; ++i) { + total += mData[i].getSize(); + } + return total; +} + +template<> +status_t TiffEntryImpl::writeData(uint32_t offset, EndianOutput* out) const { + status_t ret = OK; + for (uint32_t i = 0; i < mCount; ++i) { + BAIL_ON_FAIL(mData[i].writeData(offset, out), ret); + } + return ret; +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/TiffIfd.cpp b/media/img_utils/src/TiffIfd.cpp new file mode 100644 index 0000000..b75309b --- /dev/null +++ b/media/img_utils/src/TiffIfd.cpp @@ -0,0 +1,182 @@ +/* + * Copyright 2014 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 +#include + +#include + +namespace android { +namespace img_utils { + +TiffIfd::TiffIfd(uint32_t ifdId) + : mNextIfd(), mIfdId(ifdId) {} + +TiffIfd::~TiffIfd() {} + +status_t TiffIfd::addEntry(const sp& entry) { + size_t size = mEntries.size(); + if (size >= MAX_IFD_ENTRIES) { + ALOGW("%s: Failed to add entry for tag 0x%x to IFD %d, too many entries in IFD!", + __FUNCTION__, entry->getTag(), mIfdId); + return BAD_INDEX; + } + + if (mEntries.add(entry) < 0) { + ALOGW("%s: Failed to add entry for tag 0x%x to ifd %d.", __FUNCTION__, entry->getTag(), + mIfdId); + return BAD_INDEX; + } + return OK; +} + +sp TiffIfd::getEntry(uint16_t tag) const { + ssize_t index = mEntries.indexOfTag(tag); + if (index < 0) { + ALOGW("%s: No entry for tag 0x%x in ifd %d.", __FUNCTION__, tag, mIfdId); + return NULL; + } + return mEntries[index]; +} + +void TiffIfd::setNextIfd(const sp& ifd) { + mNextIfd = ifd; +} + +sp TiffIfd::getNextIfd() const { + return mNextIfd; +} + +uint32_t TiffIfd::checkAndGetOffset(uint32_t offset) const { + size_t size = mEntries.size(); + + if (size > MAX_IFD_ENTRIES) { + ALOGW("%s: Could not calculate IFD offsets, IFD %d contains too many entries.", + __FUNCTION__, mIfdId); + return BAD_OFFSET; + } + + if (size <= 0) { + ALOGW("%s: Could not calculate IFD offsets, IFD %d contains no entries.", __FUNCTION__, + mIfdId); + return BAD_OFFSET; + } + + if (offset == BAD_OFFSET) { + ALOGW("%s: Could not calculate IFD offsets, IFD %d had a bad initial offset.", + __FUNCTION__, mIfdId); + return BAD_OFFSET; + } + + uint32_t ifdSize = calculateIfdSize(size); + WORD_ALIGN(ifdSize); + return offset + ifdSize; +} + +status_t TiffIfd::writeData(uint32_t offset, /*out*/EndianOutput* out) const { + assert((offset % TIFF_WORD_SIZE) == 0); + status_t ret = OK; + + ALOGV("%s: IFD %u written to offset %u", __FUNCTION__, mIfdId, offset ); + uint32_t valueOffset = checkAndGetOffset(offset); + if (valueOffset == 0) { + return BAD_VALUE; + } + + size_t size = mEntries.size(); + + // Writer IFD header (2 bytes, number of entries). + uint16_t header = static_cast(size); + BAIL_ON_FAIL(out->write(&header, 0, 1), ret); + + // Write tag entries + for (size_t i = 0; i < size; ++i) { + BAIL_ON_FAIL(mEntries[i]->writeTagInfo(valueOffset, out), ret); + valueOffset += mEntries[i]->getSize(); + } + + // Writer IFD footer (4 bytes, offset to next IFD). + uint32_t footer = (mNextIfd != NULL) ? offset + getSize() : 0; + BAIL_ON_FAIL(out->write(&footer, 0, 1), ret); + + assert(out->getCurrentOffset() == offset + calculateIfdSize(size)); + + // Write zeroes till word aligned + ZERO_TILL_WORD(out, calculateIfdSize(size), ret); + + // Write values for each tag entry + for (size_t i = 0; i < size; ++i) { + size_t last = out->getCurrentOffset(); + // Only write values that are too large to fit in the 12-byte TIFF entry + if (mEntries[i]->getSize() > OFFSET_SIZE) { + BAIL_ON_FAIL(mEntries[i]->writeData(out->getCurrentOffset(), out), ret); + } + size_t next = out->getCurrentOffset(); + size_t diff = (next - last); + size_t actual = mEntries[i]->getSize(); + if (diff != actual) { + ALOGW("Sizes do not match for tag %x. Expected %d, received %d", + mEntries[i]->getTag(), actual, diff); + } + } + + assert(out->getCurrentOffset() == offset + getSize()); + + return ret; +} + +uint32_t TiffIfd::getSize() const { + size_t size = mEntries.size(); + uint32_t total = calculateIfdSize(size); + WORD_ALIGN(total); + for (size_t i = 0; i < size; ++i) { + total += mEntries[i]->getSize(); + } + return total; +} + +uint32_t TiffIfd::getId() const { + return mIfdId; +} + +uint32_t TiffIfd::getComparableValue() const { + return mIfdId; +} + +String8 TiffIfd::toString() const { + size_t s = mEntries.size(); + String8 output; + output.appendFormat("[ifd: %x, num_entries: %u, entries:\n", getId(), s); + for(size_t i = 0; i < mEntries.size(); ++i) { + output.append("\t"); + output.append(mEntries[i]->toString()); + output.append("\n"); + } + output.append(", next_ifd: %x]", ((mNextIfd != NULL) ? mNextIfd->getId() : 0)); + return output; +} + +void TiffIfd::log() const { + size_t s = mEntries.size(); + ALOGI("[ifd: %x, num_entries: %u, entries:\n", getId(), s); + for(size_t i = 0; i < s; ++i) { + ALOGI("\t%s", mEntries[i]->toString().string()); + } + ALOGI(", next_ifd: %x]", ((mNextIfd != NULL) ? mNextIfd->getId() : 0)); +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/TiffWritable.cpp b/media/img_utils/src/TiffWritable.cpp new file mode 100644 index 0000000..f8d7de7 --- /dev/null +++ b/media/img_utils/src/TiffWritable.cpp @@ -0,0 +1,31 @@ +/* + * Copyright 2014 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 +#include + +#include + +namespace android { +namespace img_utils { + +TiffWritable::TiffWritable() {} + +TiffWritable::~TiffWritable() {} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/TiffWriter.cpp b/media/img_utils/src/TiffWriter.cpp new file mode 100644 index 0000000..2439033 --- /dev/null +++ b/media/img_utils/src/TiffWriter.cpp @@ -0,0 +1,232 @@ +/* + * Copyright 2014 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 +#include +#include +#include + +#include + +namespace android { +namespace img_utils { + +KeyedVector TiffWriter::buildTagMap( + const TagDefinition_t* definitions, size_t length) { + KeyedVector map; + for(size_t i = 0; i < length; ++i) { + map.add(definitions[i].tagId, definitions + i); + } + return map; +} + +#define COMPARE(op) \ +bool Orderable::operator op (const Orderable& orderable) const { \ + return getComparableValue() op orderable.getComparableValue(); \ +} + +#define ARRAY_SIZE(array) \ + (sizeof(array) / sizeof(array[0])) + +KeyedVector TiffWriter::sTagMaps[] = { + buildTagMap(TIFF_EP_TAG_DEFINITIONS, ARRAY_SIZE(TIFF_EP_TAG_DEFINITIONS)), + buildTagMap(DNG_TAG_DEFINITIONS, ARRAY_SIZE(DNG_TAG_DEFINITIONS)), + buildTagMap(EXIF_2_3_TAG_DEFINITIONS, ARRAY_SIZE(EXIF_2_3_TAG_DEFINITIONS)), + buildTagMap(TIFF_6_TAG_DEFINITIONS, ARRAY_SIZE(TIFF_6_TAG_DEFINITIONS)) +}; + +TiffWriter::TiffWriter() : mTagMaps(sTagMaps), mNumTagMaps(DEFAULT_NUM_TAG_MAPS) {} + +TiffWriter::TiffWriter(KeyedVector* enabledDefinitions, + size_t length) : mTagMaps(enabledDefinitions), mNumTagMaps(length) {} + +TiffWriter::~TiffWriter() {} + +status_t TiffWriter::write(Output* out, Endianness end) { + status_t ret = OK; + EndianOutput endOut(out, end); + + if (mIfd == NULL) { + ALOGE("%s: Tiff header is empty.", __FUNCTION__); + return BAD_VALUE; + } + BAIL_ON_FAIL(writeFileHeader(endOut), ret); + + uint32_t offset = FILE_HEADER_SIZE; + sp ifd = mIfd; + while(ifd != NULL) { + BAIL_ON_FAIL(ifd->writeData(offset, &endOut), ret); + offset += ifd->getSize(); + ifd = ifd->getNextIfd(); + } + return ret; +} + + +const TagDefinition_t* TiffWriter::lookupDefinition(uint16_t tag) const { + const TagDefinition_t* definition = NULL; + for (size_t i = 0; i < mNumTagMaps; ++i) { + ssize_t index = mTagMaps[i].indexOfKey(tag); + if (index >= 0) { + definition = mTagMaps[i][index]; + break; + } + } + + if (definition == NULL) { + ALOGE("%s: No definition exists for tag with id %x.", __FUNCTION__, tag); + } + return definition; +} + +sp TiffWriter::getEntry(uint16_t tag, uint32_t ifd) const { + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index < 0) { + ALOGE("%s: No IFD %d set for this writer.", __FUNCTION__, ifd); + return NULL; + } + return mNamedIfds[index]->getEntry(tag); +} + + +// TODO: Fix this to handle IFD position in chain/sub-IFD tree +status_t TiffWriter::addEntry(const sp& entry) { + uint16_t tag = entry->getTag(); + + const TagDefinition_t* definition = lookupDefinition(tag); + + if (definition == NULL) { + return BAD_INDEX; + } + uint32_t ifdId = 0; // TODO: all in IFD0 for now. + + ssize_t index = mNamedIfds.indexOfKey(ifdId); + + // Add a new IFD if necessary + if (index < 0) { + sp ifdEntry = new TiffIfd(ifdId); + if (mIfd == NULL) { + mIfd = ifdEntry; + } + index = mNamedIfds.add(ifdId, ifdEntry); + assert(index >= 0); + } + + sp selectedIfd = mNamedIfds[index]; + return selectedIfd->addEntry(entry); +} + +status_t TiffWriter::uncheckedAddIfd(const sp& ifd) { + mNamedIfds.add(ifd->getId(), ifd); + sp last = findLastIfd(); + if (last == NULL) { + mIfd = ifd; + } else { + last->setNextIfd(ifd); + } + last = ifd->getNextIfd(); + while (last != NULL) { + mNamedIfds.add(last->getId(), last); + last = last->getNextIfd(); + } + return OK; +} + +status_t TiffWriter::addIfd(uint32_t ifd) { + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index >= 0) { + ALOGE("%s: Ifd with ID 0x%x already exists.", __FUNCTION__, ifd); + return BAD_VALUE; + } + sp newIfd = new TiffIfd(ifd); + if (mIfd == NULL) { + mIfd = newIfd; + } else { + sp last = findLastIfd(); + last->setNextIfd(newIfd); + } + mNamedIfds.add(ifd, newIfd); + return OK; +} + +TagType TiffWriter::getDefaultType(uint16_t tag) const { + const TagDefinition_t* definition = lookupDefinition(tag); + if (definition == NULL) { + ALOGE("%s: Could not find definition for tag %x", __FUNCTION__, tag); + return UNKNOWN_TAGTYPE; + } + return definition->defaultType; +} + +uint32_t TiffWriter::getDefaultCount(uint16_t tag) const { + const TagDefinition_t* definition = lookupDefinition(tag); + if (definition == NULL) { + ALOGE("%s: Could not find definition for tag %x", __FUNCTION__, tag); + return 0; + } + return definition->fixedCount; +} + +bool TiffWriter::checkIfDefined(uint16_t tag) const { + return lookupDefinition(tag) != NULL; +} + +sp TiffWriter::findLastIfd() { + sp ifd = mIfd; + while(ifd != NULL) { + sp nextIfd = ifd->getNextIfd(); + if (nextIfd == NULL) { + break; + } + ifd = nextIfd; + } + return ifd; +} + +status_t TiffWriter::writeFileHeader(EndianOutput& out) { + status_t ret = OK; + uint16_t endMarker = (out.getEndianness() == BIG) ? BIG_ENDIAN_MARKER : LITTLE_ENDIAN_MARKER; + BAIL_ON_FAIL(out.write(&endMarker, 0, 1), ret); + + uint16_t tiffMarker = TIFF_FILE_MARKER; + BAIL_ON_FAIL(out.write(&tiffMarker, 0, 1), ret); + + uint32_t offsetMarker = FILE_HEADER_SIZE; + BAIL_ON_FAIL(out.write(&offsetMarker, 0, 1), ret); + return ret; +} + +uint32_t TiffWriter::getTotalSize() const { + uint32_t totalSize = FILE_HEADER_SIZE; + sp ifd = mIfd; + while(ifd != NULL) { + totalSize += ifd->getSize(); + ifd = ifd->getNextIfd(); + } + return totalSize; +} + +void TiffWriter::log() const { + ALOGI("%s: TiffWriter:", __FUNCTION__); + sp ifd = mIfd; + while(ifd != NULL) { + ifd->log(); + ifd = ifd->getNextIfd(); + } +} + +} /*namespace img_utils*/ +} /*namespace android*/ -- cgit v1.1 From 22fcacaf30e157037e6651241c7b3a45f075daa0 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Sat, 17 May 2014 00:39:17 -0700 Subject: Fixbuild Change-Id: I4379964731b671f36a1e239b0f7665f595ac1c2d --- media/img_utils/src/Android.mk | 1 - 1 file changed, 1 deletion(-) (limited to 'media') diff --git a/media/img_utils/src/Android.mk b/media/img_utils/src/Android.mk index 80893be..29c011f 100644 --- a/media/img_utils/src/Android.mk +++ b/media/img_utils/src/Android.mk @@ -46,7 +46,6 @@ LOCAL_C_INCLUDES += \ LOCAL_CFLAGS += \ -Wall \ -Wextra \ - -Werror \ -fvisibility=hidden ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),) -- cgit v1.1 From 272b7f26c300d2029f278cf2af523cf94e513b89 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Sat, 17 May 2014 01:09:04 -0700 Subject: Fix warnings, re-enable -Werror. Change-Id: Ic6b1a10f46f980f9a9d8d130600419a792703c44 --- media/img_utils/include/img_utils/TiffEntryImpl.h | 4 ++-- media/img_utils/include/img_utils/TiffIfd.h | 2 +- media/img_utils/src/Android.mk | 1 + media/img_utils/src/TiffEntryImpl.cpp | 2 +- media/img_utils/src/TiffIfd.cpp | 20 ++++++++++---------- 5 files changed, 15 insertions(+), 14 deletions(-) (limited to 'media') diff --git a/media/img_utils/include/img_utils/TiffEntryImpl.h b/media/img_utils/include/img_utils/TiffEntryImpl.h index 0e713dc..cbe0e9a 100644 --- a/media/img_utils/include/img_utils/TiffEntryImpl.h +++ b/media/img_utils/include/img_utils/TiffEntryImpl.h @@ -43,7 +43,7 @@ class TiffEntryImpl : public TiffEntry { uint16_t getTag() const; TagType getType() const; Endianness getEndianness() const; - uint32_t getSize() const; + size_t getSize() const; uint32_t getComparableValue() const; protected: @@ -97,7 +97,7 @@ const void* TiffEntryImpl::getDataHelper() const { } template -uint32_t TiffEntryImpl::getSize() const { +size_t TiffEntryImpl::getSize() const { uint32_t total = getActualSize(); WORD_ALIGN(total) return (total <= OFFSET_SIZE) ? 0 : total; diff --git a/media/img_utils/include/img_utils/TiffIfd.h b/media/img_utils/include/img_utils/TiffIfd.h index c35f858..9400456 100644 --- a/media/img_utils/include/img_utils/TiffIfd.h +++ b/media/img_utils/include/img_utils/TiffIfd.h @@ -82,7 +82,7 @@ class ANDROID_API TiffIfd : public TiffWritable { * and the corresponding values for each entry (recursively including * any sub-IFDs). */ - virtual uint32_t getSize() const; + virtual size_t getSize() const; /** * Get the id of this IFD. diff --git a/media/img_utils/src/Android.mk b/media/img_utils/src/Android.mk index 29c011f..80893be 100644 --- a/media/img_utils/src/Android.mk +++ b/media/img_utils/src/Android.mk @@ -46,6 +46,7 @@ LOCAL_C_INCLUDES += \ LOCAL_CFLAGS += \ -Wall \ -Wextra \ + -Werror \ -fvisibility=hidden ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),) diff --git a/media/img_utils/src/TiffEntryImpl.cpp b/media/img_utils/src/TiffEntryImpl.cpp index 2052ceb..6efa458 100644 --- a/media/img_utils/src/TiffEntryImpl.cpp +++ b/media/img_utils/src/TiffEntryImpl.cpp @@ -23,7 +23,7 @@ namespace android { namespace img_utils { template<> -uint32_t TiffEntryImpl::getSize() const { +size_t TiffEntryImpl::getSize() const { uint32_t total = 0; for (uint32_t i = 0; i < mCount; ++i) { total += mData[i].getSize(); diff --git a/media/img_utils/src/TiffIfd.cpp b/media/img_utils/src/TiffIfd.cpp index b75309b..1b3b40d 100644 --- a/media/img_utils/src/TiffIfd.cpp +++ b/media/img_utils/src/TiffIfd.cpp @@ -30,13 +30,13 @@ TiffIfd::~TiffIfd() {} status_t TiffIfd::addEntry(const sp& entry) { size_t size = mEntries.size(); if (size >= MAX_IFD_ENTRIES) { - ALOGW("%s: Failed to add entry for tag 0x%x to IFD %d, too many entries in IFD!", + ALOGW("%s: Failed to add entry for tag 0x%x to IFD %u, too many entries in IFD!", __FUNCTION__, entry->getTag(), mIfdId); return BAD_INDEX; } if (mEntries.add(entry) < 0) { - ALOGW("%s: Failed to add entry for tag 0x%x to ifd %d.", __FUNCTION__, entry->getTag(), + ALOGW("%s: Failed to add entry for tag 0x%x to ifd %u.", __FUNCTION__, entry->getTag(), mIfdId); return BAD_INDEX; } @@ -46,7 +46,7 @@ status_t TiffIfd::addEntry(const sp& entry) { sp TiffIfd::getEntry(uint16_t tag) const { ssize_t index = mEntries.indexOfTag(tag); if (index < 0) { - ALOGW("%s: No entry for tag 0x%x in ifd %d.", __FUNCTION__, tag, mIfdId); + ALOGW("%s: No entry for tag 0x%x in ifd %u.", __FUNCTION__, tag, mIfdId); return NULL; } return mEntries[index]; @@ -64,19 +64,19 @@ uint32_t TiffIfd::checkAndGetOffset(uint32_t offset) const { size_t size = mEntries.size(); if (size > MAX_IFD_ENTRIES) { - ALOGW("%s: Could not calculate IFD offsets, IFD %d contains too many entries.", + ALOGW("%s: Could not calculate IFD offsets, IFD %u contains too many entries.", __FUNCTION__, mIfdId); return BAD_OFFSET; } if (size <= 0) { - ALOGW("%s: Could not calculate IFD offsets, IFD %d contains no entries.", __FUNCTION__, + ALOGW("%s: Could not calculate IFD offsets, IFD %u contains no entries.", __FUNCTION__, mIfdId); return BAD_OFFSET; } if (offset == BAD_OFFSET) { - ALOGW("%s: Could not calculate IFD offsets, IFD %d had a bad initial offset.", + ALOGW("%s: Could not calculate IFD offsets, IFD %u had a bad initial offset.", __FUNCTION__, mIfdId); return BAD_OFFSET; } @@ -128,7 +128,7 @@ status_t TiffIfd::writeData(uint32_t offset, /*out*/EndianOutput* out) const { size_t diff = (next - last); size_t actual = mEntries[i]->getSize(); if (diff != actual) { - ALOGW("Sizes do not match for tag %x. Expected %d, received %d", + ALOGW("Sizes do not match for tag %x. Expected %zu, received %zu", mEntries[i]->getTag(), actual, diff); } } @@ -138,7 +138,7 @@ status_t TiffIfd::writeData(uint32_t offset, /*out*/EndianOutput* out) const { return ret; } -uint32_t TiffIfd::getSize() const { +size_t TiffIfd::getSize() const { size_t size = mEntries.size(); uint32_t total = calculateIfdSize(size); WORD_ALIGN(total); @@ -159,7 +159,7 @@ uint32_t TiffIfd::getComparableValue() const { String8 TiffIfd::toString() const { size_t s = mEntries.size(); String8 output; - output.appendFormat("[ifd: %x, num_entries: %u, entries:\n", getId(), s); + output.appendFormat("[ifd: %x, num_entries: %zu, entries:\n", getId(), s); for(size_t i = 0; i < mEntries.size(); ++i) { output.append("\t"); output.append(mEntries[i]->toString()); @@ -171,7 +171,7 @@ String8 TiffIfd::toString() const { void TiffIfd::log() const { size_t s = mEntries.size(); - ALOGI("[ifd: %x, num_entries: %u, entries:\n", getId(), s); + ALOGI("[ifd: %x, num_entries: %zu, entries:\n", getId(), s); for(size_t i = 0; i < s; ++i) { ALOGI("\t%s", mEntries[i]->toString().string()); } -- cgit v1.1 From c56f3426099a3cf2d07ccff8886050c7fbce140f Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 21 Mar 2014 17:53:17 -0700 Subject: Pass stereo gains as packed minifloat This will allow (eventually) a greater dynamic range for gains. However there are still a few remaining places in effects and mixer that will also need to be changed in order to get the full benefit. Also fixes a minor bug: was not checking for NaN in AudioTrack C++. Change-Id: I63bce9e82e0a61546d8ff475fb94bcb700d99c96 --- media/libmedia/AudioTrack.cpp | 13 ++++++++----- media/libmedia/AudioTrackShared.cpp | 2 +- media/mediaserver/Android.mk | 3 ++- 3 files changed, 11 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index aaaa3f1..120b28e 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -19,6 +19,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "AudioTrack" +#include #include #include #include @@ -566,7 +567,9 @@ void AudioTrack::pause() status_t AudioTrack::setVolume(float left, float right) { - if (left < 0.0f || left > 1.0f || right < 0.0f || right > 1.0f) { + // This duplicates a test by AudioTrack JNI, but that is not the only caller + if (isnanf(left) || left < GAIN_FLOAT_ZERO || left > GAIN_FLOAT_UNITY || + isnanf(right) || right < GAIN_FLOAT_ZERO || right > GAIN_FLOAT_UNITY) { return BAD_VALUE; } @@ -574,7 +577,7 @@ status_t AudioTrack::setVolume(float left, float right) mVolume[AUDIO_INTERLEAVE_LEFT] = left; mVolume[AUDIO_INTERLEAVE_RIGHT] = right; - mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000)); + mProxy->setVolumeLR(gain_minifloat_pack(gain_from_float(left), gain_from_float(right))); if (isOffloaded_l()) { mAudioTrack->signal(); @@ -589,7 +592,8 @@ status_t AudioTrack::setVolume(float volume) status_t AudioTrack::setAuxEffectSendLevel(float level) { - if (level < 0.0f || level > 1.0f) { + // This duplicates a test by AudioTrack JNI, but that is not the only caller + if (isnanf(level) || level < GAIN_FLOAT_ZERO || level > GAIN_FLOAT_UNITY) { return BAD_VALUE; } @@ -1137,8 +1141,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF); mProxy = mStaticProxy; } - mProxy->setVolumeLR((uint32_t(uint16_t(mVolume[AUDIO_INTERLEAVE_RIGHT] * 0x1000)) << 16) | - uint16_t(mVolume[AUDIO_INTERLEAVE_LEFT] * 0x1000)); + mProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY); mProxy->setSendLevel(mSendLevel); mProxy->setSampleRate(mSampleRate); mProxy->setEpoch(epoch); diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index 323b675..27a3718 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -27,7 +27,7 @@ namespace android { audio_track_cblk_t::audio_track_cblk_t() : mServer(0), mFutex(0), mMinimum(0), - mVolumeLR(0x10001000), mSampleRate(0), mSendLevel(0), mFlags(0) + mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0), mFlags(0) { memset(&u, 0, sizeof(u)); } diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk index d3e546a..5bc3f2f 100644 --- a/media/mediaserver/Android.mk +++ b/media/mediaserver/Android.mk @@ -35,7 +35,8 @@ LOCAL_C_INCLUDES := \ frameworks/av/services/medialog \ frameworks/av/services/audioflinger \ frameworks/av/services/audiopolicy \ - frameworks/av/services/camera/libcameraservice + frameworks/av/services/camera/libcameraservice \ + $(call include-path-for, audio-utils) LOCAL_MODULE:= mediaserver LOCAL_32_BIT_ONLY := true -- cgit v1.1 From 79e2b622702fb148ccff12d6f38643466555c4eb Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 16 May 2014 08:07:28 -0700 Subject: Add docs, releaseOutputBufferAtTime, seekTo. Change-Id: Iadd231b63e75b7937c13d2ebfef47aedeaeef5a1 --- media/ndk/NdkMediaCodec.cpp | 15 +++++++++++---- media/ndk/NdkMediaExtractor.cpp | 16 +++++++++++++++- 2 files changed, 26 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index 9e2aa67..bd2541f 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -341,6 +341,13 @@ media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, b } EXPORT +media_status_t AMediaCodec_releaseOutputBufferAtTime( + AMediaCodec *mData, size_t idx, int64_t timestampNs) { + ALOGV("render @ %lld", timestampNs); + return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs)); +} + +EXPORT media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) { mData->mCallback = callback; mData->mCallbackUserData = userdata; @@ -351,7 +358,7 @@ typedef struct AMediaCodecCryptoInfo { int numsubsamples; uint8_t key[16]; uint8_t iv[16]; - uint32_t mode; + cryptoinfo_mode_t mode; size_t *clearbytes; size_t *encryptedbytes; } AMediaCodecCryptoInfo; @@ -396,7 +403,7 @@ AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( int numsubsamples, uint8_t key[16], uint8_t iv[16], - uint32_t mode, + cryptoinfo_mode_t mode, size_t *clearbytes, size_t *encryptedbytes) { @@ -459,9 +466,9 @@ media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *d } EXPORT -uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) { +cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) { if (!ci) { - return AMEDIA_ERROR_INVALID_OBJECT; + return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT; } return ci->mode; } diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp index 563358f..b0a9590 100644 --- a/media/ndk/NdkMediaExtractor.cpp +++ b/media/ndk/NdkMediaExtractor.cpp @@ -150,6 +150,20 @@ bool AMediaExtractor_advance(AMediaExtractor *mData) { } EXPORT +media_status_t AMediaExtractor_seekTo(AMediaExtractor *ex, int64_t seekPosUs, SeekMode mode) { + android::MediaSource::ReadOptions::SeekMode sfmode; + if (mode == AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC) { + sfmode = android::MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC; + } else if (mode == AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC) { + sfmode = android::MediaSource::ReadOptions::SEEK_CLOSEST_SYNC; + } else { + sfmode = android::MediaSource::ReadOptions::SEEK_NEXT_SYNC; + } + + return translate_error(ex->mImpl->seekTo(seekPosUs, sfmode)); +} + +EXPORT ssize_t AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size_t capacity) { //ALOGV("readSampleData"); sp tmp = new ABuffer(buffer, capacity); @@ -331,7 +345,7 @@ AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *ex) numSubSamples, (uint8_t*) key, (uint8_t*) iv, - mode, + (cryptoinfo_mode_t) mode, (size_t*) cleardata, (size_t*) crypteddata); } -- cgit v1.1 From ce171998009e1abcb0c718c0aee495fcd33645e2 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Mon, 19 May 2014 11:03:42 -0700 Subject: MPEG4Extractor: guard against missing stbl. Bug: 14320131 Change-Id: I33f65117c9c5365bddd96bb41cc4379a0c7ebcbd --- media/libstagefright/MPEG4Extractor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index e07b6aa..05caf75 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -2460,8 +2460,9 @@ status_t MPEG4Extractor::verifyTrack(Track *track) { } } - if (!track->sampleTable->isValid()) { + if (track->sampleTable == NULL || !track->sampleTable->isValid()) { // Make sure we have all the metadata we need. + ALOGE("stbl atom missing/invalid."); return ERROR_MALFORMED; } -- cgit v1.1 From 14ead787204a1bfc13e92067691efaefd624fcae Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Mon, 19 May 2014 21:36:20 -0700 Subject: Fix OGG recognition for 64 bit Change-Id: I4cef86ca05e06f508929d109a52e375169c33bf9 --- media/libmediaplayerservice/MediaPlayerFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp index 74e5013..9b239b1 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.cpp +++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp @@ -186,7 +186,7 @@ class StagefrightPlayerFactory : read(fd, buf, sizeof(buf)); lseek(fd, offset, SEEK_SET); - long ident = *((long*)buf); + uint32_t ident = *((uint32_t*)buf); // Ogg vorbis? if (ident == 0x5367674f) // 'OggS' -- cgit v1.1 From 18a1b5904b352cedef29b95169a1226140d38576 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 20 May 2014 08:45:18 -0700 Subject: Use pointers instead of references because C Change-Id: I5c84469e5ff977bf8bb91be2cc6c38a0c7f08609 --- media/ndk/NdkMediaDrm.cpp | 163 ++++++++++++++++++++++++++++------------------ 1 file changed, 101 insertions(+), 62 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp index f982275..a0cbb70 100644 --- a/media/ndk/NdkMediaDrm.cpp +++ b/media/ndk/NdkMediaDrm.cpp @@ -101,7 +101,7 @@ void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel return; } - (*mListener)(mObj, sessionId, ndkEventType, extra, data, dataSize); + (*mListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize); delete [] sessionId.ptr; delete [] data; @@ -236,29 +236,35 @@ static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List: } EXPORT -media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) { +media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId *sessionId) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } + if (!sessionId) { + return AMEDIA_ERROR_INVALID_PARAMETER; + } Vector session; status_t status = mObj->mDrm->openSession(session); if (status == OK) { mObj->mIds.push_front(session); List::iterator iter = mObj->mIds.begin(); - sessionId.ptr = iter->array(); - sessionId.length = iter->size(); + sessionId->ptr = iter->array(); + sessionId->length = iter->size(); } return AMEDIA_OK; } EXPORT -media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) { +media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } + if (!sessionId) { + return AMEDIA_ERROR_INVALID_PARAMETER; + } List::iterator iter; - if (!findId(mObj, sessionId, iter)) { + if (!findId(mObj, *sessionId, iter)) { return AMEDIA_DRM_SESSION_NOT_OPENED; } mObj->mDrm->closeSession(*iter); @@ -267,20 +273,20 @@ media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId } EXPORT -media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope, +media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope *scope, const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType, const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters, - const uint8_t *&keyRequest, size_t &keyRequestSize) { + const uint8_t **keyRequest, size_t *keyRequestSize) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } - if (!mimeType) { + if (!mimeType || !scope || !keyRequest || !keyRequestSize) { return AMEDIA_ERROR_INVALID_PARAMETER; } List::iterator iter; - if (!findId(mObj, scope, iter)) { + if (!findId(mObj, *scope, iter)) { return AMEDIA_DRM_SESSION_NOT_OPENED; } @@ -311,25 +317,25 @@ media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &sc if (status != OK) { return translateStatus(status); } else { - keyRequest = mObj->mKeyRequest.array(); - keyRequestSize = mObj->mKeyRequest.size(); + *keyRequest = mObj->mKeyRequest.array(); + *keyRequestSize = mObj->mKeyRequest.size(); } return AMEDIA_OK; } EXPORT -media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope, - const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) { +media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope, + const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } - if (!response || !responseSize) { + if (!scope || !response || !responseSize || !keySetId) { return AMEDIA_ERROR_INVALID_PARAMETER; } List::iterator iter; - if (!findId(mObj, scope, iter)) { + if (!findId(mObj, *scope, iter)) { return AMEDIA_DRM_SESSION_NOT_OPENED; } Vector mdResponse; @@ -340,41 +346,47 @@ media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScop if (status == OK) { mObj->mIds.push_front(mdKeySetId); List::iterator iter = mObj->mIds.begin(); - keySetId.ptr = iter->array(); - keySetId.length = iter->size(); + keySetId->ptr = iter->array(); + keySetId->length = iter->size(); } else { - keySetId.ptr = NULL; - keySetId.length = 0; + keySetId->ptr = NULL; + keySetId->length = 0; } return AMEDIA_OK; } EXPORT -media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, - const AMediaDrmKeySetId &keySetId) { +media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, + const AMediaDrmKeySetId *keySetId) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } + if (!sessionId || !keySetId) { + return AMEDIA_ERROR_INVALID_PARAMETER; + } List::iterator iter; - if (!findId(mObj, sessionId, iter)) { + if (!findId(mObj, *sessionId, iter)) { return AMEDIA_DRM_SESSION_NOT_OPENED; } Vector keySet; - keySet.appendArray(keySetId.ptr, keySetId.length); + keySet.appendArray(keySetId->ptr, keySetId->length); return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet)); } EXPORT -media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) { +media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } + if (!keySetId) { + return AMEDIA_ERROR_INVALID_PARAMETER; + } List::iterator iter; status_t status; - if (!findId(mObj, keySetId, iter)) { + if (!findId(mObj, *keySetId, iter)) { Vector keySet; - keySet.appendArray(keySetId.ptr, keySetId.length); + keySet.appendArray(keySetId->ptr, keySetId->length); status = mObj->mDrm->removeKeys(keySet); } else { status = mObj->mDrm->removeKeys(*iter); @@ -384,25 +396,28 @@ media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &k } EXPORT -media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, - AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) { +media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, + AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } + if (!sessionId || !numPairs) { + return AMEDIA_ERROR_INVALID_PARAMETER; + } List::iterator iter; - if (!findId(mObj, sessionId, iter)) { + if (!findId(mObj, *sessionId, iter)) { return AMEDIA_DRM_SESSION_NOT_OPENED; } status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults); if (status != OK) { - numPairs = 0; + *numPairs = 0; return translateStatus(status); } - if (mObj->mQueryResults.size() > numPairs) { - numPairs = mObj->mQueryResults.size(); + if (mObj->mQueryResults.size() > *numPairs) { + *numPairs = mObj->mQueryResults.size(); return AMEDIA_DRM_SHORT_BUFFER; } @@ -410,17 +425,17 @@ media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionI keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string(); keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string(); } - numPairs = mObj->mQueryResults.size(); + *numPairs = mObj->mQueryResults.size(); return AMEDIA_OK; } EXPORT -media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest, - size_t &provisionRequestSize, const char *&serverUrl) { +media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest, + size_t *provisionRequestSize, const char **serverUrl) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } - if (!provisionRequestSize || !serverUrl) { + if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) { return AMEDIA_ERROR_INVALID_PARAMETER; } @@ -429,9 +444,9 @@ media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&pr if (status != OK) { return translateStatus(status); } else { - provisionRequest = mObj->mProvisionRequest.array(); - provisionRequestSize = mObj->mProvisionRequest.size(); - serverUrl = mObj->mProvisionUrl.string(); + *provisionRequest = mObj->mProvisionRequest.array(); + *provisionRequestSize = mObj->mProvisionRequest.size(); + *serverUrl = mObj->mProvisionUrl.string(); } return AMEDIA_OK; } @@ -455,17 +470,20 @@ media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj, EXPORT media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, - AMediaDrmSecureStop *secureStops, size_t &numSecureStops) { + AMediaDrmSecureStop *secureStops, size_t *numSecureStops) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } + if (!numSecureStops) { + return AMEDIA_ERROR_INVALID_PARAMETER; + } status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops); if (status != OK) { - numSecureStops = 0; + *numSecureStops = 0; return translateStatus(status); } - if (numSecureStops < mObj->mSecureStops.size()) { + if (*numSecureStops < mObj->mSecureStops.size()) { return AMEDIA_DRM_SHORT_BUFFER; } List >::iterator iter = mObj->mSecureStops.begin(); @@ -476,59 +494,68 @@ media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, ++iter; ++i; } - numSecureStops = mObj->mSecureStops.size(); + *numSecureStops = mObj->mSecureStops.size(); return AMEDIA_OK; } EXPORT media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj, - const AMediaDrmSecureStop &ssRelease) { + const AMediaDrmSecureStop *ssRelease) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } + if (!ssRelease) { + return AMEDIA_ERROR_INVALID_PARAMETER; + } Vector release; - release.appendArray(ssRelease.ptr, ssRelease.length); + release.appendArray(ssRelease->ptr, ssRelease->length); return translateStatus(mObj->mDrm->releaseSecureStops(release)); } EXPORT media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName, - const char *&propertyValue) { + const char **propertyValue) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } + if (!propertyName || !propertyValue) { + return AMEDIA_ERROR_INVALID_PARAMETER; + } status_t status = mObj->mDrm->getPropertyString(String8(propertyName), mObj->mPropertyString); if (status == OK) { - propertyValue = mObj->mPropertyString.string(); + *propertyValue = mObj->mPropertyString.string(); } else { - propertyValue = NULL; + *propertyValue = NULL; } return translateStatus(status); } EXPORT media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj, - const char *propertyName, AMediaDrmByteArray &propertyValue) { + const char *propertyName, AMediaDrmByteArray *propertyValue) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } + if (!propertyName || !propertyValue) { + return AMEDIA_ERROR_INVALID_PARAMETER; + } status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName), mObj->mPropertyByteArray); if (status == OK) { - propertyValue.ptr = mObj->mPropertyByteArray.array(); - propertyValue.length = mObj->mPropertyByteArray.size(); + propertyValue->ptr = mObj->mPropertyByteArray.array(); + propertyValue->length = mObj->mPropertyByteArray.size(); } else { - propertyValue.ptr = NULL; - propertyValue.length = 0; + propertyValue->ptr = NULL; + propertyValue->length = 0; } return translateStatus(status); } @@ -598,31 +625,40 @@ static media_status_t encrypt_decrypt_common(AMediaDrm *mObj, } EXPORT -media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, +media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, const uint8_t *input, uint8_t *output, size_t dataSize) { - return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv, + if (!sessionId) { + return AMEDIA_ERROR_INVALID_PARAMETER; + } + return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv, input, output, dataSize, true); } EXPORT -media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, +media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, const uint8_t *input, uint8_t *output, size_t dataSize) { - return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv, + if (!sessionId) { + return AMEDIA_ERROR_INVALID_PARAMETER; + } + return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv, input, output, dataSize, false); } EXPORT -media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, +media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize, uint8_t *signature, size_t *signatureSize) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } + if (!sessionId) { + return AMEDIA_ERROR_INVALID_PARAMETER; + } List::iterator iter; - if (!findId(mObj, sessionId, iter)) { + if (!findId(mObj, *sessionId, iter)) { return AMEDIA_DRM_SESSION_NOT_OPENED; } @@ -650,15 +686,18 @@ media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &session } EXPORT -media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, +media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize, const uint8_t *signature, size_t signatureSize) { if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } + if (!sessionId) { + return AMEDIA_ERROR_INVALID_PARAMETER; + } List::iterator iter; - if (!findId(mObj, sessionId, iter)) { + if (!findId(mObj, *sessionId, iter)) { return AMEDIA_DRM_SESSION_NOT_OPENED; } -- cgit v1.1 From 0e03cf07deeda10c573657479591dcfbf1efca56 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 21 May 2014 07:53:04 -0700 Subject: Remove the last of the references. Change-Id: Id68cdab7e972e3e78e2065e56b8a095c3d496df2 --- media/ndk/NdkMediaMuxer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp index 19b9fc4..50fc336 100644 --- a/media/ndk/NdkMediaMuxer.cpp +++ b/media/ndk/NdkMediaMuxer.cpp @@ -96,10 +96,10 @@ media_status_t AMediaMuxer_stop(AMediaMuxer *muxer) { EXPORT media_status_t AMediaMuxer_writeSampleData(AMediaMuxer *muxer, - size_t trackIdx, const uint8_t *data, const AMediaCodecBufferInfo &info) { - sp buf = new ABuffer((void*)(data + info.offset), info.size); + size_t trackIdx, const uint8_t *data, const AMediaCodecBufferInfo *info) { + sp buf = new ABuffer((void*)(data + info->offset), info->size); return translate_error( - muxer->mImpl->writeSampleData(buf, trackIdx, info.presentationTimeUs, info.flags)); + muxer->mImpl->writeSampleData(buf, trackIdx, info->presentationTimeUs, info->flags)); } -- cgit v1.1 From 98c6be0e30fa28e752b13f3dd5986d41710bb7ae Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 21 May 2014 08:14:08 -0700 Subject: audio policy: split audio policy library Split audio policy library into a service part and a policy part. This will allow OEMs to customize the policy part: - libaudiopolicyservice for the service. - libaudiopolicymanager for the policy. Two build options can be defined in device make file to select the policy library: - USE_LEGACY_AUDIO_POLICY = 1: this will use the legacy policy in hardware/libhardware_legacy implemented by AudioPolicyManagerBase class. This policy is loaded as a harware module and exposes the audio policy HAL defined in include/hardware/audio_policy.h and is in a library called audio_policy.XXX.so (e.g audio_policy.default.so) The legacy HAL will not be updated with new features. If USE_LEGACY_AUDIO_POLICY is not defined, the policy is implemented by a class named AudioPolicyManager exposing an interface defined in AudioPolicyInterface.h. The corresponding library is libaudiopolicymanager.so. New features will be added only to AudioPolicyInterface.h The default implementation is provided here in file AudioPolicyManager.cpp OEMs wanting to cutomize the policy can implement the AudioPolicyManager class and provide the libaudiopolicymanager.so library. In this case the device make file should define: - USE_CUSTOM_AUDIO_POLICY = 1 For now, USE_LEGACY_AUDIO_POLICY = 1 is forced in audio policy service make file. This will be removed when the new audio policy is enabled. Change-Id: I066799dacc9b182b468a43d48ff7798c9109a414 --- media/mediaserver/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk index d3e546a..15b2bc0 100644 --- a/media/mediaserver/Android.mk +++ b/media/mediaserver/Android.mk @@ -15,7 +15,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libaudioflinger \ - libaudiopolicy \ + libaudiopolicyservice \ libcamera_metadata\ libcameraservice \ libmedialogservice \ -- cgit v1.1 From 29b703eec27b305e7b5b2343bf257643e38f6b68 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 12 May 2014 11:06:26 -0700 Subject: Move validation of frameCount from set to openRecord_l This move is needed because frameCount is validated on server side for fast tracks (as should be done for normal tracks too). Change-Id: I6d99e80869fd90fab373cf60ef348c01f075fbca --- media/libmedia/AudioRecord.cpp | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 1c808d0..db61e85 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -203,23 +203,6 @@ status_t AudioRecord::set( mFrameSize = sizeof(uint8_t); } - // validate framecount - size_t minFrameCount; - status_t status = AudioRecord::getMinFrameCount(&minFrameCount, - sampleRate, format, channelMask); - if (status != NO_ERROR) { - ALOGE("getMinFrameCount() failed for sampleRate %u, format %#x, channelMask %#x; status %d", - sampleRate, format, channelMask, status); - return status; - } - ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount); - - if (frameCount == 0) { - frameCount = minFrameCount; - } else if (frameCount < minFrameCount) { - ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount); - return BAD_VALUE; - } // mFrameCount is initialized in openRecord_l mReqFrameCount = frameCount; @@ -242,7 +225,7 @@ status_t AudioRecord::set( } // create the IAudioRecord - status = openRecord_l(0 /*epoch*/); + status_t status = openRecord_l(0 /*epoch*/); if (status != NO_ERROR) { if (mAudioRecordThread != 0) { @@ -464,6 +447,29 @@ status_t AudioRecord::openRecord_l(size_t epoch) size_t frameCount = mReqFrameCount; if (!(mFlags & AUDIO_INPUT_FLAG_FAST)) { + // validate framecount + // If fast track was not requested, this preserves + // the old behavior of validating on client side. + // FIXME Eventually the validation should be done on server side + // regardless of whether it's a fast or normal track. It's debatable + // whether to account for the input latency to provision buffers appropriately. + size_t minFrameCount; + status = AudioRecord::getMinFrameCount(&minFrameCount, + mSampleRate, mFormat, mChannelMask); + if (status != NO_ERROR) { + ALOGE("getMinFrameCount() failed for sampleRate %u, format %#x, channelMask %#x; " + "status %d", + mSampleRate, mFormat, mChannelMask, status); + return status; + } + + if (frameCount == 0) { + frameCount = minFrameCount; + } else if (frameCount < minFrameCount) { + ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount); + return BAD_VALUE; + } + // Make sure that application is notified with sufficient margin before overrun if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/2) { mNotificationFramesAct = frameCount/2; -- cgit v1.1 From e22a64b6887240fc9910d6fc8afb0e6f81507047 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 23 May 2014 15:49:49 -0700 Subject: Remove codec callback for now. Change-Id: I7ef3c1fc7aa1bfec958e6ea58bf95ae35a575e91 --- media/ndk/NdkMediaCodec.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index bd2541f..2ac16c7 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -61,6 +61,8 @@ public: virtual void onMessageReceived(const sp &msg); }; +typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata); + struct AMediaCodec { sp mCodec; sp mLooper; @@ -347,7 +349,7 @@ media_status_t AMediaCodec_releaseOutputBufferAtTime( return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs)); } -EXPORT +//EXPORT media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) { mData->mCallback = callback; mData->mCallbackUserData = userdata; -- cgit v1.1 From 4b123406c10c17852734a1b691bb9ce2a4cb7caf Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 11 Apr 2014 09:22:20 -0700 Subject: IAudioFlinger interface extension for patch panel Change-Id: Iaabe0a7e315d5725e00a74a6ed40339b98f20330 --- media/libmedia/IAudioFlinger.cpp | 172 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 171 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 0e2463e..687fa76 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -74,6 +74,12 @@ enum { GET_PRIMARY_OUTPUT_SAMPLING_RATE, GET_PRIMARY_OUTPUT_FRAME_COUNT, SET_LOW_RAM_DEVICE, + LIST_AUDIO_PORTS, + GET_AUDIO_PORT, + CREATE_AUDIO_PATCH, + RELEASE_AUDIO_PATCH, + LIST_AUDIO_PATCHES, + SET_AUDIO_PORT_CONFIG }; class BpAudioFlinger : public BpInterface @@ -801,7 +807,101 @@ public: remote()->transact(SET_LOW_RAM_DEVICE, data, &reply); return reply.readInt32(); } - + virtual status_t listAudioPorts(unsigned int *num_ports, + struct audio_port *ports) + { + if (num_ports == NULL || *num_ports == 0 || ports == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(*num_ports); + status_t status = remote()->transact(LIST_AUDIO_PORTS, data, &reply); + if (status != NO_ERROR || + (status = (status_t)reply.readInt32()) != NO_ERROR) { + return status; + } + *num_ports = (unsigned int)reply.readInt32(); + reply.read(ports, *num_ports * sizeof(struct audio_port)); + return status; + } + virtual status_t getAudioPort(struct audio_port *port) + { + if (port == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.write(port, sizeof(struct audio_port)); + status_t status = remote()->transact(GET_AUDIO_PORT, data, &reply); + if (status != NO_ERROR || + (status = (status_t)reply.readInt32()) != NO_ERROR) { + return status; + } + reply.read(port, sizeof(struct audio_port)); + return status; + } + virtual status_t createAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle) + { + if (patch == NULL || handle == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.write(patch, sizeof(struct audio_patch)); + data.write(handle, sizeof(audio_patch_handle_t)); + status_t status = remote()->transact(CREATE_AUDIO_PATCH, data, &reply); + if (status != NO_ERROR || + (status = (status_t)reply.readInt32()) != NO_ERROR) { + return status; + } + reply.read(handle, sizeof(audio_patch_handle_t)); + return status; + } + virtual status_t releaseAudioPatch(audio_patch_handle_t handle) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.write(&handle, sizeof(audio_patch_handle_t)); + status_t status = remote()->transact(RELEASE_AUDIO_PATCH, data, &reply); + if (status != NO_ERROR) { + status = (status_t)reply.readInt32(); + } + return status; + } + virtual status_t listAudioPatches(unsigned int *num_patches, + struct audio_patch *patches) + { + if (num_patches == NULL || *num_patches == 0 || patches == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(*num_patches); + status_t status = remote()->transact(LIST_AUDIO_PATCHES, data, &reply); + if (status != NO_ERROR || + (status = (status_t)reply.readInt32()) != NO_ERROR) { + return status; + } + *num_patches = (unsigned int)reply.readInt32(); + reply.read(patches, *num_patches * sizeof(struct audio_patch)); + return status; + } + virtual status_t setAudioPortConfig(const struct audio_port_config *config) + { + if (config == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.write(config, sizeof(struct audio_port_config)); + status_t status = remote()->transact(SET_AUDIO_PORT_CONFIG, data, &reply); + if (status != NO_ERROR) { + status = (status_t)reply.readInt32(); + } + return status; + } }; IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger"); @@ -1199,6 +1299,76 @@ status_t BnAudioFlinger::onTransact( reply->writeInt32(setLowRamDevice(isLowRamDevice)); return NO_ERROR; } break; + case LIST_AUDIO_PORTS: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + unsigned int num_ports = data.readInt32(); + struct audio_port *ports = + (struct audio_port *)calloc(num_ports, + sizeof(struct audio_port)); + status_t status = listAudioPorts(&num_ports, ports); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->writeInt32(num_ports); + reply->write(&ports, num_ports * sizeof(struct audio_port)); + } + free(ports); + return NO_ERROR; + } break; + case GET_AUDIO_PORT: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + struct audio_port port; + data.read(&port, sizeof(struct audio_port)); + status_t status = getAudioPort(&port); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->write(&port, sizeof(struct audio_port)); + } + return NO_ERROR; + } break; + case CREATE_AUDIO_PATCH: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + struct audio_patch patch; + data.read(&patch, sizeof(struct audio_patch)); + audio_patch_handle_t handle; + data.read(&handle, sizeof(audio_patch_handle_t)); + status_t status = createAudioPatch(&patch, &handle); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->write(&handle, sizeof(audio_patch_handle_t)); + } + return NO_ERROR; + } break; + case RELEASE_AUDIO_PATCH: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + audio_patch_handle_t handle; + data.read(&handle, sizeof(audio_patch_handle_t)); + status_t status = releaseAudioPatch(handle); + reply->writeInt32(status); + return NO_ERROR; + } break; + case LIST_AUDIO_PATCHES: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + unsigned int num_patches = data.readInt32(); + struct audio_patch *patches = + (struct audio_patch *)calloc(num_patches, + sizeof(struct audio_patch)); + status_t status = listAudioPatches(&num_patches, patches); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->writeInt32(num_patches); + reply->write(&patches, num_patches * sizeof(struct audio_patch)); + } + free(patches); + return NO_ERROR; + } break; + case SET_AUDIO_PORT_CONFIG: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + struct audio_port_config config; + data.read(&config, sizeof(struct audio_port_config)); + status_t status = setAudioPortConfig(&config); + reply->writeInt32(status); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } -- cgit v1.1 From 8670c31fddbeadcf9627aa970c69a823f13939ff Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 1 Apr 2014 10:34:16 -0700 Subject: IAudioPolicyService interface extension for patch panel Change-Id: I0a62e5416edc41c3a0e816275085ab18a23066f1 --- media/libmedia/AudioSystem.cpp | 49 +++++++ media/libmedia/IAudioPolicyService.cpp | 228 ++++++++++++++++++++++++++++++++- 2 files changed, 275 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 2f16444..845ee20 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -831,6 +831,55 @@ bool AudioSystem::isOffloadSupported(const audio_offload_info_t& info) return aps->isOffloadSupported(info); } +status_t AudioSystem::listAudioPorts(audio_port_role_t role, + audio_port_type_t type, + unsigned int *num_ports, + struct audio_port *ports, + unsigned int *generation) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->listAudioPorts(role, type, num_ports, ports, generation); +} + +status_t AudioSystem::getAudioPort(struct audio_port *port) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->getAudioPort(port); +} + +status_t AudioSystem::createAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->createAudioPatch(patch, handle); +} + +status_t AudioSystem::releaseAudioPatch(audio_patch_handle_t handle) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->releaseAudioPatch(handle); +} + +status_t AudioSystem::listAudioPatches(unsigned int *num_patches, + struct audio_patch *patches, + unsigned int *generation) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->listAudioPatches(num_patches, patches, generation); +} + +status_t AudioSystem::setAudioPortConfig(const struct audio_port_config *config) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->setAudioPortConfig(config); +} + // --------------------------------------------------------------------------- void AudioSystem::AudioPolicyServiceClient::binderDied(const wp& who __unused) diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 9bb4a49..ad2d4eb 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -57,7 +57,13 @@ enum { QUERY_DEFAULT_PRE_PROCESSING, SET_EFFECT_ENABLED, IS_STREAM_ACTIVE_REMOTELY, - IS_OFFLOAD_SUPPORTED + IS_OFFLOAD_SUPPORTED, + LIST_AUDIO_PORTS, + GET_AUDIO_PORT, + CREATE_AUDIO_PATCH, + RELEASE_AUDIO_PATCH, + LIST_AUDIO_PATCHES, + SET_AUDIO_PORT_CONFIG }; class BpAudioPolicyService : public BpInterface @@ -390,7 +396,134 @@ public: data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.write(&info, sizeof(audio_offload_info_t)); remote()->transact(IS_OFFLOAD_SUPPORTED, data, &reply); - return reply.readInt32(); } + return reply.readInt32(); + } + + virtual status_t listAudioPorts(audio_port_role_t role, + audio_port_type_t type, + unsigned int *num_ports, + struct audio_port *ports, + unsigned int *generation) + { + if (num_ports == NULL || (*num_ports != 0 && ports == NULL) || + generation == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + unsigned int numPortsReq = (ports == NULL) ? 0 : *num_ports; + data.writeInt32(role); + data.writeInt32(type); + data.writeInt32(numPortsReq); + status_t status = remote()->transact(LIST_AUDIO_PORTS, data, &reply); + if (status == NO_ERROR) { + status = (status_t)reply.readInt32(); + *num_ports = (unsigned int)reply.readInt32(); + } + ALOGI("listAudioPorts() status %d got *num_ports %d", status, *num_ports); + if (status == NO_ERROR) { + if (numPortsReq > *num_ports) { + numPortsReq = *num_ports; + } + if (numPortsReq > 0) { + reply.read(ports, numPortsReq * sizeof(struct audio_port)); + } + *generation = reply.readInt32(); + } + return status; + } + + virtual status_t getAudioPort(struct audio_port *port) + { + if (port == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(port, sizeof(struct audio_port)); + status_t status = remote()->transact(GET_AUDIO_PORT, data, &reply); + if (status != NO_ERROR || + (status = (status_t)reply.readInt32()) != NO_ERROR) { + return status; + } + reply.read(port, sizeof(struct audio_port)); + return status; + } + + virtual status_t createAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle) + { + if (patch == NULL || handle == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(patch, sizeof(struct audio_patch)); + data.write(handle, sizeof(audio_patch_handle_t)); + status_t status = remote()->transact(CREATE_AUDIO_PATCH, data, &reply); + if (status != NO_ERROR || + (status = (status_t)reply.readInt32()) != NO_ERROR) { + return status; + } + reply.read(handle, sizeof(audio_patch_handle_t)); + return status; + } + + virtual status_t releaseAudioPatch(audio_patch_handle_t handle) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(&handle, sizeof(audio_patch_handle_t)); + status_t status = remote()->transact(RELEASE_AUDIO_PATCH, data, &reply); + if (status != NO_ERROR) { + status = (status_t)reply.readInt32(); + } + return status; + } + + virtual status_t listAudioPatches(unsigned int *num_patches, + struct audio_patch *patches, + unsigned int *generation) + { + if (num_patches == NULL || (*num_patches != 0 && patches == NULL) || + generation == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + unsigned int numPatchesReq = (patches == NULL) ? 0 : *num_patches; + data.writeInt32(numPatchesReq); + status_t status = remote()->transact(LIST_AUDIO_PATCHES, data, &reply); + if (status == NO_ERROR) { + status = (status_t)reply.readInt32(); + *num_patches = (unsigned int)reply.readInt32(); + } + if (status == NO_ERROR) { + if (numPatchesReq > *num_patches) { + numPatchesReq = *num_patches; + } + if (numPatchesReq > 0) { + reply.read(patches, numPatchesReq * sizeof(struct audio_patch)); + } + *generation = reply.readInt32(); + } + return status; + } + + virtual status_t setAudioPortConfig(const struct audio_port_config *config) + { + if (config == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(config, sizeof(struct audio_port_config)); + status_t status = remote()->transact(SET_AUDIO_PORT_CONFIG, data, &reply); + if (status != NO_ERROR) { + status = (status_t)reply.readInt32(); + } + return status; + } }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -687,6 +820,97 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } + case LIST_AUDIO_PORTS: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + audio_port_role_t role = (audio_port_role_t)data.readInt32(); + audio_port_type_t type = (audio_port_type_t)data.readInt32(); + unsigned int numPortsReq = data.readInt32(); + unsigned int numPorts = numPortsReq; + unsigned int generation; + struct audio_port *ports = + (struct audio_port *)calloc(numPortsReq, sizeof(struct audio_port)); + status_t status = listAudioPorts(role, type, &numPorts, ports, &generation); + reply->writeInt32(status); + reply->writeInt32(numPorts); + ALOGI("LIST_AUDIO_PORTS status %d got numPorts %d", status, numPorts); + + if (status == NO_ERROR) { + if (numPortsReq > numPorts) { + numPortsReq = numPorts; + } + reply->write(ports, numPortsReq * sizeof(struct audio_port)); + reply->writeInt32(generation); + } + free(ports); + return NO_ERROR; + } + + case GET_AUDIO_PORT: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + struct audio_port port; + data.read(&port, sizeof(struct audio_port)); + status_t status = getAudioPort(&port); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->write(&port, sizeof(struct audio_port)); + } + return NO_ERROR; + } + + case CREATE_AUDIO_PATCH: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + struct audio_patch patch; + data.read(&patch, sizeof(struct audio_patch)); + audio_patch_handle_t handle; + data.read(&handle, sizeof(audio_patch_handle_t)); + status_t status = createAudioPatch(&patch, &handle); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->write(&handle, sizeof(audio_patch_handle_t)); + } + return NO_ERROR; + } + + case RELEASE_AUDIO_PATCH: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + audio_patch_handle_t handle; + data.read(&handle, sizeof(audio_patch_handle_t)); + status_t status = releaseAudioPatch(handle); + reply->writeInt32(status); + return NO_ERROR; + } + + case LIST_AUDIO_PATCHES: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + unsigned int numPatchesReq = data.readInt32(); + unsigned int numPatches = numPatchesReq; + unsigned int generation; + struct audio_patch *patches = + (struct audio_patch *)calloc(numPatchesReq, + sizeof(struct audio_patch)); + status_t status = listAudioPatches(&numPatches, patches, &generation); + reply->writeInt32(status); + reply->writeInt32(numPatches); + if (status == NO_ERROR) { + if (numPatchesReq > numPatches) { + numPatchesReq = numPatches; + } + reply->write(patches, numPatchesReq * sizeof(struct audio_patch)); + reply->writeInt32(generation); + } + free(patches); + return NO_ERROR; + } + + case SET_AUDIO_PORT_CONFIG: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + struct audio_port_config config; + data.read(&config, sizeof(struct audio_port_config)); + status_t status = setAudioPortConfig(&config); + reply->writeInt32(status); + return NO_ERROR; + } + default: return BBinder::onTransact(code, data, reply, flags); } -- cgit v1.1 From 1cda6afaf6207a41303e653a6ecd7909d73186eb Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 11 Apr 2014 09:22:20 -0700 Subject: DO NOT MERGE - IAudioFlinger interface extension for patch panel Change-Id: Iaabe0a7e315d5725e00a74a6ed40339b98f20330 --- media/libmedia/IAudioFlinger.cpp | 172 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 171 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 0e2463e..687fa76 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -74,6 +74,12 @@ enum { GET_PRIMARY_OUTPUT_SAMPLING_RATE, GET_PRIMARY_OUTPUT_FRAME_COUNT, SET_LOW_RAM_DEVICE, + LIST_AUDIO_PORTS, + GET_AUDIO_PORT, + CREATE_AUDIO_PATCH, + RELEASE_AUDIO_PATCH, + LIST_AUDIO_PATCHES, + SET_AUDIO_PORT_CONFIG }; class BpAudioFlinger : public BpInterface @@ -801,7 +807,101 @@ public: remote()->transact(SET_LOW_RAM_DEVICE, data, &reply); return reply.readInt32(); } - + virtual status_t listAudioPorts(unsigned int *num_ports, + struct audio_port *ports) + { + if (num_ports == NULL || *num_ports == 0 || ports == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(*num_ports); + status_t status = remote()->transact(LIST_AUDIO_PORTS, data, &reply); + if (status != NO_ERROR || + (status = (status_t)reply.readInt32()) != NO_ERROR) { + return status; + } + *num_ports = (unsigned int)reply.readInt32(); + reply.read(ports, *num_ports * sizeof(struct audio_port)); + return status; + } + virtual status_t getAudioPort(struct audio_port *port) + { + if (port == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.write(port, sizeof(struct audio_port)); + status_t status = remote()->transact(GET_AUDIO_PORT, data, &reply); + if (status != NO_ERROR || + (status = (status_t)reply.readInt32()) != NO_ERROR) { + return status; + } + reply.read(port, sizeof(struct audio_port)); + return status; + } + virtual status_t createAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle) + { + if (patch == NULL || handle == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.write(patch, sizeof(struct audio_patch)); + data.write(handle, sizeof(audio_patch_handle_t)); + status_t status = remote()->transact(CREATE_AUDIO_PATCH, data, &reply); + if (status != NO_ERROR || + (status = (status_t)reply.readInt32()) != NO_ERROR) { + return status; + } + reply.read(handle, sizeof(audio_patch_handle_t)); + return status; + } + virtual status_t releaseAudioPatch(audio_patch_handle_t handle) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.write(&handle, sizeof(audio_patch_handle_t)); + status_t status = remote()->transact(RELEASE_AUDIO_PATCH, data, &reply); + if (status != NO_ERROR) { + status = (status_t)reply.readInt32(); + } + return status; + } + virtual status_t listAudioPatches(unsigned int *num_patches, + struct audio_patch *patches) + { + if (num_patches == NULL || *num_patches == 0 || patches == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(*num_patches); + status_t status = remote()->transact(LIST_AUDIO_PATCHES, data, &reply); + if (status != NO_ERROR || + (status = (status_t)reply.readInt32()) != NO_ERROR) { + return status; + } + *num_patches = (unsigned int)reply.readInt32(); + reply.read(patches, *num_patches * sizeof(struct audio_patch)); + return status; + } + virtual status_t setAudioPortConfig(const struct audio_port_config *config) + { + if (config == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.write(config, sizeof(struct audio_port_config)); + status_t status = remote()->transact(SET_AUDIO_PORT_CONFIG, data, &reply); + if (status != NO_ERROR) { + status = (status_t)reply.readInt32(); + } + return status; + } }; IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger"); @@ -1199,6 +1299,76 @@ status_t BnAudioFlinger::onTransact( reply->writeInt32(setLowRamDevice(isLowRamDevice)); return NO_ERROR; } break; + case LIST_AUDIO_PORTS: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + unsigned int num_ports = data.readInt32(); + struct audio_port *ports = + (struct audio_port *)calloc(num_ports, + sizeof(struct audio_port)); + status_t status = listAudioPorts(&num_ports, ports); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->writeInt32(num_ports); + reply->write(&ports, num_ports * sizeof(struct audio_port)); + } + free(ports); + return NO_ERROR; + } break; + case GET_AUDIO_PORT: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + struct audio_port port; + data.read(&port, sizeof(struct audio_port)); + status_t status = getAudioPort(&port); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->write(&port, sizeof(struct audio_port)); + } + return NO_ERROR; + } break; + case CREATE_AUDIO_PATCH: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + struct audio_patch patch; + data.read(&patch, sizeof(struct audio_patch)); + audio_patch_handle_t handle; + data.read(&handle, sizeof(audio_patch_handle_t)); + status_t status = createAudioPatch(&patch, &handle); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->write(&handle, sizeof(audio_patch_handle_t)); + } + return NO_ERROR; + } break; + case RELEASE_AUDIO_PATCH: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + audio_patch_handle_t handle; + data.read(&handle, sizeof(audio_patch_handle_t)); + status_t status = releaseAudioPatch(handle); + reply->writeInt32(status); + return NO_ERROR; + } break; + case LIST_AUDIO_PATCHES: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + unsigned int num_patches = data.readInt32(); + struct audio_patch *patches = + (struct audio_patch *)calloc(num_patches, + sizeof(struct audio_patch)); + status_t status = listAudioPatches(&num_patches, patches); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->writeInt32(num_patches); + reply->write(&patches, num_patches * sizeof(struct audio_patch)); + } + free(patches); + return NO_ERROR; + } break; + case SET_AUDIO_PORT_CONFIG: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + struct audio_port_config config; + data.read(&config, sizeof(struct audio_port_config)); + status_t status = setAudioPortConfig(&config); + reply->writeInt32(status); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } -- cgit v1.1 From 203b1a18a806e2c56c701aac49cda963bccfad5b Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 1 Apr 2014 10:34:16 -0700 Subject: DO NOT MERGE - IAudioPolicyService interface extension for patch panel Change-Id: I0a62e5416edc41c3a0e816275085ab18a23066f1 --- media/libmedia/AudioSystem.cpp | 49 +++++++ media/libmedia/IAudioPolicyService.cpp | 228 ++++++++++++++++++++++++++++++++- 2 files changed, 275 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 2f16444..845ee20 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -831,6 +831,55 @@ bool AudioSystem::isOffloadSupported(const audio_offload_info_t& info) return aps->isOffloadSupported(info); } +status_t AudioSystem::listAudioPorts(audio_port_role_t role, + audio_port_type_t type, + unsigned int *num_ports, + struct audio_port *ports, + unsigned int *generation) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->listAudioPorts(role, type, num_ports, ports, generation); +} + +status_t AudioSystem::getAudioPort(struct audio_port *port) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->getAudioPort(port); +} + +status_t AudioSystem::createAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->createAudioPatch(patch, handle); +} + +status_t AudioSystem::releaseAudioPatch(audio_patch_handle_t handle) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->releaseAudioPatch(handle); +} + +status_t AudioSystem::listAudioPatches(unsigned int *num_patches, + struct audio_patch *patches, + unsigned int *generation) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->listAudioPatches(num_patches, patches, generation); +} + +status_t AudioSystem::setAudioPortConfig(const struct audio_port_config *config) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->setAudioPortConfig(config); +} + // --------------------------------------------------------------------------- void AudioSystem::AudioPolicyServiceClient::binderDied(const wp& who __unused) diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 9bb4a49..ad2d4eb 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -57,7 +57,13 @@ enum { QUERY_DEFAULT_PRE_PROCESSING, SET_EFFECT_ENABLED, IS_STREAM_ACTIVE_REMOTELY, - IS_OFFLOAD_SUPPORTED + IS_OFFLOAD_SUPPORTED, + LIST_AUDIO_PORTS, + GET_AUDIO_PORT, + CREATE_AUDIO_PATCH, + RELEASE_AUDIO_PATCH, + LIST_AUDIO_PATCHES, + SET_AUDIO_PORT_CONFIG }; class BpAudioPolicyService : public BpInterface @@ -390,7 +396,134 @@ public: data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.write(&info, sizeof(audio_offload_info_t)); remote()->transact(IS_OFFLOAD_SUPPORTED, data, &reply); - return reply.readInt32(); } + return reply.readInt32(); + } + + virtual status_t listAudioPorts(audio_port_role_t role, + audio_port_type_t type, + unsigned int *num_ports, + struct audio_port *ports, + unsigned int *generation) + { + if (num_ports == NULL || (*num_ports != 0 && ports == NULL) || + generation == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + unsigned int numPortsReq = (ports == NULL) ? 0 : *num_ports; + data.writeInt32(role); + data.writeInt32(type); + data.writeInt32(numPortsReq); + status_t status = remote()->transact(LIST_AUDIO_PORTS, data, &reply); + if (status == NO_ERROR) { + status = (status_t)reply.readInt32(); + *num_ports = (unsigned int)reply.readInt32(); + } + ALOGI("listAudioPorts() status %d got *num_ports %d", status, *num_ports); + if (status == NO_ERROR) { + if (numPortsReq > *num_ports) { + numPortsReq = *num_ports; + } + if (numPortsReq > 0) { + reply.read(ports, numPortsReq * sizeof(struct audio_port)); + } + *generation = reply.readInt32(); + } + return status; + } + + virtual status_t getAudioPort(struct audio_port *port) + { + if (port == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(port, sizeof(struct audio_port)); + status_t status = remote()->transact(GET_AUDIO_PORT, data, &reply); + if (status != NO_ERROR || + (status = (status_t)reply.readInt32()) != NO_ERROR) { + return status; + } + reply.read(port, sizeof(struct audio_port)); + return status; + } + + virtual status_t createAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle) + { + if (patch == NULL || handle == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(patch, sizeof(struct audio_patch)); + data.write(handle, sizeof(audio_patch_handle_t)); + status_t status = remote()->transact(CREATE_AUDIO_PATCH, data, &reply); + if (status != NO_ERROR || + (status = (status_t)reply.readInt32()) != NO_ERROR) { + return status; + } + reply.read(handle, sizeof(audio_patch_handle_t)); + return status; + } + + virtual status_t releaseAudioPatch(audio_patch_handle_t handle) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(&handle, sizeof(audio_patch_handle_t)); + status_t status = remote()->transact(RELEASE_AUDIO_PATCH, data, &reply); + if (status != NO_ERROR) { + status = (status_t)reply.readInt32(); + } + return status; + } + + virtual status_t listAudioPatches(unsigned int *num_patches, + struct audio_patch *patches, + unsigned int *generation) + { + if (num_patches == NULL || (*num_patches != 0 && patches == NULL) || + generation == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + unsigned int numPatchesReq = (patches == NULL) ? 0 : *num_patches; + data.writeInt32(numPatchesReq); + status_t status = remote()->transact(LIST_AUDIO_PATCHES, data, &reply); + if (status == NO_ERROR) { + status = (status_t)reply.readInt32(); + *num_patches = (unsigned int)reply.readInt32(); + } + if (status == NO_ERROR) { + if (numPatchesReq > *num_patches) { + numPatchesReq = *num_patches; + } + if (numPatchesReq > 0) { + reply.read(patches, numPatchesReq * sizeof(struct audio_patch)); + } + *generation = reply.readInt32(); + } + return status; + } + + virtual status_t setAudioPortConfig(const struct audio_port_config *config) + { + if (config == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(config, sizeof(struct audio_port_config)); + status_t status = remote()->transact(SET_AUDIO_PORT_CONFIG, data, &reply); + if (status != NO_ERROR) { + status = (status_t)reply.readInt32(); + } + return status; + } }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -687,6 +820,97 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } + case LIST_AUDIO_PORTS: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + audio_port_role_t role = (audio_port_role_t)data.readInt32(); + audio_port_type_t type = (audio_port_type_t)data.readInt32(); + unsigned int numPortsReq = data.readInt32(); + unsigned int numPorts = numPortsReq; + unsigned int generation; + struct audio_port *ports = + (struct audio_port *)calloc(numPortsReq, sizeof(struct audio_port)); + status_t status = listAudioPorts(role, type, &numPorts, ports, &generation); + reply->writeInt32(status); + reply->writeInt32(numPorts); + ALOGI("LIST_AUDIO_PORTS status %d got numPorts %d", status, numPorts); + + if (status == NO_ERROR) { + if (numPortsReq > numPorts) { + numPortsReq = numPorts; + } + reply->write(ports, numPortsReq * sizeof(struct audio_port)); + reply->writeInt32(generation); + } + free(ports); + return NO_ERROR; + } + + case GET_AUDIO_PORT: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + struct audio_port port; + data.read(&port, sizeof(struct audio_port)); + status_t status = getAudioPort(&port); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->write(&port, sizeof(struct audio_port)); + } + return NO_ERROR; + } + + case CREATE_AUDIO_PATCH: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + struct audio_patch patch; + data.read(&patch, sizeof(struct audio_patch)); + audio_patch_handle_t handle; + data.read(&handle, sizeof(audio_patch_handle_t)); + status_t status = createAudioPatch(&patch, &handle); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->write(&handle, sizeof(audio_patch_handle_t)); + } + return NO_ERROR; + } + + case RELEASE_AUDIO_PATCH: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + audio_patch_handle_t handle; + data.read(&handle, sizeof(audio_patch_handle_t)); + status_t status = releaseAudioPatch(handle); + reply->writeInt32(status); + return NO_ERROR; + } + + case LIST_AUDIO_PATCHES: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + unsigned int numPatchesReq = data.readInt32(); + unsigned int numPatches = numPatchesReq; + unsigned int generation; + struct audio_patch *patches = + (struct audio_patch *)calloc(numPatchesReq, + sizeof(struct audio_patch)); + status_t status = listAudioPatches(&numPatches, patches, &generation); + reply->writeInt32(status); + reply->writeInt32(numPatches); + if (status == NO_ERROR) { + if (numPatchesReq > numPatches) { + numPatchesReq = numPatches; + } + reply->write(patches, numPatchesReq * sizeof(struct audio_patch)); + reply->writeInt32(generation); + } + free(patches); + return NO_ERROR; + } + + case SET_AUDIO_PORT_CONFIG: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + struct audio_port_config config; + data.read(&config, sizeof(struct audio_port_config)); + status_t status = setAudioPortConfig(&config); + reply->writeInt32(status); + return NO_ERROR; + } + default: return BBinder::onTransact(code, data, reply, flags); } -- cgit v1.1 From dd114d19f65d8a5cdfddbaf6d3ef8119c6169b28 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 28 May 2014 15:23:14 -0700 Subject: Fix some NuPlayer issues. Fixes OnSeekCompleted callback and calling getDuration immediately after prepare(). Change-Id: Ie58c509005cded278a0e50c87240b0a2d920b7d7 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 13 ++++++------- media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 4 ++++ 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index d8d939a..857e703 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1376,16 +1376,15 @@ void NuPlayer::onSourceNotify(const sp &msg) { sp driver = mDriver.promote(); if (driver != NULL) { - driver->notifyPrepareCompleted(err); - } - - int64_t durationUs; - if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) { - sp driver = mDriver.promote(); - if (driver != NULL) { + // notify duration first, so that it's definitely set when + // the app received the "prepare complete" callback. + int64_t durationUs; + if (mSource->getDuration(&durationUs) == OK) { driver->notifyDuration(durationUs); } + driver->notifyPrepareCompleted(err); } + break; } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index e4850f0..280b5af 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -284,6 +284,10 @@ status_t NuPlayerDriver::seekTo(int msec) { case STATE_PREPARED: { mStartupSeekTimeUs = seekTimeUs; + // pretend that the seek completed. It will actually happen when starting playback. + // TODO: actually perform the seek here, so the player is ready to go at the new + // location + notifySeekComplete(); break; } -- cgit v1.1 From 8c6693b73cb4aed9d1dcb8d5d0828a77b7471a55 Mon Sep 17 00:00:00 2001 From: Vignesh Venkatasubramanian Date: Wed, 28 May 2014 07:59:35 -0700 Subject: libstagefright: Add Opus support to ACodec::getPortFormat Bug: 15114855 Change-Id: Idb184ae15986450423fc8cf116cf077600b3ea67 --- media/libstagefright/ACodec.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 8f154be..d3c508d 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -2872,6 +2872,24 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { break; } + case OMX_AUDIO_CodingAndroidOPUS: + { + OMX_AUDIO_PARAM_ANDROID_OPUSTYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + CHECK_EQ((status_t)OK, mOMX->getParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidOpus, + ¶ms, + sizeof(params))); + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_OPUS); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSampleRate); + break; + } + default: ALOGE("UNKNOWN AUDIO CODING: %d\n", audioDef->eEncoding); TRESPASS(); -- cgit v1.1 From 32f93b7bedc44b425ba99d69dec998334e759532 Mon Sep 17 00:00:00 2001 From: Vignesh Venkatasubramanian Date: Wed, 28 May 2014 07:59:35 -0700 Subject: DO NOT MERGE: libstagefright: Add Opus support to ACodec::getPortFormat Bug: 15114855 Change-Id: Idb184ae15986450423fc8cf116cf077600b3ea67 (cherry picked from commit 8c6693b73cb4aed9d1dcb8d5d0828a77b7471a55) --- media/libstagefright/ACodec.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 8f154be..d3c508d 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -2872,6 +2872,24 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { break; } + case OMX_AUDIO_CodingAndroidOPUS: + { + OMX_AUDIO_PARAM_ANDROID_OPUSTYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + CHECK_EQ((status_t)OK, mOMX->getParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidOpus, + ¶ms, + sizeof(params))); + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_OPUS); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSampleRate); + break; + } + default: ALOGE("UNKNOWN AUDIO CODING: %d\n", audioDef->eEncoding); TRESPASS(); -- cgit v1.1 From 17a6dd60f5f8a28af1db451bcbf44805648c844a Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 29 May 2014 07:34:59 -0700 Subject: DO NOT MERGE: MediaCodecList: remove force-added codecs for videoeditor Bug: 15320804 Change-Id: I1c2f0f75aeaabc20cb94e79e47b70f7faefe0a9e --- media/libstagefright/MediaCodecList.cpp | 9 --------- 1 file changed, 9 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index 6248e90..b74b2e2 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -57,15 +57,6 @@ MediaCodecList::MediaCodecList() parseXMLFile(file); - if (mInitCheck == OK) { - // These are currently still used by the video editing suite. - - addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm"); - - addMediaCodec( - false /* encoder */, "OMX.google.raw.decoder", "audio/raw"); - } - #if 0 for (size_t i = 0; i < mCodecInfos.size(); ++i) { const CodecInfo &info = mCodecInfos.itemAt(i); -- cgit v1.1 From dcec687af73ee38d8e0053a378b6bc7d5efe0bb8 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 29 May 2014 07:34:59 -0700 Subject: MediaCodecList: remove force-added codecs for videoeditor Bug: 15320804 Change-Id: I1c2f0f75aeaabc20cb94e79e47b70f7faefe0a9e --- media/libstagefright/MediaCodecList.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index 8a451c8..cd51582 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -70,11 +70,6 @@ void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml) { return; } - // These are currently still used by the video editing suite. - addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm"); - addMediaCodec( - false /* encoder */, "OMX.google.raw.decoder", "audio/raw"); - for (size_t i = mCodecInfos.size(); i-- > 0;) { CodecInfo *info = &mCodecInfos.editItemAt(i); -- cgit v1.1 From eb4860c305def68c5965474bb43c67c2c9d49bbb Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 29 May 2014 08:04:34 -0700 Subject: getSampletime -> getSampleTime Change-Id: I87aaa87be068d414903a0e1e22bfe4183cf45ab0 --- media/ndk/NdkMediaExtractor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp index b0a9590..f9f9ac3 100644 --- a/media/ndk/NdkMediaExtractor.cpp +++ b/media/ndk/NdkMediaExtractor.cpp @@ -205,7 +205,7 @@ int AMediaExtractor_getSampleTrackIndex(AMediaExtractor *mData) { } EXPORT -int64_t AMediaExtractor_getSampletime(AMediaExtractor *mData) { +int64_t AMediaExtractor_getSampleTime(AMediaExtractor *mData) { int64_t time; if (mData->mImpl->getSampleTime(&time) != OK) { return -1; -- cgit v1.1 From d4838ed14a169f5981c0adc2edcb24559a913fe6 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 20 May 2014 18:32:17 -0700 Subject: AAC decoder: compensate limiter delay Add decoder limiter delay compensation to decoder wrapper Includes a wrapper function for SoftAAC2.cpp which selects DRC-related decoder parameters according to information in the bitstream and desired DRC characteristics for different playback modes. Bug 9428126 Change-Id: I5041b68760e95cf54073c3addf2b6026b9cfe8c5 --- media/libstagefright/codecs/aacdec/Android.mk | 3 +- .../codecs/aacdec/DrcPresModeWrap.cpp | 372 +++++++++++ .../libstagefright/codecs/aacdec/DrcPresModeWrap.h | 62 ++ media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 727 +++++++++++++++------ media/libstagefright/codecs/aacdec/SoftAAC2.h | 27 +- 5 files changed, 973 insertions(+), 218 deletions(-) create mode 100644 media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp create mode 100644 media/libstagefright/codecs/aacdec/DrcPresModeWrap.h (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk index 49ff238..afb00aa 100644 --- a/media/libstagefright/codecs/aacdec/Android.mk +++ b/media/libstagefright/codecs/aacdec/Android.mk @@ -3,7 +3,8 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - SoftAAC2.cpp + SoftAAC2.cpp \ + DrcPresModeWrap.cpp LOCAL_C_INCLUDES := \ frameworks/av/media/libstagefright/include \ diff --git a/media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp new file mode 100644 index 0000000..129ad65 --- /dev/null +++ b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2014 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 "DrcPresModeWrap.h" + +#include + +#define LOG_TAG "SoftAAC2_DrcWrapper" +//#define LOG_NDEBUG 0 +#include + +//#define DRC_PRES_MODE_WRAP_DEBUG + +#define GPM_ENCODER_TARGET_LEVEL 64 +#define MAX_TARGET_LEVEL 64 + +CDrcPresModeWrapper::CDrcPresModeWrapper() +{ + mDataUpdate = true; + + /* Data from streamInfo. */ + /* Initialized to the same values as in the aac decoder */ + mStreamPRL = -1; + mStreamDRCPresMode = -1; + mStreamNrAACChan = 0; + mStreamNrOutChan = 0; + + /* Desired values (set by user). */ + /* Initialized to the same values as in the aac decoder */ + mDesTarget = -1; + mDesAttFactor = 0; + mDesBoostFactor = 0; + mDesHeavy = 0; + + mEncoderTarget = -1; + + /* Values from last time. */ + /* Initialized to the same values as the desired values */ + mLastTarget = -1; + mLastAttFactor = 0; + mLastBoostFactor = 0; + mLastHeavy = 0; +} + +CDrcPresModeWrapper::~CDrcPresModeWrapper() +{ +} + +void +CDrcPresModeWrapper::setDecoderHandle(const HANDLE_AACDECODER handle) +{ + mHandleDecoder = handle; +} + +void +CDrcPresModeWrapper::submitStreamData(CStreamInfo* pStreamInfo) +{ + assert(pStreamInfo); + + if (mStreamPRL != pStreamInfo->drcProgRefLev) { + mStreamPRL = pStreamInfo->drcProgRefLev; + mDataUpdate = true; +#ifdef DRC_PRES_MODE_WRAP_DEBUG + ALOGV("DRC presentation mode wrapper: drcProgRefLev is %d\n", mStreamPRL); +#endif + } + + if (mStreamDRCPresMode != pStreamInfo->drcPresMode) { + mStreamDRCPresMode = pStreamInfo->drcPresMode; + mDataUpdate = true; +#ifdef DRC_PRES_MODE_WRAP_DEBUG + ALOGV("DRC presentation mode wrapper: drcPresMode is %d\n", mStreamDRCPresMode); +#endif + } + + if (mStreamNrAACChan != pStreamInfo->aacNumChannels) { + mStreamNrAACChan = pStreamInfo->aacNumChannels; + mDataUpdate = true; +#ifdef DRC_PRES_MODE_WRAP_DEBUG + ALOGV("DRC presentation mode wrapper: aacNumChannels is %d\n", mStreamNrAACChan); +#endif + } + + if (mStreamNrOutChan != pStreamInfo->numChannels) { + mStreamNrOutChan = pStreamInfo->numChannels; + mDataUpdate = true; +#ifdef DRC_PRES_MODE_WRAP_DEBUG + ALOGV("DRC presentation mode wrapper: numChannels is %d\n", mStreamNrOutChan); +#endif + } + + + + if (mStreamNrOutChan -31 dB + if ((mIsStereoDownmix == false) && (mIsMonoDownmix == false)) { + // no stereo or mono downmixing, calculated scaling of light DRC + /* use as little compression as possible */ + newAttFactor = 0; + newBoostFactor = 0; + if (mDesTarget PRL + if (mEncoderTarget < mDesTarget) { // if mEncoderTarget > target level + // mEncoderTarget > target level > PRL + int calcFactor; + float calcFactor_norm; + // 0.0f < calcFactor_norm < 1.0f + calcFactor_norm = (float)(mDesTarget - progRefLevel) / + (float)(mEncoderTarget - progRefLevel); + calcFactor = (int)(calcFactor_norm*127.0f); // 0 <= calcFactor < 127 + // calcFactor is the lower limit + newAttFactor = (calcFactor>newAttFactor) ? calcFactor : newAttFactor; + // new AttFactor will be always = calcFactor, as it is set to 0 before. + newBoostFactor = newAttFactor; + } else { + /* target level > mEncoderTarget > PRL */ + // newTDLimiterEnable = 1; + // the time domain limiter must always be active in this case. + // It is assumed that the framework activates it by default + newAttFactor = 127; + newBoostFactor = 127; + } + } else { // target level <= PRL + // no restrictions required + // newAttFactor = newAttFactor; + } + } else { // downmixing + // if target level > -23 dB or mono downmix + if ( (mDesTarget<92) || mIsMonoDownmix ) { + newHeavy = 1; + } else { + // we perform a downmix, so, we need at least full light DRC + newAttFactor = 127; + } + } + } else { // target level <= -31 dB + // playback -31 dB: light DRC only needed if we perform downmixing + if (mIsDownmix) { // we do downmixing + newAttFactor = 127; + } + } + } + else { // handle other used encoder target levels + + // Sanity check: DRC presentation mode is only specified for max. 5.1 channels + if (mStreamNrAACChan > 6) { + drcPresMode = 0; + } + + switch (drcPresMode) { + case 0: + default: // presentation mode not indicated + { + + if (mDesTarget<124) { // if target level > -31 dB + // no stereo or mono downmixing + if ((mIsStereoDownmix == false) && (mIsMonoDownmix == false)) { + if (mDesTarget PRL + // newTDLimiterEnable = 1; + // the time domain limiter must always be active in this case. + // It is assumed that the framework activates it by default + newAttFactor = 127; // at least, use light compression + } else { // target level <= PRL + // no restrictions required + // newAttFactor = newAttFactor; + } + } else { // downmixing + // newTDLimiterEnable = 1; + // the time domain limiter must always be active in this case. + // It is assumed that the framework activates it by default + + // if target level > -23 dB or mono downmix + if ( (mDesTarget < 92) || mIsMonoDownmix ) { + newHeavy = 1; + } else{ + // we perform a downmix, so, we need at least full light DRC + newAttFactor = 127; + } + } + } else { // target level <= -31 dB + if (mIsDownmix) { // we do downmixing. + // newTDLimiterEnable = 1; + // the time domain limiter must always be active in this case. + // It is assumed that the framework activates it by default + newAttFactor = 127; + } + } + } + break; + + // Presentation mode 1 and 2 according to ETSI TS 101 154: + // Digital Video Broadcasting (DVB); Specification for the use of Video and Audio Coding + // in Broadcasting Applications based on the MPEG-2 Transport Stream, + // section C.5.4., "Decoding", and Table C.33 + // ISO DRC -> newHeavy = 0 (Use light compression, MPEG-style) + // Compression_value -> newHeavy = 1 (Use heavy compression, DVB-style) + // scaling restricted -> newAttFactor = 127 + + case 1: // presentation mode 1, Light:-31/Heavy:-23 + { + if (mDesTarget < 124) { // if target level > -31 dB + // playback up to -23 dB + newHeavy = 1; + } else { // target level <= -31 dB + // playback -31 dB + if (mIsDownmix) { // we do downmixing. + newAttFactor = 127; + } + } + } + break; + + case 2: // presentation mode 2, Light:-23/Heavy:-23 + { + if (mDesTarget < 124) { // if target level > -31 dB + // playback up to -23 dB + if (mIsMonoDownmix) { // if mono downmix + newHeavy = 1; + } else { + newHeavy = 0; + newAttFactor = 127; + } + } else { // target level <= -31 dB + // playback -31 dB + newHeavy = 0; + if (mIsDownmix) { // we do downmixing. + newAttFactor = 127; + } + } + } + break; + + } // switch() + } // if (mEncoderTarget == GPM_ENCODER_TARGET_LEVEL) + + // sanity again + if (newHeavy == 1) { + newBoostFactor=127; // not really needed as the same would be done by the decoder anyway + newAttFactor = 127; + } + + // update the decoder + if (newTarget != mLastTarget) { + aacDecoder_SetParam(mHandleDecoder, AAC_DRC_REFERENCE_LEVEL, newTarget); + mLastTarget = newTarget; +#ifdef DRC_PRES_MODE_WRAP_DEBUG + if (newTarget != mDesTarget) + ALOGV("DRC presentation mode wrapper: forced target level to %d (from %d)\n", newTarget, mDesTarget); + else + ALOGV("DRC presentation mode wrapper: set target level to %d\n", newTarget); +#endif + } + + if (newAttFactor != mLastAttFactor) { + aacDecoder_SetParam(mHandleDecoder, AAC_DRC_ATTENUATION_FACTOR, newAttFactor); + mLastAttFactor = newAttFactor; +#ifdef DRC_PRES_MODE_WRAP_DEBUG + if (newAttFactor != mDesAttFactor) + ALOGV("DRC presentation mode wrapper: forced attenuation factor to %d (from %d)\n", newAttFactor, mDesAttFactor); + else + ALOGV("DRC presentation mode wrapper: set attenuation factor to %d\n", newAttFactor); +#endif + } + + if (newBoostFactor != mLastBoostFactor) { + aacDecoder_SetParam(mHandleDecoder, AAC_DRC_BOOST_FACTOR, newBoostFactor); + mLastBoostFactor = newBoostFactor; +#ifdef DRC_PRES_MODE_WRAP_DEBUG + if (newBoostFactor != mDesBoostFactor) + ALOGV("DRC presentation mode wrapper: forced boost factor to %d (from %d)\n", + newBoostFactor, mDesBoostFactor); + else + ALOGV("DRC presentation mode wrapper: set boost factor to %d\n", newBoostFactor); +#endif + } + + if (newHeavy != mLastHeavy) { + aacDecoder_SetParam(mHandleDecoder, AAC_DRC_HEAVY_COMPRESSION, newHeavy); + mLastHeavy = newHeavy; +#ifdef DRC_PRES_MODE_WRAP_DEBUG + if (newHeavy != mDesHeavy) + ALOGV("DRC presentation mode wrapper: forced heavy compression to %d (from %d)\n", + newHeavy, mDesHeavy); + else + ALOGV("DRC presentation mode wrapper: set heavy compression to %d\n", newHeavy); +#endif + } + +#ifdef DRC_PRES_MODE_WRAP_DEBUG + ALOGV("DRC config: tgt_lev: %3d, cut: %3d, boost: %3d, heavy: %d\n", newTarget, + newAttFactor, newBoostFactor, newHeavy); +#endif + mDataUpdate = false; + + } // if (mDataUpdate) +} diff --git a/media/libstagefright/codecs/aacdec/DrcPresModeWrap.h b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.h new file mode 100644 index 0000000..f0b6cf2 --- /dev/null +++ b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2014 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. + */ +#pragma once +#include "aacdecoder_lib.h" + +typedef enum +{ + DRC_PRES_MODE_WRAP_DESIRED_TARGET = 0x0000, + DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR = 0x0001, + DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR = 0x0002, + DRC_PRES_MODE_WRAP_DESIRED_HEAVY = 0x0003, + DRC_PRES_MODE_WRAP_ENCODER_TARGET = 0x0004 +} DRC_PRES_MODE_WRAP_PARAM; + + +class CDrcPresModeWrapper { +public: + CDrcPresModeWrapper(); + ~CDrcPresModeWrapper(); + void setDecoderHandle(const HANDLE_AACDECODER handle); + void setParam(const DRC_PRES_MODE_WRAP_PARAM param, const int value); + void submitStreamData(CStreamInfo*); + void update(); + +protected: + HANDLE_AACDECODER mHandleDecoder; + int mDesTarget; + int mDesAttFactor; + int mDesBoostFactor; + int mDesHeavy; + + int mEncoderTarget; + + int mLastTarget; + int mLastAttFactor; + int mLastBoostFactor; + int mLastHeavy; + + SCHAR mStreamPRL; + SCHAR mStreamDRCPresMode; + INT mStreamNrAACChan; + INT mStreamNrOutChan; + + bool mIsDownmix; + bool mIsMonoDownmix; + bool mIsStereoDownmix; + + bool mDataUpdate; +}; diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 532e36f..a0e3265 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -25,16 +25,22 @@ #include #include +#include + #define FILEREAD_MAX_LAYERS 2 #define DRC_DEFAULT_MOBILE_REF_LEVEL 64 /* 64*-0.25dB = -16 dB below full scale for mobile conf */ #define DRC_DEFAULT_MOBILE_DRC_CUT 127 /* maximum compression of dynamic range for mobile conf */ #define DRC_DEFAULT_MOBILE_DRC_BOOST 127 /* maximum compression of dynamic range for mobile conf */ +#define DRC_DEFAULT_MOBILE_DRC_HEAVY 1 /* switch for heavy compression for mobile conf */ +#define DRC_DEFAULT_MOBILE_ENC_LEVEL -1 /* encoder target level; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */ #define MAX_CHANNEL_COUNT 8 /* maximum number of audio channels that can be decoded */ // names of properties that can be used to override the default DRC settings #define PROP_DRC_OVERRIDE_REF_LEVEL "aac_drc_reference_level" #define PROP_DRC_OVERRIDE_CUT "aac_drc_cut" #define PROP_DRC_OVERRIDE_BOOST "aac_drc_boost" +#define PROP_DRC_OVERRIDE_HEAVY "aac_drc_heavy" +#define PROP_DRC_OVERRIDE_ENC_LEVEL "aac_drc_enc_target_level" namespace android { @@ -57,18 +63,19 @@ SoftAAC2::SoftAAC2( mStreamInfo(NULL), mIsADTS(false), mInputBufferCount(0), + mOutputBufferCount(0), mSignalledError(false), - mSawInputEos(false), - mSignalledOutputEos(false), - mAnchorTimeUs(0), - mNumSamplesOutput(0), mOutputPortSettingsChange(NONE) { + for (unsigned int i = 0; i < kNumDelayBlocksMax; i++) { + mAnchorTimeUs[i] = 0; + } initPorts(); CHECK_EQ(initDecoder(), (status_t)OK); } SoftAAC2::~SoftAAC2() { aacDecoder_Close(mAACDecoder); + delete mOutputDelayRingBuffer; } void SoftAAC2::initPorts() { @@ -121,36 +128,72 @@ status_t SoftAAC2::initDecoder() { status = OK; } } - mDecoderHasData = false; - // for streams that contain metadata, use the mobile profile DRC settings unless overridden - // by platform properties: + mEndOfInput = false; + mEndOfOutput = false; + mOutputDelayCompensated = 0; + mOutputDelayRingBufferSize = 2048 * MAX_CHANNEL_COUNT * kNumDelayBlocksMax; + mOutputDelayRingBuffer = new short[mOutputDelayRingBufferSize]; + mOutputDelayRingBufferWritePos = 0; + mOutputDelayRingBufferReadPos = 0; + + if (mAACDecoder == NULL) { + ALOGE("AAC decoder is null. TODO: Can not call aacDecoder_SetParam in the following code"); + } + + //aacDecoder_SetParam(mAACDecoder, AAC_PCM_LIMITER_ENABLE, 0); + + //init DRC wrapper + mDrcWrap.setDecoderHandle(mAACDecoder); + mDrcWrap.submitStreamData(mStreamInfo); + + // for streams that contain metadata, use the mobile profile DRC settings unless overridden by platform properties + // TODO: change the DRC settings depending on audio output device type (HDMI, loadspeaker, headphone) char value[PROPERTY_VALUE_MAX]; - // * AAC_DRC_REFERENCE_LEVEL + // DRC_PRES_MODE_WRAP_DESIRED_TARGET if (property_get(PROP_DRC_OVERRIDE_REF_LEVEL, value, NULL)) { unsigned refLevel = atoi(value); - ALOGV("AAC decoder using AAC_DRC_REFERENCE_LEVEL of %d instead of %d", - refLevel, DRC_DEFAULT_MOBILE_REF_LEVEL); - aacDecoder_SetParam(mAACDecoder, AAC_DRC_REFERENCE_LEVEL, refLevel); + ALOGV("AAC decoder using desired DRC target reference level of %d instead of %d", refLevel, + DRC_DEFAULT_MOBILE_REF_LEVEL); + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, refLevel); } else { - aacDecoder_SetParam(mAACDecoder, AAC_DRC_REFERENCE_LEVEL, DRC_DEFAULT_MOBILE_REF_LEVEL); + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, DRC_DEFAULT_MOBILE_REF_LEVEL); } - // * AAC_DRC_ATTENUATION_FACTOR + // DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR if (property_get(PROP_DRC_OVERRIDE_CUT, value, NULL)) { unsigned cut = atoi(value); - ALOGV("AAC decoder using AAC_DRC_ATTENUATION_FACTOR of %d instead of %d", - cut, DRC_DEFAULT_MOBILE_DRC_CUT); - aacDecoder_SetParam(mAACDecoder, AAC_DRC_ATTENUATION_FACTOR, cut); + ALOGV("AAC decoder using desired DRC attenuation factor of %d instead of %d", cut, + DRC_DEFAULT_MOBILE_DRC_CUT); + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, cut); } else { - aacDecoder_SetParam(mAACDecoder, AAC_DRC_ATTENUATION_FACTOR, DRC_DEFAULT_MOBILE_DRC_CUT); + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, DRC_DEFAULT_MOBILE_DRC_CUT); } - // * AAC_DRC_BOOST_FACTOR (note: no default, using cut) + // DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR if (property_get(PROP_DRC_OVERRIDE_BOOST, value, NULL)) { unsigned boost = atoi(value); - ALOGV("AAC decoder using AAC_DRC_BOOST_FACTOR of %d", boost); - aacDecoder_SetParam(mAACDecoder, AAC_DRC_BOOST_FACTOR, boost); + ALOGV("AAC decoder using desired DRC boost factor of %d instead of %d", boost, + DRC_DEFAULT_MOBILE_DRC_BOOST); + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, boost); + } else { + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, DRC_DEFAULT_MOBILE_DRC_BOOST); + } + // DRC_PRES_MODE_WRAP_DESIRED_HEAVY + if (property_get(PROP_DRC_OVERRIDE_HEAVY, value, NULL)) { + unsigned heavy = atoi(value); + ALOGV("AAC decoder using desried DRC heavy compression switch of %d instead of %d", heavy, + DRC_DEFAULT_MOBILE_DRC_HEAVY); + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, heavy); } else { - aacDecoder_SetParam(mAACDecoder, AAC_DRC_BOOST_FACTOR, DRC_DEFAULT_MOBILE_DRC_BOOST); + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, DRC_DEFAULT_MOBILE_DRC_HEAVY); + } + // DRC_PRES_MODE_WRAP_ENCODER_TARGET + if (property_get(PROP_DRC_OVERRIDE_ENC_LEVEL, value, NULL)) { + unsigned encoderRefLevel = atoi(value); + ALOGV("AAC decoder using encoder-side DRC reference level of %d instead of %d", + encoderRefLevel, DRC_DEFAULT_MOBILE_ENC_LEVEL); + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, encoderRefLevel); + } else { + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, DRC_DEFAULT_MOBILE_ENC_LEVEL); } return status; @@ -290,19 +333,101 @@ bool SoftAAC2::isConfigured() const { return mInputBufferCount > 0; } -void SoftAAC2::maybeConfigureDownmix() const { - if (mStreamInfo->numChannels > 2) { - char value[PROPERTY_VALUE_MAX]; - if (!(property_get("media.aac_51_output_enabled", value, NULL) && - (!strcmp(value, "1") || !strcasecmp(value, "true")))) { - ALOGI("Downmixing multichannel AAC to stereo"); - aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, 2); - mStreamInfo->numChannels = 2; - // By default, the decoder creates a 5.1 channel downmix signal - // for seven and eight channel input streams. To enable 6.1 and 7.1 channel output - // use aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1) +void SoftAAC2::configureDownmix() const { + char value[PROPERTY_VALUE_MAX]; + if (!(property_get("media.aac_51_output_enabled", value, NULL) + && (!strcmp(value, "1") || !strcasecmp(value, "true")))) { + ALOGI("limiting to stereo output"); + aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, 2); + // By default, the decoder creates a 5.1 channel downmix signal + // for seven and eight channel input streams. To enable 6.1 and 7.1 channel output + // use aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1) + } +} + +bool SoftAAC2::outputDelayRingBufferPutSamples(INT_PCM *samples, int32_t numSamples) { + if (mOutputDelayRingBufferWritePos + numSamples <= mOutputDelayRingBufferSize + && (mOutputDelayRingBufferReadPos <= mOutputDelayRingBufferWritePos + || mOutputDelayRingBufferReadPos > mOutputDelayRingBufferWritePos + numSamples)) { + // faster memcopy loop without checks, if the preconditions allow this + for (int32_t i = 0; i < numSamples; i++) { + mOutputDelayRingBuffer[mOutputDelayRingBufferWritePos++] = samples[i]; + } + + if (mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferSize) { + mOutputDelayRingBufferWritePos -= mOutputDelayRingBufferSize; + } + if (mOutputDelayRingBufferWritePos == mOutputDelayRingBufferReadPos) { + ALOGE("RING BUFFER OVERFLOW"); + return false; + } + } else { + ALOGV("slow SoftAAC2::outputDelayRingBufferPutSamples()"); + + for (int32_t i = 0; i < numSamples; i++) { + mOutputDelayRingBuffer[mOutputDelayRingBufferWritePos] = samples[i]; + mOutputDelayRingBufferWritePos++; + if (mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferSize) { + mOutputDelayRingBufferWritePos -= mOutputDelayRingBufferSize; + } + if (mOutputDelayRingBufferWritePos == mOutputDelayRingBufferReadPos) { + ALOGE("RING BUFFER OVERFLOW"); + return false; + } + } + } + return true; +} + +int32_t SoftAAC2::outputDelayRingBufferGetSamples(INT_PCM *samples, int32_t numSamples) { + if (mOutputDelayRingBufferReadPos + numSamples <= mOutputDelayRingBufferSize + && (mOutputDelayRingBufferWritePos < mOutputDelayRingBufferReadPos + || mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferReadPos + numSamples)) { + // faster memcopy loop without checks, if the preconditions allow this + if (samples != 0) { + for (int32_t i = 0; i < numSamples; i++) { + samples[i] = mOutputDelayRingBuffer[mOutputDelayRingBufferReadPos++]; + } + } else { + mOutputDelayRingBufferReadPos += numSamples; + } + if (mOutputDelayRingBufferReadPos >= mOutputDelayRingBufferSize) { + mOutputDelayRingBufferReadPos -= mOutputDelayRingBufferSize; + } + } else { + ALOGV("slow SoftAAC2::outputDelayRingBufferGetSamples()"); + + for (int32_t i = 0; i < numSamples; i++) { + if (mOutputDelayRingBufferWritePos == mOutputDelayRingBufferReadPos) { + ALOGE("RING BUFFER UNDERRUN"); + return -1; + } + if (samples != 0) { + samples[i] = mOutputDelayRingBuffer[mOutputDelayRingBufferReadPos]; + } + mOutputDelayRingBufferReadPos++; + if (mOutputDelayRingBufferReadPos >= mOutputDelayRingBufferSize) { + mOutputDelayRingBufferReadPos -= mOutputDelayRingBufferSize; + } } } + return numSamples; +} + +int32_t SoftAAC2::outputDelayRingBufferSamplesAvailable() { + int32_t available = mOutputDelayRingBufferWritePos - mOutputDelayRingBufferReadPos; + if (available < 0) { + available += mOutputDelayRingBufferSize; + } + if (available < 0) { + ALOGE("FATAL RING BUFFER ERROR"); + return 0; + } + return available; +} + +int32_t SoftAAC2::outputDelayRingBufferSamplesLeft() { + return mOutputDelayRingBufferSize - outputDelayRingBufferSamplesAvailable(); } void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { @@ -318,12 +443,11 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { List &outQueue = getPortQueue(1); if (portIndex == 0 && mInputBufferCount == 0) { - ++mInputBufferCount; - BufferInfo *info = *inQueue.begin(); - OMX_BUFFERHEADERTYPE *header = info->mHeader; + BufferInfo *inInfo = *inQueue.begin(); + OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; - inBuffer[0] = header->pBuffer + header->nOffset; - inBufferLength[0] = header->nFilledLen; + inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; + inBufferLength[0] = inHeader->nFilledLen; AAC_DECODER_ERROR decoderErr = aacDecoder_ConfigRaw(mAACDecoder, @@ -331,19 +455,25 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { inBufferLength); if (decoderErr != AAC_DEC_OK) { + ALOGW("aacDecoder_ConfigRaw decoderErr = 0x%4.4x", decoderErr); mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); return; } + mInputBufferCount++; + mOutputBufferCount++; // fake increase of outputBufferCount to keep the counters aligned + + inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); - info->mOwnedByUs = false; - notifyEmptyBufferDone(header); + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + configureDownmix(); // Only send out port settings changed event if both sample rate // and numChannels are valid. if (mStreamInfo->sampleRate && mStreamInfo->numChannels) { - maybeConfigureDownmix(); ALOGI("Initially configuring decoder: %d Hz, %d channels", mStreamInfo->sampleRate, mStreamInfo->numChannels); @@ -355,202 +485,304 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { return; } - while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) { - BufferInfo *inInfo = NULL; - OMX_BUFFERHEADERTYPE *inHeader = NULL; + while ((!inQueue.empty() || mEndOfInput) && !outQueue.empty()) { if (!inQueue.empty()) { - inInfo = *inQueue.begin(); - inHeader = inInfo->mHeader; - } + INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT]; + BufferInfo *inInfo = *inQueue.begin(); + OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; - BufferInfo *outInfo = *outQueue.begin(); - OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; - outHeader->nFlags = 0; - - if (inHeader) { if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { - mSawInputEos = true; + mEndOfInput = true; + } else { + mEndOfInput = false; } - - if (inHeader->nOffset == 0 && inHeader->nFilledLen) { - mAnchorTimeUs = inHeader->nTimeStamp; - mNumSamplesOutput = 0; + if (inHeader->nOffset == 0) { // TODO: does nOffset != 0 happen? + mAnchorTimeUs[mInputBufferCount % kNumDelayBlocksMax] = + inHeader->nTimeStamp; } - if (mIsADTS && inHeader->nFilledLen) { - size_t adtsHeaderSize = 0; - // skip 30 bits, aac_frame_length follows. - // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + inQueue.erase(inQueue.begin()); + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } else { + if (mIsADTS) { + size_t adtsHeaderSize = 0; + // skip 30 bits, aac_frame_length follows. + // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? - const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset; + const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset; - bool signalError = false; - if (inHeader->nFilledLen < 7) { - ALOGE("Audio data too short to contain even the ADTS header. " - "Got %d bytes.", inHeader->nFilledLen); - hexdump(adtsHeader, inHeader->nFilledLen); - signalError = true; - } else { - bool protectionAbsent = (adtsHeader[1] & 1); - - unsigned aac_frame_length = - ((adtsHeader[3] & 3) << 11) - | (adtsHeader[4] << 3) - | (adtsHeader[5] >> 5); - - if (inHeader->nFilledLen < aac_frame_length) { - ALOGE("Not enough audio data for the complete frame. " - "Got %d bytes, frame size according to the ADTS " - "header is %u bytes.", - inHeader->nFilledLen, aac_frame_length); + bool signalError = false; + if (inHeader->nFilledLen < 7) { + ALOGE("Audio data too short to contain even the ADTS header. " + "Got %d bytes.", inHeader->nFilledLen); hexdump(adtsHeader, inHeader->nFilledLen); signalError = true; } else { - adtsHeaderSize = (protectionAbsent ? 7 : 9); + bool protectionAbsent = (adtsHeader[1] & 1); + + unsigned aac_frame_length = + ((adtsHeader[3] & 3) << 11) + | (adtsHeader[4] << 3) + | (adtsHeader[5] >> 5); + + if (inHeader->nFilledLen < aac_frame_length) { + ALOGE("Not enough audio data for the complete frame. " + "Got %d bytes, frame size according to the ADTS " + "header is %u bytes.", + inHeader->nFilledLen, aac_frame_length); + hexdump(adtsHeader, inHeader->nFilledLen); + signalError = true; + } else { + adtsHeaderSize = (protectionAbsent ? 7 : 9); + + inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize; + inBufferLength[0] = aac_frame_length - adtsHeaderSize; + + inHeader->nOffset += adtsHeaderSize; + inHeader->nFilledLen -= adtsHeaderSize; + } + } - inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize; - inBufferLength[0] = aac_frame_length - adtsHeaderSize; + if (signalError) { + mSignalledError = true; - inHeader->nOffset += adtsHeaderSize; - inHeader->nFilledLen -= adtsHeaderSize; + notify(OMX_EventError, + OMX_ErrorStreamCorrupt, + ERROR_MALFORMED, + NULL); + + return; } + } else { + inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; + inBufferLength[0] = inHeader->nFilledLen; } - if (signalError) { - mSignalledError = true; + // Fill and decode + bytesValid[0] = inBufferLength[0]; + + INT prevSampleRate = mStreamInfo->sampleRate; + INT prevNumChannels = mStreamInfo->numChannels; + + aacDecoder_Fill(mAACDecoder, + inBuffer, + inBufferLength, + bytesValid); + + // run DRC check + mDrcWrap.submitStreamData(mStreamInfo); + mDrcWrap.update(); - notify(OMX_EventError, - OMX_ErrorStreamCorrupt, - ERROR_MALFORMED, - NULL); + AAC_DECODER_ERROR decoderErr = + aacDecoder_DecodeFrame(mAACDecoder, + tmpOutBuffer, + 2048 * MAX_CHANNEL_COUNT, + 0 /* flags */); + if (decoderErr != AAC_DEC_OK) { + ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); + } + + if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { + ALOGE("AAC_DEC_NOT_ENOUGH_BITS should never happen"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); return; } - } else { - inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; - inBufferLength[0] = inHeader->nFilledLen; - } - } else { - inBufferLength[0] = 0; - } - // Fill and decode - INT_PCM *outBuffer = reinterpret_cast( - outHeader->pBuffer + outHeader->nOffset); - - bytesValid[0] = inBufferLength[0]; - - int prevSampleRate = mStreamInfo->sampleRate; - int prevNumChannels = mStreamInfo->numChannels; - - AAC_DECODER_ERROR decoderErr = AAC_DEC_NOT_ENOUGH_BITS; - while ((bytesValid[0] > 0 || mSawInputEos) && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { - mDecoderHasData |= (bytesValid[0] > 0); - aacDecoder_Fill(mAACDecoder, - inBuffer, - inBufferLength, - bytesValid); - - decoderErr = aacDecoder_DecodeFrame(mAACDecoder, - outBuffer, - outHeader->nAllocLen, - 0 /* flags */); - if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { - if (mSawInputEos && bytesValid[0] <= 0) { - if (mDecoderHasData) { - // flush out the decoder's delayed data by calling DecodeFrame - // one more time, with the AACDEC_FLUSH flag set - decoderErr = aacDecoder_DecodeFrame(mAACDecoder, - outBuffer, - outHeader->nAllocLen, - AACDEC_FLUSH); - mDecoderHasData = false; + if (bytesValid[0] != 0) { + ALOGE("bytesValid[0] != 0 should never happen"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } + + size_t numOutBytes = + mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; + + if (decoderErr == AAC_DEC_OK) { + if (!outputDelayRingBufferPutSamples(tmpOutBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels)) { + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; } - outHeader->nFlags = OMX_BUFFERFLAG_EOS; - mSignalledOutputEos = true; - break; + UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; + inHeader->nFilledLen -= inBufferUsedLength; + inHeader->nOffset += inBufferUsedLength; } else { - ALOGW("Not enough bits, bytesValid %d", bytesValid[0]); - } - } - } + ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr); - size_t numOutBytes = - mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; + memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow - if (inHeader) { - if (decoderErr == AAC_DEC_OK) { - UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; - inHeader->nFilledLen -= inBufferUsedLength; - inHeader->nOffset += inBufferUsedLength; - } else { - ALOGW("AAC decoder returned error %d, substituting silence", - decoderErr); + if (!outputDelayRingBufferPutSamples(tmpOutBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels)) { + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; + } - memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes); + // Discard input buffer. + inHeader->nFilledLen = 0; - // Discard input buffer. - inHeader->nFilledLen = 0; + aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); - aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); + // fall through + } - // fall through + /* + * AAC+/eAAC+ streams can be signalled in two ways: either explicitly + * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual + * rate system and the sampling rate in the final output is actually + * doubled compared with the core AAC decoder sampling rate. + * + * Explicit signalling is done by explicitly defining SBR audio object + * type in the bitstream. Implicit signalling is done by embedding + * SBR content in AAC extension payload specific to SBR, and hence + * requires an AAC decoder to perform pre-checks on actual audio frames. + * + * Thus, we could not say for sure whether a stream is + * AAC+/eAAC+ until the first data frame is decoded. + */ + if (mOutputBufferCount > 1) { + if (mStreamInfo->sampleRate != prevSampleRate || + mStreamInfo->numChannels != prevNumChannels) { + ALOGE("can not reconfigure AAC output"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; + } + } + if (mInputBufferCount <= 2) { // TODO: <= 1 + if (mStreamInfo->sampleRate != prevSampleRate || + mStreamInfo->numChannels != prevNumChannels) { + ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", + prevSampleRate, mStreamInfo->sampleRate, + prevNumChannels, mStreamInfo->numChannels); + + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + mInputBufferCount++; + inQueue.erase(inQueue.begin()); + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } + return; + } + } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { + ALOGW("Invalid AAC stream"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; + } + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + mInputBufferCount++; + inQueue.erase(inQueue.begin()); + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } else { + ALOGW("inHeader->nFilledLen = %d", inHeader->nFilledLen); + } } + } - if (inHeader->nFilledLen == 0) { - inInfo->mOwnedByUs = false; - inQueue.erase(inQueue.begin()); - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; + int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels; + + if (!mEndOfInput && mOutputDelayCompensated < outputDelay) { + // discard outputDelay at the beginning + int32_t toCompensate = outputDelay - mOutputDelayCompensated; + int32_t discard = outputDelayRingBufferSamplesAvailable(); + if (discard > toCompensate) { + discard = toCompensate; } + int32_t discarded = outputDelayRingBufferGetSamples(0, discard); + mOutputDelayCompensated += discarded; + continue; } - /* - * AAC+/eAAC+ streams can be signalled in two ways: either explicitly - * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual - * rate system and the sampling rate in the final output is actually - * doubled compared with the core AAC decoder sampling rate. - * - * Explicit signalling is done by explicitly defining SBR audio object - * type in the bitstream. Implicit signalling is done by embedding - * SBR content in AAC extension payload specific to SBR, and hence - * requires an AAC decoder to perform pre-checks on actual audio frames. - * - * Thus, we could not say for sure whether a stream is - * AAC+/eAAC+ until the first data frame is decoded. - */ - if (mInputBufferCount <= 2) { - if (mStreamInfo->sampleRate != prevSampleRate || - mStreamInfo->numChannels != prevNumChannels) { - maybeConfigureDownmix(); - ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", - prevSampleRate, mStreamInfo->sampleRate, - prevNumChannels, mStreamInfo->numChannels); - - notify(OMX_EventPortSettingsChanged, 1, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; - return; + if (mEndOfInput) { + while (mOutputDelayCompensated > 0) { + // a buffer big enough for MAX_CHANNEL_COUNT channels of decoded HE-AAC + INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT]; + + // run DRC check + mDrcWrap.submitStreamData(mStreamInfo); + mDrcWrap.update(); + + AAC_DECODER_ERROR decoderErr = + aacDecoder_DecodeFrame(mAACDecoder, + tmpOutBuffer, + 2048 * MAX_CHANNEL_COUNT, + AACDEC_FLUSH); + if (decoderErr != AAC_DEC_OK) { + ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); + } + + int32_t tmpOutBufferSamples = mStreamInfo->frameSize * mStreamInfo->numChannels; + if (tmpOutBufferSamples > mOutputDelayCompensated) { + tmpOutBufferSamples = mOutputDelayCompensated; + } + outputDelayRingBufferPutSamples(tmpOutBuffer, tmpOutBufferSamples); + mOutputDelayCompensated -= tmpOutBufferSamples; } - } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { - ALOGW("Invalid AAC stream"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - return; } - if (decoderErr == AAC_DEC_OK || mNumSamplesOutput > 0) { - // We'll only output data if we successfully decoded it or - // we've previously decoded valid data, in the latter case - // (decode failed) we'll output a silent frame. - outHeader->nFilledLen = numOutBytes; + while (!outQueue.empty() + && outputDelayRingBufferSamplesAvailable() + >= mStreamInfo->frameSize * mStreamInfo->numChannels) { + BufferInfo *outInfo = *outQueue.begin(); + OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; - outHeader->nTimeStamp = - mAnchorTimeUs - + (mNumSamplesOutput * 1000000ll) / mStreamInfo->sampleRate; + if (outHeader->nOffset != 0) { + ALOGE("outHeader->nOffset != 0 is not handled"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } + + INT_PCM *outBuffer = + reinterpret_cast(outHeader->pBuffer + outHeader->nOffset); + if (outHeader->nOffset + + mStreamInfo->frameSize * mStreamInfo->numChannels * sizeof(int16_t) + > outHeader->nAllocLen) { + ALOGE("buffer overflow"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; - mNumSamplesOutput += mStreamInfo->frameSize; + } + int32_t ns = outputDelayRingBufferGetSamples(outBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels); // TODO: check for overflow + if (ns != mStreamInfo->frameSize * mStreamInfo->numChannels) { + ALOGE("not a complete frame of samples available"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } + + outHeader->nFilledLen = mStreamInfo->frameSize * mStreamInfo->numChannels + * sizeof(int16_t); + if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) { + outHeader->nFlags = OMX_BUFFERFLAG_EOS; + mEndOfOutput = true; + } else { + outHeader->nFlags = 0; + } + outHeader->nTimeStamp = mAnchorTimeUs[mOutputBufferCount + % kNumDelayBlocksMax]; + + mOutputBufferCount++; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; @@ -558,8 +790,48 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { outHeader = NULL; } - if (decoderErr == AAC_DEC_OK) { - ++mInputBufferCount; + if (mEndOfInput) { + if (outputDelayRingBufferSamplesAvailable() > 0 + && outputDelayRingBufferSamplesAvailable() + < mStreamInfo->frameSize * mStreamInfo->numChannels) { + ALOGE("not a complete frame of samples available"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } + + if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) { + if (!mEndOfOutput) { + // send empty block signaling EOS + mEndOfOutput = true; + BufferInfo *outInfo = *outQueue.begin(); + OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; + + if (outHeader->nOffset != 0) { + ALOGE("outHeader->nOffset != 0 is not handled"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } + + INT_PCM *outBuffer = reinterpret_cast(outHeader->pBuffer + + outHeader->nOffset); + int32_t ns = 0; + outHeader->nFilledLen = 0; + outHeader->nFlags = OMX_BUFFERFLAG_EOS; + + outHeader->nTimeStamp = mAnchorTimeUs[mOutputBufferCount + % kNumDelayBlocksMax]; + + mOutputBufferCount++; + outInfo->mOwnedByUs = false; + outQueue.erase(outQueue.begin()); + outInfo = NULL; + notifyFillBufferDone(outHeader); + outHeader = NULL; + } + break; // if outQueue not empty but no more output + } } } } @@ -574,34 +846,67 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { // but only if initialization has already happened. if (mInputBufferCount != 0) { mInputBufferCount = 1; - mStreamInfo->sampleRate = 0; } + } else { + while (outputDelayRingBufferSamplesAvailable() > 0) { + int32_t ns = outputDelayRingBufferGetSamples(0, + mStreamInfo->frameSize * mStreamInfo->numChannels); + if (ns != mStreamInfo->frameSize * mStreamInfo->numChannels) { + ALOGE("not a complete frame of samples available"); + } + mOutputBufferCount++; + } + mOutputDelayRingBufferReadPos = mOutputDelayRingBufferWritePos; } } void SoftAAC2::drainDecoder() { - // a buffer big enough for 6 channels of decoded HE-AAC - short buf [2048*6]; - aacDecoder_DecodeFrame(mAACDecoder, - buf, sizeof(buf), AACDEC_FLUSH | AACDEC_CLRHIST | AACDEC_INTR); - aacDecoder_DecodeFrame(mAACDecoder, - buf, sizeof(buf), AACDEC_FLUSH | AACDEC_CLRHIST | AACDEC_INTR); - aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); - mDecoderHasData = false; + int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels; + + // flush decoder until outputDelay is compensated + while (mOutputDelayCompensated > 0) { + // a buffer big enough for MAX_CHANNEL_COUNT channels of decoded HE-AAC + INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT]; + + // run DRC check + mDrcWrap.submitStreamData(mStreamInfo); + mDrcWrap.update(); + + AAC_DECODER_ERROR decoderErr = + aacDecoder_DecodeFrame(mAACDecoder, + tmpOutBuffer, + 2048 * MAX_CHANNEL_COUNT, + AACDEC_FLUSH); + if (decoderErr != AAC_DEC_OK) { + ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); + } + + int32_t tmpOutBufferSamples = mStreamInfo->frameSize * mStreamInfo->numChannels; + if (tmpOutBufferSamples > mOutputDelayCompensated) { + tmpOutBufferSamples = mOutputDelayCompensated; + } + outputDelayRingBufferPutSamples(tmpOutBuffer, tmpOutBufferSamples); + + mOutputDelayCompensated -= tmpOutBufferSamples; + } } void SoftAAC2::onReset() { drainDecoder(); // reset the "configured" state mInputBufferCount = 0; - mNumSamplesOutput = 0; + mOutputBufferCount = 0; + mOutputDelayCompensated = 0; + mOutputDelayRingBufferWritePos = 0; + mOutputDelayRingBufferReadPos = 0; + mEndOfInput = false; + mEndOfOutput = false; + // To make the codec behave the same before and after a reset, we need to invalidate the // streaminfo struct. This does that: - mStreamInfo->sampleRate = 0; + mStreamInfo->sampleRate = 0; // TODO: mStreamInfo is read only mSignalledError = false; - mSawInputEos = false; - mSignalledOutputEos = false; mOutputPortSettingsChange = NONE; } diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h index a7ea1e2..5cde03a 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.h +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h @@ -20,6 +20,7 @@ #include "SimpleSoftOMXComponent.h" #include "aacdecoder_lib.h" +#include "DrcPresModeWrap.h" namespace android { @@ -47,18 +48,19 @@ private: enum { kNumInputBuffers = 4, kNumOutputBuffers = 4, + kNumDelayBlocksMax = 8, }; HANDLE_AACDECODER mAACDecoder; CStreamInfo *mStreamInfo; bool mIsADTS; - bool mDecoderHasData; + bool mIsFirst; size_t mInputBufferCount; + size_t mOutputBufferCount; bool mSignalledError; - bool mSawInputEos; - bool mSignalledOutputEos; - int64_t mAnchorTimeUs; - int64_t mNumSamplesOutput; + int64_t mAnchorTimeUs[kNumDelayBlocksMax]; + + CDrcPresModeWrapper mDrcWrap; enum { NONE, @@ -69,9 +71,22 @@ private: void initPorts(); status_t initDecoder(); bool isConfigured() const; - void maybeConfigureDownmix() const; + void configureDownmix() const; void drainDecoder(); +// delay compensation + bool mEndOfInput; + bool mEndOfOutput; + int32_t mOutputDelayCompensated; + int32_t mOutputDelayRingBufferSize; + short *mOutputDelayRingBuffer; + int32_t mOutputDelayRingBufferWritePos; + int32_t mOutputDelayRingBufferReadPos; + bool outputDelayRingBufferPutSamples(INT_PCM *samples, int numSamples); + int32_t outputDelayRingBufferGetSamples(INT_PCM *samples, int numSamples); + int32_t outputDelayRingBufferSamplesAvailable(); + int32_t outputDelayRingBufferSamplesLeft(); + DISALLOW_EVIL_CONSTRUCTORS(SoftAAC2); }; -- cgit v1.1 From b52c152d553556b2d227ffc943489de0c60b4b02 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 20 May 2014 11:27:36 -0700 Subject: audio policy: add routing update client interface Added IAudioPolicyServiceClient client binder interface for client process to receive notifications from AudioPolicyService when audio ports are added/removed or audio patches created/released. The audio patches owned by a given client are automatically released when this client binder dies. Bug: 14815883. Change-Id: I6013f6aec03b50565cffb1ad2cd1f0f8852032c5 --- media/libmedia/Android.mk | 1 + media/libmedia/AudioSystem.cpp | 30 +++++++++- media/libmedia/IAudioPolicyService.cpp | 17 +++++- media/libmedia/IAudioPolicyServiceClient.cpp | 83 ++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 media/libmedia/IAudioPolicyServiceClient.cpp (limited to 'media') diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index f3770e4..69eead3 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -44,6 +44,7 @@ LOCAL_SRC_FILES:= \ JetPlayer.cpp \ IOMX.cpp \ IAudioPolicyService.cpp \ + IAudioPolicyServiceClient.cpp \ MediaScanner.cpp \ MediaScannerClient.cpp \ CharacterEncodingDetector.cpp \ diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 845ee20..eafb3ad 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -45,6 +45,7 @@ audio_format_t AudioSystem::gPrevInFormat; audio_channel_mask_t AudioSystem::gPrevInChannelMask; size_t AudioSystem::gInBuffSize = 0; // zero indicates cache is invalid +sp AudioSystem::gAudioPortCallback; // establish binder interface to AudioFlinger service const sp& AudioSystem::get_audio_flinger() @@ -528,6 +529,7 @@ void AudioSystem::setErrorCallback(audio_error_callback cb) gAudioErrorCallback = cb; } + bool AudioSystem::routedToA2dpOutput(audio_stream_type_t streamType) { switch (streamType) { @@ -566,6 +568,7 @@ const sp& AudioSystem::get_audio_policy_service() } binder->linkToDeath(gAudioPolicyServiceClient); gAudioPolicyService = interface_cast(binder); + gAudioPolicyService->registerClient(gAudioPolicyServiceClient); gLock.unlock(); } else { gLock.unlock(); @@ -880,14 +883,39 @@ status_t AudioSystem::setAudioPortConfig(const struct audio_port_config *config) return aps->setAudioPortConfig(config); } +void AudioSystem::setAudioPortCallback(sp callBack) +{ + Mutex::Autolock _l(gLock); + gAudioPortCallback = callBack; +} + // --------------------------------------------------------------------------- void AudioSystem::AudioPolicyServiceClient::binderDied(const wp& who __unused) { - Mutex::Autolock _l(AudioSystem::gLock); + Mutex::Autolock _l(gLock); + if (gAudioPortCallback != 0) { + gAudioPortCallback->onServiceDied(); + } AudioSystem::gAudioPolicyService.clear(); ALOGW("AudioPolicyService server died!"); } +void AudioSystem::AudioPolicyServiceClient::onAudioPortListUpdate() +{ + Mutex::Autolock _l(gLock); + if (gAudioPortCallback != 0) { + gAudioPortCallback->onAudioPortListUpdate(); + } +} + +void AudioSystem::AudioPolicyServiceClient::onAudioPatchListUpdate() +{ + Mutex::Autolock _l(gLock); + if (gAudioPortCallback != 0) { + gAudioPortCallback->onAudioPatchListUpdate(); + } +} + }; // namespace android diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index ad2d4eb..eee72c5 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -63,7 +63,8 @@ enum { CREATE_AUDIO_PATCH, RELEASE_AUDIO_PATCH, LIST_AUDIO_PATCHES, - SET_AUDIO_PORT_CONFIG + SET_AUDIO_PORT_CONFIG, + REGISTER_CLIENT }; class BpAudioPolicyService : public BpInterface @@ -524,6 +525,13 @@ public: } return status; } + virtual void registerClient(const sp& client) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeStrongBinder(client->asBinder()); + remote()->transact(REGISTER_CLIENT, data, &reply); + } }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -910,6 +918,13 @@ status_t BnAudioPolicyService::onTransact( reply->writeInt32(status); return NO_ERROR; } + case REGISTER_CLIENT: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + sp client = interface_cast( + data.readStrongBinder()); + registerClient(client); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); diff --git a/media/libmedia/IAudioPolicyServiceClient.cpp b/media/libmedia/IAudioPolicyServiceClient.cpp new file mode 100644 index 0000000..e802277 --- /dev/null +++ b/media/libmedia/IAudioPolicyServiceClient.cpp @@ -0,0 +1,83 @@ +/* + * 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. + */ + +#define LOG_TAG "IAudioPolicyServiceClient" +#include + +#include +#include + +#include + +#include +#include + +namespace android { + +enum { + PORT_LIST_UPDATE = IBinder::FIRST_CALL_TRANSACTION, + PATCH_LIST_UPDATE +}; + +class BpAudioPolicyServiceClient : public BpInterface +{ +public: + BpAudioPolicyServiceClient(const sp& impl) + : BpInterface(impl) + { + } + + void onAudioPortListUpdate() + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyServiceClient::getInterfaceDescriptor()); + remote()->transact(PORT_LIST_UPDATE, data, &reply, IBinder::FLAG_ONEWAY); + } + + void onAudioPatchListUpdate() + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyServiceClient::getInterfaceDescriptor()); + remote()->transact(PATCH_LIST_UPDATE, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(AudioPolicyServiceClient, "android.media.IAudioPolicyServiceClient"); + +// ---------------------------------------------------------------------- + +status_t BnAudioPolicyServiceClient::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch (code) { + case PORT_LIST_UPDATE: { + CHECK_INTERFACE(IAudioPolicyServiceClient, data, reply); + onAudioPortListUpdate(); + return NO_ERROR; + } break; + case PATCH_LIST_UPDATE: { + CHECK_INTERFACE(IAudioPolicyServiceClient, data, reply); + onAudioPatchListUpdate(); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android -- cgit v1.1 From c7a11b2208aa8f1e6a39eb70a136fbc0dafd3260 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 30 May 2014 10:13:25 -0700 Subject: Disable verbose logging Change-Id: If9c87615707ed67f209258f9207d56f671cd0f08 --- media/ndk/NdkMediaCodec.cpp | 2 +- media/ndk/NdkMediaCrypto.cpp | 2 +- media/ndk/NdkMediaDrm.cpp | 2 +- media/ndk/NdkMediaExtractor.cpp | 2 +- media/ndk/NdkMediaFormat.cpp | 2 +- media/ndk/NdkMediaMuxer.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index 2ac16c7..c5d8858 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaCodec" #include "NdkMediaCodec.h" diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp index cbadea5..1cc2f1a 100644 --- a/media/ndk/NdkMediaCrypto.cpp +++ b/media/ndk/NdkMediaCrypto.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaCrypto" diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp index a0cbb70..7a1048c 100644 --- a/media/ndk/NdkMediaDrm.cpp +++ b/media/ndk/NdkMediaDrm.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaDrm" #include "NdkMediaDrm.h" diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp index f9f9ac3..492e002 100644 --- a/media/ndk/NdkMediaExtractor.cpp +++ b/media/ndk/NdkMediaExtractor.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaExtractor" diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp index 77018ec..67dc2c2 100644 --- a/media/ndk/NdkMediaFormat.cpp +++ b/media/ndk/NdkMediaFormat.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaFormat" diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp index 50fc336..b1b0362 100644 --- a/media/ndk/NdkMediaMuxer.cpp +++ b/media/ndk/NdkMediaMuxer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaMuxer" -- cgit v1.1 From 6dbb5e3336cfff1ad51d429fcb847307c06efd61 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 13 May 2014 10:38:42 -0700 Subject: Use of fast capture by normal capture Will only configure fast capture path if the input buffer size is less than 10 ms and the input sample rate is same as the primary output sample rate. Change-Id: I4a7cdc6069d750845412c626d27e83f72a1ab397 --- media/libmedia/AudioTrackShared.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index 219dbfd..0dbfa62 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -134,10 +134,17 @@ status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *reques ssize_t filled = rear - front; // pipe should not be overfull if (!(0 <= filled && (size_t) filled <= mFrameCount)) { - ALOGE("Shared memory control block is corrupt (filled=%d); shutting down", filled); - mIsShutdown = true; - status = NO_INIT; - goto end; + if (mIsOut) { + ALOGE("Shared memory control block is corrupt (filled=%d, mFrameCount=%u); " + "shutting down", filled, mFrameCount); + mIsShutdown = true; + status = NO_INIT; + goto end; + } + // for input, sync up on overrun + filled = 0; + cblk->u.mStreaming.mFront = rear; + (void) android_atomic_or(CBLK_OVERRUN, &cblk->mFlags); } // don't allow filling pipe beyond the nominal size size_t avail = mIsOut ? mFrameCount - filled : filled; -- cgit v1.1 From 8c472f09e49884146ef7d83917ec482208d320c2 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Mon, 2 Jun 2014 22:57:26 -0700 Subject: DNG: Add additional TIFF/EP tag definitions. Bug: 15112503 Change-Id: Ib06d9a5e70e6e3d5063a95a7109538ef64f03334 --- media/img_utils/include/img_utils/TagDefinitions.h | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'media') diff --git a/media/img_utils/include/img_utils/TagDefinitions.h b/media/img_utils/include/img_utils/TagDefinitions.h index 9232e58..6cc42b2 100644 --- a/media/img_utils/include/img_utils/TagDefinitions.h +++ b/media/img_utils/include/img_utils/TagDefinitions.h @@ -172,8 +172,14 @@ enum { TAG_ARTIST = 0x013Bu, TAG_EXIFVERSION = 0x9000u, TAG_CFAREPEATPATTERNDIM = 0x828Du, + TAG_DATETIMEORIGINAL = 0x9003u, TAG_CFAPATTERN = 0x828Eu, TAG_SUBIFDS = 0x014Au, + TAG_TIFFEPSTANDARDID = 0x9216u, + TAG_EXPOSURETIME = 0x829Au, + TAG_ISOSPEEDRATINGS = 0x8827u, + TAG_FOCALLENGTH = 0x920Au, + TAG_FNUMBER = 0x829Du, }; /** @@ -208,6 +214,48 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { 2, UNDEFINED_ENDIAN }, + { // DateTimeOriginal + 0x9003u, + ASCII, + IFD_0, + 20, + UNDEFINED_ENDIAN + }, + { // Tiff/EPStandardID + 0x9216u, + BYTE, + IFD_0, + 4, + UNDEFINED_ENDIAN + }, + { // ExposureTime + 0x829Au, + RATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // ISOSpeedRatings + 0x8827u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // FocalLength + 0x920Au, + RATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // FNumber + 0x829Du, + RATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, /*TODO: Remaining TIFF EP tags*/ }; -- cgit v1.1 From 63141c4356b4f885d3926247df508df3515e41a7 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 2 Jun 2014 15:40:15 -0700 Subject: Fix typos, remove callback functions - do not merge b/15414091 Change-Id: I2f7b7ea6a7943a808de2c6a54fe810eefdee133e --- media/ndk/NdkMediaCodec.cpp | 6 ++++-- media/ndk/NdkMediaCrypto.cpp | 2 +- media/ndk/NdkMediaDrm.cpp | 2 +- media/ndk/NdkMediaExtractor.cpp | 4 ++-- media/ndk/NdkMediaFormat.cpp | 2 +- media/ndk/NdkMediaMuxer.cpp | 2 +- 6 files changed, 10 insertions(+), 8 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index bd2541f..c5d8858 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaCodec" #include "NdkMediaCodec.h" @@ -61,6 +61,8 @@ public: virtual void onMessageReceived(const sp &msg); }; +typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata); + struct AMediaCodec { sp mCodec; sp mLooper; @@ -347,7 +349,7 @@ media_status_t AMediaCodec_releaseOutputBufferAtTime( return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs)); } -EXPORT +//EXPORT media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) { mData->mCallback = callback; mData->mCallbackUserData = userdata; diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp index cbadea5..1cc2f1a 100644 --- a/media/ndk/NdkMediaCrypto.cpp +++ b/media/ndk/NdkMediaCrypto.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaCrypto" diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp index a0cbb70..7a1048c 100644 --- a/media/ndk/NdkMediaDrm.cpp +++ b/media/ndk/NdkMediaDrm.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaDrm" #include "NdkMediaDrm.h" diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp index b0a9590..492e002 100644 --- a/media/ndk/NdkMediaExtractor.cpp +++ b/media/ndk/NdkMediaExtractor.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaExtractor" @@ -205,7 +205,7 @@ int AMediaExtractor_getSampleTrackIndex(AMediaExtractor *mData) { } EXPORT -int64_t AMediaExtractor_getSampletime(AMediaExtractor *mData) { +int64_t AMediaExtractor_getSampleTime(AMediaExtractor *mData) { int64_t time; if (mData->mImpl->getSampleTime(&time) != OK) { return -1; diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp index 77018ec..67dc2c2 100644 --- a/media/ndk/NdkMediaFormat.cpp +++ b/media/ndk/NdkMediaFormat.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaFormat" diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp index 50fc336..b1b0362 100644 --- a/media/ndk/NdkMediaMuxer.cpp +++ b/media/ndk/NdkMediaMuxer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaMuxer" -- cgit v1.1 From a121f90f388343dc48793cbc7eb899aba42e7664 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 3 Jun 2014 13:32:54 -0700 Subject: audio policy: new setAudioPortConfig implementation Rewrite setAudioPortConfig() to take advantage of the new AudioPortConfig class. The configuration is now checked against AudioPort capabilities and stored in the AudioPortConfig. Fix a bug where the config mask was not set properly when calling setAudioPortConfig at the PatchPanel interface. Remove debug log in IAudioPolicyService. Bug: 14815883. Change-Id: I7eb7683a96e049581c13f2a212486507883d008d --- media/libmedia/IAudioPolicyService.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index eee72c5..77d131b 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -421,7 +421,6 @@ public: status = (status_t)reply.readInt32(); *num_ports = (unsigned int)reply.readInt32(); } - ALOGI("listAudioPorts() status %d got *num_ports %d", status, *num_ports); if (status == NO_ERROR) { if (numPortsReq > *num_ports) { numPortsReq = *num_ports; @@ -840,7 +839,6 @@ status_t BnAudioPolicyService::onTransact( status_t status = listAudioPorts(role, type, &numPorts, ports, &generation); reply->writeInt32(status); reply->writeInt32(numPorts); - ALOGI("LIST_AUDIO_PORTS status %d got numPorts %d", status, numPorts); if (status == NO_ERROR) { if (numPortsReq > numPorts) { -- cgit v1.1 From ee777157c12a02e7350e18d49f7571b1222dfa69 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Mon, 2 Jun 2014 22:57:26 -0700 Subject: DNG: Add additional TIFF/EP tag definitions. Bug: 15112503 Change-Id: Ib06d9a5e70e6e3d5063a95a7109538ef64f03334 --- media/img_utils/include/img_utils/TagDefinitions.h | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'media') diff --git a/media/img_utils/include/img_utils/TagDefinitions.h b/media/img_utils/include/img_utils/TagDefinitions.h index 9232e58..6cc42b2 100644 --- a/media/img_utils/include/img_utils/TagDefinitions.h +++ b/media/img_utils/include/img_utils/TagDefinitions.h @@ -172,8 +172,14 @@ enum { TAG_ARTIST = 0x013Bu, TAG_EXIFVERSION = 0x9000u, TAG_CFAREPEATPATTERNDIM = 0x828Du, + TAG_DATETIMEORIGINAL = 0x9003u, TAG_CFAPATTERN = 0x828Eu, TAG_SUBIFDS = 0x014Au, + TAG_TIFFEPSTANDARDID = 0x9216u, + TAG_EXPOSURETIME = 0x829Au, + TAG_ISOSPEEDRATINGS = 0x8827u, + TAG_FOCALLENGTH = 0x920Au, + TAG_FNUMBER = 0x829Du, }; /** @@ -208,6 +214,48 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { 2, UNDEFINED_ENDIAN }, + { // DateTimeOriginal + 0x9003u, + ASCII, + IFD_0, + 20, + UNDEFINED_ENDIAN + }, + { // Tiff/EPStandardID + 0x9216u, + BYTE, + IFD_0, + 4, + UNDEFINED_ENDIAN + }, + { // ExposureTime + 0x829Au, + RATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // ISOSpeedRatings + 0x8827u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // FocalLength + 0x920Au, + RATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // FNumber + 0x829Du, + RATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, /*TODO: Remaining TIFF EP tags*/ }; -- cgit v1.1 From b7a11d83f749ad0200778c4815e907d011d4b5d3 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 18 Apr 2014 17:40:41 -0700 Subject: add sound trigger native service Change-Id: I0cd954c1c7d28a334e786d0004431d4f6a1227ec --- media/mediaserver/Android.mk | 6 ++++-- media/mediaserver/main_mediaserver.cpp | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk index 786bf0d..3a280f0 100644 --- a/media/mediaserver/Android.mk +++ b/media/mediaserver/Android.mk @@ -25,7 +25,8 @@ LOCAL_SHARED_LIBRARIES := \ libmediaplayerservice \ libutils \ liblog \ - libbinder + libbinder \ + libsoundtriggerservice LOCAL_STATIC_LIBRARIES := \ libregistermsext @@ -36,7 +37,8 @@ LOCAL_C_INCLUDES := \ frameworks/av/services/audioflinger \ frameworks/av/services/audiopolicy \ frameworks/av/services/camera/libcameraservice \ - $(call include-path-for, audio-utils) + $(call include-path-for, audio-utils) \ + frameworks/av/services/soundtrigger LOCAL_MODULE:= mediaserver LOCAL_32_BIT_ONLY := true diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp index a347951..af1c9e6 100644 --- a/media/mediaserver/main_mediaserver.cpp +++ b/media/mediaserver/main_mediaserver.cpp @@ -34,6 +34,7 @@ #include "MediaLogService.h" #include "MediaPlayerService.h" #include "AudioPolicyService.h" +#include "SoundTriggerHwService.h" using namespace android; @@ -128,6 +129,7 @@ int main(int argc __unused, char** argv) MediaPlayerService::instantiate(); CameraService::instantiate(); AudioPolicyService::instantiate(); + SoundTriggerHwService::instantiate(); registerExtensions(); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); -- cgit v1.1 From 3fe1435e28dc6959e410740feea89ca1bf4f4fc1 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Wed, 4 Jun 2014 15:35:21 -0700 Subject: DNG: Fix OpcodeList2 length field. Bug: 15432434 Change-Id: I2a0e017f72c31cdbd30df1fdb32cdd5ff4af3649 --- media/img_utils/src/DngUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp index 788dfc8..14b31ec 100644 --- a/media/img_utils/src/DngUtils.cpp +++ b/media/img_utils/src/DngUtils.cpp @@ -19,7 +19,7 @@ namespace android { namespace img_utils { -OpcodeListBuilder::OpcodeListBuilder() : mOpList(), mEndianOut(&mOpList, BIG) { +OpcodeListBuilder::OpcodeListBuilder() : mCount(0), mOpList(), mEndianOut(&mOpList, BIG) { if(mEndianOut.open() != OK) { ALOGE("%s: Open failed.", __FUNCTION__); } -- cgit v1.1 From c263ca0ad8b6bdf5b0693996bc5f2f5916e0cd49 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 4 Jun 2014 20:31:46 -0700 Subject: Squashed commit of the following: commit 9128d6ffec43731d723f9b394f243d940f4c7e41 Author: Glenn Kasten Date: Tue May 13 10:38:42 2014 -0700 Use of fast capture by normal capture Will only configure fast capture path if the input buffer size is less than 10 ms and the input sample rate is same as the primary output sample rate. Change-Id: I4a7cdc6069d750845412c626d27e83f72a1ab397 commit 2e5e0806a5abe7499848358ef5fde5c26405000d Author: Glenn Kasten Date: Mon Jun 2 08:29:22 2014 -0700 Add mPrimaryOutputSampleRate Change-Id: I46b527fc3f2b5a5720a74b4f0b9a8f2e0d570b09 commit baf1d73467923996d1b1f2a9237260cc5697e050 Author: Andy Hung Date: Fri May 30 10:42:03 2014 -0700 Change parameter type for volume to float in AudioMixer Change-Id: I4da1505ce852505f86f8e5b87f60e8edceeb30e0 commit 40fe20fa9760cd03c69778c2021cf7a490d75ece Author: Andy Hung Date: Fri May 30 10:35:47 2014 -0700 Rename UNITY_GAIN to UNITY_GAIN_INT in AudioMixer Change-Id: Ic040311305026f0b4c4280a5b3bef7a447ac1da3 commit 37c9a2b49f876abc5ff537a9ec036d7f0a423775 Author: Andy Hung Date: Thu May 29 21:33:13 2014 -0700 Refactor setVolumeRampVariables in AudioMixer Change-Id: I8fcf3101bcea292de7c65433fa578f1c9cdd0974 commit 397070eca31f121d5d3993de1bfea99aaea5d4f3 Author: Andy Hung Date: Thu May 29 18:52:38 2014 -0700 Fix floating point output from mixer A buffer pointer was being erroneously reset to buffer start, potentially causing an audio glitch. The floating point output mode is not enabled at this time, but will be in the future. Change-Id: If8b6414d232f064f3a2e2c5a6da889a91b27fb24 commit 2e61aa5b33b2247bbc5d4eaa0b519df9accd4bbc Author: Andy Hung Date: Fri May 23 21:22:17 2014 -0700 Add multiple format capability to FastMixer Floating point data from MixerThread into FastMixer. Multiple output format capability from FastMixer to Sink. Change-Id: I0da17810ee71381a39a006c46faec71108d22c26 commit b9ea653c702a785bbd23a66c5e588d40b4192c4e Author: Andy Hung Date: Thu May 29 15:53:09 2014 -0700 Avoid resetting BufferProviders in mixer unnecessarily Change-Id: Iad85c4dfd21be1dbf89dc11906106b34219376f8 commit 7f1a6d6da21c616f80cf9ba21bea11b419ec561b Author: Andy Hung Date: Tue May 27 12:32:17 2014 -0700 Update dynamic resampler buffer fetching Make the criteria tight for fetching to avoid storing excessive frame data internal to the resampler. This should reduce jitter in frame delivery computation. Bug: 14962343 Change-Id: I7adaf714d11c272696ccdbf218bda994c7217477 commit b5e4aac07b9a02f0c803c090058602b03ac09ebb Author: Glenn Kasten Date: Tue May 27 12:30:54 2014 -0700 Allow kFastTrackMultiplier to be specified per device Change-Id: I4eaaaf038df720cec4f5d9221d1b632970f9e3dd commit b93cd97a52af31122df2da2cc0415cda888c8c73 Author: Andy Hung Date: Fri May 23 21:13:31 2014 -0700 Rename mixBuffer to mMixerBuffer in FastMixer Likewise mixBufferState becomes mMixerBufferState. This harmonizes with the naming in AF::MixerThread. Change-Id: I1255d7c07cc2c6ee925d7430925236d2bd163122 commit 8340758622b9711365a8801806cbdf934803c63f Author: Andy Hung Date: Mon May 12 16:51:41 2014 -0700 Add multiple format capability to AudioMixer Change-Id: I04ac1cafd90b6ed652f8d51888ad07576678f0bc Signed-off-by: Andy Hung commit 6b695b9d094820c232a897a3fabbe83d2b7193fe Author: Glenn Kasten Date: Thu Mar 13 14:59:31 2014 -0700 Start adding FastCapture based on FastThread WIP This version supports at most one fast capture client. Change-Id: Idf609bfc80ae22433433d66a5232c043c65506df commit e951ad05a2c388471d7e2806d91e7d51325a150a Author: Glenn Kasten Date: Mon May 12 11:06:26 2014 -0700 Move validation of frameCount from set to openRecord_l This move is needed because frameCount is validated on server side for fast tracks (as should be done for normal tracks too). Change-Id: I6d99e80869fd90fab373cf60ef348c01f075fbca commit 73e76992dbba794894837c38e5472312ea829cf3 Author: Glenn Kasten Date: Tue May 13 10:41:52 2014 -0700 Allow track buffer "allocation" to be from pipe Change-Id: Ib9ac170f8e8b7746b3588157a56cbee3b753a1cb commit 60de1d7ded05c6304037d4858b401094b1d2b4d3 Author: Andy Hung Date: Fri May 9 15:02:21 2014 -0700 Add format parameter to getTrackName() and track_t Change-Id: Ia152a839014e235fbfb656104c15d7c1b456d02e Signed-off-by: Andy Hung Change-Id: Ied0ade8b25d23e89bb03319a7e3135c238f735b9 --- media/libmedia/AudioRecord.cpp | 42 +++++++++++++++++++++---------------- media/libmedia/AudioTrackShared.cpp | 15 +++++++++---- 2 files changed, 35 insertions(+), 22 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 1c808d0..db61e85 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -203,23 +203,6 @@ status_t AudioRecord::set( mFrameSize = sizeof(uint8_t); } - // validate framecount - size_t minFrameCount; - status_t status = AudioRecord::getMinFrameCount(&minFrameCount, - sampleRate, format, channelMask); - if (status != NO_ERROR) { - ALOGE("getMinFrameCount() failed for sampleRate %u, format %#x, channelMask %#x; status %d", - sampleRate, format, channelMask, status); - return status; - } - ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount); - - if (frameCount == 0) { - frameCount = minFrameCount; - } else if (frameCount < minFrameCount) { - ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount); - return BAD_VALUE; - } // mFrameCount is initialized in openRecord_l mReqFrameCount = frameCount; @@ -242,7 +225,7 @@ status_t AudioRecord::set( } // create the IAudioRecord - status = openRecord_l(0 /*epoch*/); + status_t status = openRecord_l(0 /*epoch*/); if (status != NO_ERROR) { if (mAudioRecordThread != 0) { @@ -464,6 +447,29 @@ status_t AudioRecord::openRecord_l(size_t epoch) size_t frameCount = mReqFrameCount; if (!(mFlags & AUDIO_INPUT_FLAG_FAST)) { + // validate framecount + // If fast track was not requested, this preserves + // the old behavior of validating on client side. + // FIXME Eventually the validation should be done on server side + // regardless of whether it's a fast or normal track. It's debatable + // whether to account for the input latency to provision buffers appropriately. + size_t minFrameCount; + status = AudioRecord::getMinFrameCount(&minFrameCount, + mSampleRate, mFormat, mChannelMask); + if (status != NO_ERROR) { + ALOGE("getMinFrameCount() failed for sampleRate %u, format %#x, channelMask %#x; " + "status %d", + mSampleRate, mFormat, mChannelMask, status); + return status; + } + + if (frameCount == 0) { + frameCount = minFrameCount; + } else if (frameCount < minFrameCount) { + ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount); + return BAD_VALUE; + } + // Make sure that application is notified with sufficient margin before overrun if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/2) { mNotificationFramesAct = frameCount/2; diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index 219dbfd..0dbfa62 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -134,10 +134,17 @@ status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *reques ssize_t filled = rear - front; // pipe should not be overfull if (!(0 <= filled && (size_t) filled <= mFrameCount)) { - ALOGE("Shared memory control block is corrupt (filled=%d); shutting down", filled); - mIsShutdown = true; - status = NO_INIT; - goto end; + if (mIsOut) { + ALOGE("Shared memory control block is corrupt (filled=%d, mFrameCount=%u); " + "shutting down", filled, mFrameCount); + mIsShutdown = true; + status = NO_INIT; + goto end; + } + // for input, sync up on overrun + filled = 0; + cblk->u.mStreaming.mFront = rear; + (void) android_atomic_or(CBLK_OVERRUN, &cblk->mFlags); } // don't allow filling pipe beyond the nominal size size_t avail = mIsOut ? mFrameCount - filled : filled; -- cgit v1.1 From 704e72658b1082264a26a83c50046da34f07d1a1 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 4 Jun 2014 16:21:56 -0700 Subject: Added paused state to NuPlayerDecoder This prevents decoder from requesting new buffer until the decoder is resumed, and prevents processing a potential DISCONTINUITY while the player is still flushing. Bug: 13133027 Change-Id: I2f9fa9f00c8583aa6908809cb7c31ddde07cfaf0 --- .../nuplayer/NuPlayerDecoder.cpp | 20 ++++++++++++++++++-- .../libmediaplayerservice/nuplayer/NuPlayerDecoder.h | 2 ++ 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 469c9ca..cfbf282 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -37,6 +37,7 @@ NuPlayer::Decoder::Decoder( : mNotify(notify), mNativeWindow(nativeWindow), mBufferGeneration(0), + mPaused(true), mComponentName("decoder") { // Every decoder has its own looper because MediaCodec operations // are blocking, but NuPlayer needs asynchronous operations. @@ -112,6 +113,7 @@ void NuPlayer::Decoder::onConfigure(const sp &format) { mOutputBuffers.size()); requestCodecNotification(); + mPaused = false; } void NuPlayer::Decoder::requestCodecNotification() { @@ -352,6 +354,11 @@ void NuPlayer::Decoder::onFlush() { sp notify = mNotify->dup(); notify->setInt32("what", kWhatFlushCompleted); notify->post(); + mPaused = true; +} + +void NuPlayer::Decoder::onResume() { + mPaused = false; } void NuPlayer::Decoder::onShutdown() { @@ -380,6 +387,7 @@ void NuPlayer::Decoder::onShutdown() { sp notify = mNotify->dup(); notify->setInt32("what", kWhatShutdownCompleted); notify->post(); + mPaused = true; } void NuPlayer::Decoder::onMessageReceived(const sp &msg) { @@ -397,7 +405,9 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { case kWhatCodecNotify: { if (!isStaleReply(msg)) { - while (handleAnInputBuffer()) { + if (!mPaused) { + while (handleAnInputBuffer()) { + } } while (handleAnOutputBuffer()) { @@ -430,6 +440,12 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { break; } + case kWhatResume: + { + onResume(); + break; + } + case kWhatShutdown: { onShutdown(); @@ -447,7 +463,7 @@ void NuPlayer::Decoder::signalFlush() { } void NuPlayer::Decoder::signalResume() { - // nothing to do + (new AMessage(kWhatResume, id()))->post(); } void NuPlayer::Decoder::initiateShutdown() { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index 94243fc..2892584 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -87,11 +87,13 @@ private: void onConfigure(const sp &format); void onFlush(); + void onResume(); void onInputBufferFilled(const sp &msg); void onRenderBuffer(const sp &msg); void onShutdown(); int32_t mBufferGeneration; + bool mPaused; AString mComponentName; bool supportsSeamlessAudioFormatChange(const sp &targetFormat) const; -- cgit v1.1 From 270facca297275a4889d1cc49ec4d2768ed38bb7 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 5 Jun 2014 15:52:54 -0700 Subject: We still need the raw codec It's used for FLAC and PCM Wav, which output PCM data. b/15320804 Change-Id: I67921a45dd4a3a175fce412e055728859e2309ba --- media/libstagefright/data/media_codecs_google_audio.xml | 1 + 1 file changed, 1 insertion(+) (limited to 'media') diff --git a/media/libstagefright/data/media_codecs_google_audio.xml b/media/libstagefright/data/media_codecs_google_audio.xml index b1f93de..f6db0cc 100644 --- a/media/libstagefright/data/media_codecs_google_audio.xml +++ b/media/libstagefright/data/media_codecs_google_audio.xml @@ -24,6 +24,7 @@ + -- cgit v1.1 From 475300b8ac5438b5037ac088ff599394e9658022 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 5 Jun 2014 16:58:57 -0700 Subject: Make AAC decoder behavior after flush consistent with non-flush Timestamps don't start at zero, but at least they're consistent. Change-Id: I2ce9cd60655a4ece787802902b679fda01cb6182 --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index a0e3265..edb7448 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -846,6 +846,7 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { // but only if initialization has already happened. if (mInputBufferCount != 0) { mInputBufferCount = 1; + mOutputBufferCount = -1; } } else { while (outputDelayRingBufferSamplesAvailable() > 0) { -- cgit v1.1 From a91b538853e94191fbceab5f5050940dd6b96577 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 5 Jun 2014 10:37:26 -0700 Subject: Guard against malformed files b/15433074 Change-Id: I35363def42d38eba49dd5aece566fd345743937e --- media/libstagefright/MPEG4Extractor.cpp | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 05caf75..2e39036 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -478,11 +478,20 @@ status_t MPEG4Extractor::readMetaData() { off64_t offset = 0; status_t err; while (true) { + off64_t orig_offset = offset; err = parseChunk(&offset, 0); - if (err == OK) { + + if (offset <= orig_offset) { + // only continue parsing if the offset was advanced, + // otherwise we might end up in an infinite loop + ALOGE("did not advance: 0x%lld->0x%lld", orig_offset, offset); + err = ERROR_MALFORMED; + break; + } else if (err == OK) { continue; + } else if (err != UNKNOWN_ERROR) { + break; } - uint32_t hdr[2]; if (mDataSource->readAt(offset, hdr, 8) < 8) { break; @@ -505,8 +514,6 @@ status_t MPEG4Extractor::readMetaData() { } else { mFileMetaData->setCString(kKeyMIMEType, "audio/mp4"); } - - mInitCheck = OK; } else { mInitCheck = err; } @@ -758,8 +765,25 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { // The smallest valid chunk is 16 bytes long in this case. return ERROR_MALFORMED; } + } else if (chunk_size == 0) { + if (depth == 0) { + // atom extends to end of file + off64_t sourceSize; + if (mDataSource->getSize(&sourceSize) == OK) { + chunk_size = (sourceSize - *offset); + } else { + // XXX could we just pick a "sufficiently large" value here? + ALOGE("atom size is 0, and data source has no size"); + return ERROR_MALFORMED; + } + } else { + // not allowed for non-toplevel atoms, skip it + *offset += 4; + return OK; + } } else if (chunk_size < 8) { // The smallest valid chunk is 8 bytes long. + ALOGE("invalid chunk size: %d", int(chunk_size)); return ERROR_MALFORMED; } -- cgit v1.1 From 1cfe8ce28eafd5ff758adbb73bfb257503d7704b Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 5 Jun 2014 12:03:56 -0700 Subject: check camera permission for video source other than SURFACE Bug: 15448704 Change-Id: I5f5417037b877a6da3a46700ebb5a80ea59aac36 --- media/libmediaplayerservice/MediaRecorderClient.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp index a9820e0..194abbb 100644 --- a/media/libmediaplayerservice/MediaRecorderClient.cpp +++ b/media/libmediaplayerservice/MediaRecorderClient.cpp @@ -95,7 +95,8 @@ status_t MediaRecorderClient::setPreviewSurface(const sp status_t MediaRecorderClient::setVideoSource(int vs) { ALOGV("setVideoSource(%d)", vs); - if (!checkPermission(cameraPermission)) { + // Check camera permission for sources other than SURFACE + if (vs != VIDEO_SOURCE_SURFACE && !checkPermission(cameraPermission)) { return PERMISSION_DENIED; } Mutex::Autolock lock(mLock); -- cgit v1.1 From 66830855846db5c211c2da6c055ca9b4167e8974 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 5 Jun 2014 14:44:03 -0700 Subject: do not drop TS packet on discontinuity at payload start Bug: 15470543 Change-Id: Ia96a295fbc7e9f1b1d5c0d9091ac62184d44dcfa --- media/libstagefright/mpeg2ts/ATSParser.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index d1afd8b..338e899 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -555,7 +555,9 @@ status_t ATSParser::Stream::parse( } #endif - return OK; + if (!payload_unit_start_indicator) { + return OK; + } } mExpectedContinuityCounter = (continuity_counter + 1) & 0x0f; -- cgit v1.1 From 3b5a6b9fa6c6825a1d0b441429e2bb365b259827 Mon Sep 17 00:00:00 2001 From: Harish Mahendrakar Date: Tue, 20 May 2014 09:30:59 -0700 Subject: stagefright: added support, and SoftOMX decoder, for HEVC also fixed QuerySupportedProfileLevels in SoftVideoDecoderOMXComponent.cpp Bug: 14571712 Change-Id: Ifa3793f7c1b18ac5e8c0a096848c998cabd9e777 --- media/libstagefright/MPEG4Extractor.cpp | 50 +- media/libstagefright/OMXCodec.cpp | 74 ++- media/libstagefright/Utils.cpp | 50 ++ media/libstagefright/codecs/hevcdec/Android.mk | 22 + media/libstagefright/codecs/hevcdec/SoftHEVC.cpp | 710 +++++++++++++++++++++ media/libstagefright/codecs/hevcdec/SoftHEVC.h | 117 ++++ .../data/media_codecs_google_video.xml | 1 + media/libstagefright/omx/SoftOMXPlugin.cpp | 1 + .../omx/SoftVideoDecoderOMXComponent.cpp | 6 +- 9 files changed, 1023 insertions(+), 8 deletions(-) create mode 100644 media/libstagefright/codecs/hevcdec/Android.mk create mode 100644 media/libstagefright/codecs/hevcdec/SoftHEVC.cpp create mode 100644 media/libstagefright/codecs/hevcdec/SoftHEVC.h (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index e07b6aa..76546f3 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -95,6 +95,7 @@ private: uint64_t* mCurrentSampleInfoOffsets; bool mIsAVC; + bool mIsHEVC; size_t mNALLengthSize; bool mStarted; @@ -317,6 +318,9 @@ static const char *FourCC2MIME(uint32_t fourcc) { case FOURCC('a', 'v', 'c', '1'): return MEDIA_MIMETYPE_VIDEO_AVC; + case FOURCC('h', 'v', 'c', '1'): + case FOURCC('h', 'e', 'v', '1'): + return MEDIA_MIMETYPE_VIDEO_HEVC; default: CHECK(!"should not be here."); return NULL; @@ -1288,6 +1292,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('H', '2', '6', '3'): case FOURCC('h', '2', '6', '3'): case FOURCC('a', 'v', 'c', '1'): + case FOURCC('h', 'v', 'c', '1'): + case FOURCC('h', 'e', 'v', '1'): { mHasVideo = true; @@ -1580,6 +1586,21 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { break; } + case FOURCC('h', 'v', 'c', 'C'): + { + sp buffer = new ABuffer(chunk_data_size); + + if (mDataSource->readAt( + data_offset, buffer->data(), chunk_data_size) < chunk_data_size) { + return ERROR_IO; + } + + mLastTrack->meta->setData( + kKeyHVCC, kTypeHVCC, buffer->data(), chunk_data_size); + + *offset += chunk_size; + break; + } case FOURCC('d', '2', '6', '3'): { @@ -2452,6 +2473,11 @@ status_t MPEG4Extractor::verifyTrack(Track *track) { || type != kTypeAVCC) { return ERROR_MALFORMED; } + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) { + if (!track->meta->findData(kKeyHVCC, &type, &data, &size) + || type != kTypeHVCC) { + return ERROR_MALFORMED; + } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { if (!track->meta->findData(kKeyESDS, &type, &data, &size) @@ -2776,6 +2802,7 @@ MPEG4Source::MPEG4Source( mCurrentSampleInfoOffsetsAllocSize(0), mCurrentSampleInfoOffsets(NULL), mIsAVC(false), + mIsHEVC(false), mNALLengthSize(0), mStarted(false), mGroup(NULL), @@ -2800,6 +2827,7 @@ MPEG4Source::MPEG4Source( CHECK(success); mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); + mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC); if (mIsAVC) { uint32_t type; @@ -2814,6 +2842,18 @@ MPEG4Source::MPEG4Source( // The number of bytes used to encode the length of a NAL unit. mNALLengthSize = 1 + (ptr[4] & 3); + } else if (mIsHEVC) { + uint32_t type; + const void *data; + size_t size; + CHECK(format->findData(kKeyHVCC, &type, &data, &size)); + + const uint8_t *ptr = (const uint8_t *)data; + + CHECK(size >= 7); + CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1 + + mNALLengthSize = 1 + (ptr[14 + 7] & 3); } CHECK(format->findInt32(kKeyTrackID, &mTrackId)); @@ -3562,7 +3602,7 @@ status_t MPEG4Source::read( } } - if (!mIsAVC || mWantsNALFragments) { + if ((!mIsAVC && !mIsHEVC) || mWantsNALFragments) { if (newBuffer) { ssize_t num_bytes_read = mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size); @@ -3594,7 +3634,7 @@ status_t MPEG4Source::read( ++mCurrentSampleIndex; } - if (!mIsAVC) { + if (!mIsAVC && !mIsHEVC) { *out = mBuffer; mBuffer = NULL; @@ -3837,7 +3877,7 @@ status_t MPEG4Source::fragmentedRead( bufmeta->setData(kKeyCryptoKey, 0, mCryptoKey, 16); } - if (!mIsAVC || mWantsNALFragments) { + if ((!mIsAVC && !mIsHEVC)|| mWantsNALFragments) { if (newBuffer) { ssize_t num_bytes_read = mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size); @@ -3869,7 +3909,7 @@ status_t MPEG4Source::fragmentedRead( ++mCurrentSampleIndex; } - if (!mIsAVC) { + if (!mIsAVC && !mIsHEVC) { *out = mBuffer; mBuffer = NULL; @@ -4043,6 +4083,8 @@ static bool isCompatibleBrand(uint32_t fourcc) { FOURCC('i', 's', 'o', 'm'), FOURCC('i', 's', 'o', '2'), FOURCC('a', 'v', 'c', '1'), + FOURCC('h', 'v', 'c', '1'), + FOURCC('h', 'e', 'v', '1'), FOURCC('3', 'g', 'p', '4'), FOURCC('m', 'p', '4', '1'), FOURCC('m', 'p', '4', '2'), diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index c028dbf..354712c 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -381,6 +381,57 @@ sp OMXCodec::Create( return NULL; } +status_t OMXCodec::parseHEVCCodecSpecificData( + const void *data, size_t size, + unsigned *profile, unsigned *level) { + const uint8_t *ptr = (const uint8_t *)data; + + // verify minimum size and configurationVersion == 1. + if (size < 7 || ptr[0] != 1) { + return ERROR_MALFORMED; + } + + *profile = (ptr[1] & 31); + *level = ptr[12]; + + ptr += 22; + size -= 22; + + size_t numofArrays = (char)ptr[0]; + ptr += 1; + size -= 1; + size_t j = 0, i = 0; + for (i = 0; i < numofArrays; i++) { + ptr += 1; + size -= 1; + + // Num of nals + size_t numofNals = U16_AT(ptr); + ptr += 2; + size -= 2; + + for (j = 0;j < numofNals;j++) { + if (size < 2) { + return ERROR_MALFORMED; + } + + size_t length = U16_AT(ptr); + + ptr += 2; + size -= 2; + + if (size < length) { + return ERROR_MALFORMED; + } + addCodecSpecificData(ptr, length); + + ptr += length; + size -= length; + } + } + return OK; +} + status_t OMXCodec::parseAVCCodecSpecificData( const void *data, size_t size, unsigned *profile, unsigned *level) { @@ -493,6 +544,20 @@ status_t OMXCodec::configureCodec(const sp &meta) { CODEC_LOGI( "AVC profile = %u (%s), level = %u", profile, AVCProfileToString(profile), level); + } else if (meta->findData(kKeyHVCC, &type, &data, &size)) { + // Parse the HEVCDecoderConfigurationRecord + + unsigned profile, level; + status_t err; + if ((err = parseHEVCCodecSpecificData( + data, size, &profile, &level)) != OK) { + ALOGE("Malformed HEVC codec specific data."); + return err; + } + + CODEC_LOGI( + "HEVC profile = %u , level = %u", + profile, level); } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) { addCodecSpecificData(data, size); @@ -822,6 +887,8 @@ void OMXCodec::setVideoInputFormat( OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused; if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { compressionFormat = OMX_VIDEO_CodingAVC; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { + compressionFormat = OMX_VIDEO_CodingHEVC; } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { compressionFormat = OMX_VIDEO_CodingMPEG4; } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { @@ -1217,6 +1284,8 @@ status_t OMXCodec::setVideoOutputFormat( compressionFormat = OMX_VIDEO_CodingAVC; } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { compressionFormat = OMX_VIDEO_CodingMPEG4; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { + compressionFormat = OMX_VIDEO_CodingHEVC; } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { compressionFormat = OMX_VIDEO_CodingH263; } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_VP8, mime)) { @@ -1411,6 +1480,8 @@ void OMXCodec::setComponentRole( "audio_decoder.g711alaw", "audio_encoder.g711alaw" }, { MEDIA_MIMETYPE_VIDEO_AVC, "video_decoder.avc", "video_encoder.avc" }, + { MEDIA_MIMETYPE_VIDEO_HEVC, + "video_decoder.hevc", "video_encoder.hevc" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "video_decoder.mpeg4", "video_encoder.mpeg4" }, { MEDIA_MIMETYPE_VIDEO_H263, @@ -3009,7 +3080,8 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) { size_t size = specific->mSize; - if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME) + if ((!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME) || + !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mMIME)) && !(mQuirks & kWantsNALFragments)) { static const uint8_t kNALStartCode[4] = { 0x00, 0x00, 0x00, 0x01 }; diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 047fac7..7ff31a1 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -217,6 +217,56 @@ status_t convertMetaDataToMessage( buffer->meta()->setInt32("csd", true); buffer->meta()->setInt64("timeUs", 0); msg->setBuffer("csd-1", buffer); + } else if (meta->findData(kKeyHVCC, &type, &data, &size)) { + const uint8_t *ptr = (const uint8_t *)data; + + CHECK(size >= 7); + CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1 + uint8_t profile = ptr[1] & 31; + uint8_t level = ptr[12]; + ptr += 22; + size -= 22; + + + size_t numofArrays = (char)ptr[0]; + ptr += 1; + size -= 1; + size_t j = 0, i = 0; + + sp buffer = new ABuffer(1024); + buffer->setRange(0, 0); + + for (i = 0; i < numofArrays; i++) { + ptr += 1; + size -= 1; + + //Num of nals + size_t numofNals = U16_AT(ptr); + + ptr += 2; + size -= 2; + + for (j = 0; j < numofNals; j++) { + CHECK(size >= 2); + size_t length = U16_AT(ptr); + + ptr += 2; + size -= 2; + + CHECK(size >= length); + + memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4); + memcpy(buffer->data() + buffer->size() + 4, ptr, length); + buffer->setRange(0, buffer->size() + 4 + length); + + ptr += length; + size -= length; + } + } + buffer->meta()->setInt32("csd", true); + buffer->meta()->setInt64("timeUs", 0); + msg->setBuffer("csd-0", buffer); + } else if (meta->findData(kKeyESDS, &type, &data, &size)) { ESDS esds((const char *)data, size); CHECK_EQ(esds.InitCheck(), (status_t)OK); diff --git a/media/libstagefright/codecs/hevcdec/Android.mk b/media/libstagefright/codecs/hevcdec/Android.mk new file mode 100644 index 0000000..2fe347b --- /dev/null +++ b/media/libstagefright/codecs/hevcdec/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := libstagefright_soft_hevcdec +LOCAL_MODULE_TAGS := optional + +LOCAL_STATIC_LIBRARIES := libhevcdec +LOCAL_SRC_FILES := SoftHEVC.cpp + +LOCAL_C_INCLUDES := $(TOP)/external/libhevc/decoder +LOCAL_C_INCLUDES += $(TOP)/external/libhevc/common +LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include +LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax + +LOCAL_SHARED_LIBRARIES := libstagefright +LOCAL_SHARED_LIBRARIES += libstagefright_omx +LOCAL_SHARED_LIBRARIES += libstagefright_foundation +LOCAL_SHARED_LIBRARIES += libutils +LOCAL_SHARED_LIBRARIES += liblog + + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp new file mode 100644 index 0000000..0aae5ed --- /dev/null +++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp @@ -0,0 +1,710 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoftHEVC" +#include + +#include "ihevc_typedefs.h" +#include "iv.h" +#include "ivd.h" +#include "ithread.h" +#include "ihevcd_cxa.h" +#include "SoftHEVC.h" + +#include +#include +#include + +namespace android { + +#define componentName "video_decoder.hevc" +#define codingType OMX_VIDEO_CodingHEVC +#define CODEC_MIME_TYPE MEDIA_MIMETYPE_VIDEO_HEVC + +/** Function and structure definitions to keep code similar for each codec */ +#define ivdec_api_function ihevcd_cxa_api_function +#define ivdext_init_ip_t ihevcd_cxa_init_ip_t +#define ivdext_init_op_t ihevcd_cxa_init_op_t +#define ivdext_fill_mem_rec_ip_t ihevcd_cxa_fill_mem_rec_ip_t +#define ivdext_fill_mem_rec_op_t ihevcd_cxa_fill_mem_rec_op_t +#define ivdext_ctl_set_num_cores_ip_t ihevcd_cxa_ctl_set_num_cores_ip_t +#define ivdext_ctl_set_num_cores_op_t ihevcd_cxa_ctl_set_num_cores_op_t + +#define IVDEXT_CMD_CTL_SET_NUM_CORES \ + (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES + +static const CodecProfileLevel kProfileLevels[] = { + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel1 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel2 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel21 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel3 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel31 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel4 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel41 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel5 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel51 }, +}; + +SoftHEVC::SoftHEVC( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component) + : SoftVideoDecoderOMXComponent(name, componentName, codingType, + kProfileLevels, ARRAY_SIZE(kProfileLevels), + CODEC_MAX_WIDTH /* width */, CODEC_MAX_HEIGHT /* height */, callbacks, + appData, component) { + initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, + CODEC_MIME_TYPE); + + mOmxColorFormat = OMX_COLOR_FormatYUV420Planar; + mStride = mWidth; + + if (OMX_COLOR_FormatYUV420Planar == mOmxColorFormat) { + mIvColorFormat = IV_YUV_420P; + } else if (OMX_COLOR_FormatYUV420SemiPlanar == mOmxColorFormat) { + mIvColorFormat = IV_YUV_420SP_UV; + } + + mInitWidth = mWidth; + mInitHeight = mHeight; + + CHECK_EQ(initDecoder(), (status_t)OK); +} + +SoftHEVC::~SoftHEVC() { + ALOGD("In SoftHEVC::~SoftHEVC"); + CHECK_EQ(deInitDecoder(), (status_t)OK); +} + +static size_t GetCPUCoreCount() { + long cpuCoreCount = 1; +#if defined(_SC_NPROCESSORS_ONLN) + cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); +#else + // _SC_NPROC_ONLN must be defined... + cpuCoreCount = sysconf(_SC_NPROC_ONLN); +#endif + CHECK(cpuCoreCount >= 1); + ALOGD("Number of CPU cores: %ld", cpuCoreCount); + return (size_t)cpuCoreCount; +} + +status_t SoftHEVC::getVersion() { + ivd_ctl_getversioninfo_ip_t s_ctl_ip; + ivd_ctl_getversioninfo_op_t s_ctl_op; + UWORD8 au1_buf[512]; + IV_API_CALL_STATUS_T status; + + s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; + s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION; + s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t); + s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t); + s_ctl_ip.pv_version_buffer = au1_buf; + s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf); + + status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, + (void *)&s_ctl_op); + + if (status != IV_SUCCESS) { + ALOGE("Error in getting version number: 0x%x", + s_ctl_op.u4_error_code); + } else { + ALOGD("Ittiam decoder version number: %s", + (char *)s_ctl_ip.pv_version_buffer); + } + return OK; +} + +status_t SoftHEVC::setParams(WORD32 stride, IVD_VIDEO_DECODE_MODE_T decMode) { + ivd_ctl_set_config_ip_t s_ctl_ip; + ivd_ctl_set_config_op_t s_ctl_op; + IV_API_CALL_STATUS_T status; + s_ctl_ip.u4_disp_wd = stride; + s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE; + + s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT; + s_ctl_ip.e_vid_dec_mode = decMode; + s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; + s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS; + s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); + s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t); + + ALOGD("Set the run-time (dynamic) parameters"); + status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, + (void *)&s_ctl_op); + + if (status != IV_SUCCESS) { + ALOGE("Error in setting the run-time parameters: 0x%x", + s_ctl_op.u4_error_code); + + return UNKNOWN_ERROR; + } + return OK; +} + +status_t SoftHEVC::resetPlugin() { + mIsInFlush = false; + mReceivedEOS = false; + memset(mTimeStamps, 0, sizeof(mTimeStamps)); + memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); + + /* Initialize both start and end times */ + gettimeofday(&mTimeStart, NULL); + gettimeofday(&mTimeEnd, NULL); + + return OK; +} + +status_t SoftHEVC::resetDecoder() { + ivd_ctl_reset_ip_t s_ctl_ip; + ivd_ctl_reset_op_t s_ctl_op; + IV_API_CALL_STATUS_T status; + + s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; + s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET; + s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t); + s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t); + + status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, + (void *)&s_ctl_op); + if (IV_SUCCESS != status) { + ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code); + return UNKNOWN_ERROR; + } + + /* Set the run-time (dynamic) parameters */ + setParams(0, IVD_DECODE_FRAME); + + /* Set number of cores/threads to be used by the codec */ + setNumCores(); + + return OK; +} + +status_t SoftHEVC::setNumCores() { + ivdext_ctl_set_num_cores_ip_t s_set_cores_ip; + ivdext_ctl_set_num_cores_op_t s_set_cores_op; + IV_API_CALL_STATUS_T status; + s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL; + s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES; + s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES); + s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t); + s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t); + ALOGD("Set number of cores to %u", s_set_cores_ip.u4_num_cores); + status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip, + (void *)&s_set_cores_op); + if (IV_SUCCESS != status) { + ALOGE("Error in setting number of cores: 0x%x", + s_set_cores_op.u4_error_code); + return UNKNOWN_ERROR; + } + return OK; +} + +status_t SoftHEVC::setFlushMode() { + IV_API_CALL_STATUS_T status; + ivd_ctl_flush_ip_t s_video_flush_ip; + ivd_ctl_flush_op_t s_video_flush_op; + + s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL; + s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH; + s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t); + s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t); + ALOGD("Set the decoder in flush mode "); + + /* Set the decoder in Flush mode, subsequent decode() calls will flush */ + status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip, + (void *)&s_video_flush_op); + + if (status != IV_SUCCESS) { + ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status, + s_video_flush_op.u4_error_code); + return UNKNOWN_ERROR; + } + + mIsInFlush = true; + return OK; +} + +status_t SoftHEVC::initDecoder() { + IV_API_CALL_STATUS_T status; + + UWORD32 u4_num_reorder_frames; + UWORD32 u4_num_ref_frames; + UWORD32 u4_share_disp_buf; + WORD32 i4_level; + + mNumCores = GetCPUCoreCount(); + + /* Initialize number of ref and reorder modes (for HEVC) */ + u4_num_reorder_frames = 16; + u4_num_ref_frames = 16; + u4_share_disp_buf = 0; + + if ((mWidth * mHeight) > (1920 * 1088)) { + i4_level = 50; + } else if ((mWidth * mHeight) > (1280 * 720)) { + i4_level = 41; + } else { + i4_level = 31; + } + + { + iv_num_mem_rec_ip_t s_num_mem_rec_ip; + iv_num_mem_rec_op_t s_num_mem_rec_op; + + s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip); + s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op); + s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC; + + ALOGV("Get number of mem records"); + status = ivdec_api_function(mCodecCtx, (void*)&s_num_mem_rec_ip, + (void*)&s_num_mem_rec_op); + if (IV_SUCCESS != status) { + ALOGE("Error in getting mem records: 0x%x", + s_num_mem_rec_op.u4_error_code); + return UNKNOWN_ERROR; + } + + mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec; + } + + mMemRecords = (iv_mem_rec_t*)ivd_aligned_malloc( + 128, mNumMemRecords * sizeof(iv_mem_rec_t)); + if (mMemRecords == NULL) { + ALOGE("Allocation failure"); + return NO_MEMORY; + } + + { + size_t i; + ivdext_fill_mem_rec_ip_t s_fill_mem_ip; + ivdext_fill_mem_rec_op_t s_fill_mem_op; + iv_mem_rec_t *ps_mem_rec; + + s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = + sizeof(ivdext_fill_mem_rec_ip_t); + s_fill_mem_ip.i4_level = i4_level; + s_fill_mem_ip.u4_num_reorder_frames = u4_num_reorder_frames; + s_fill_mem_ip.u4_num_ref_frames = u4_num_ref_frames; + s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf; + s_fill_mem_ip.u4_num_extra_disp_buf = 0; + s_fill_mem_ip.e_output_format = mIvColorFormat; + + s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC; + s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords; + s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = mWidth; + s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = mHeight; + s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size = + sizeof(ivdext_fill_mem_rec_op_t); + + ps_mem_rec = mMemRecords; + for (i = 0; i < mNumMemRecords; i++) + ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t); + + status = ivdec_api_function(mCodecCtx, (void *)&s_fill_mem_ip, + (void *)&s_fill_mem_op); + + if (IV_SUCCESS != status) { + ALOGE("Error in filling mem records: 0x%x", + s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code); + return UNKNOWN_ERROR; + } + mNumMemRecords = + s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled; + + ps_mem_rec = mMemRecords; + + for (i = 0; i < mNumMemRecords; i++) { + ps_mem_rec->pv_base = ivd_aligned_malloc( + ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size); + if (ps_mem_rec->pv_base == NULL) { + ALOGE("Allocation failure for memory record #%zu of size %u", + i, ps_mem_rec->u4_mem_size); + status = IV_FAIL; + return NO_MEMORY; + } + + ps_mem_rec++; + } + } + + /* Initialize the decoder */ + { + ivdext_init_ip_t s_init_ip; + ivdext_init_op_t s_init_op; + + void *dec_fxns = (void *)ivdec_api_function; + + s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t); + s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT; + s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords; + s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = mWidth; + s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight; + + s_init_ip.i4_level = i4_level; + s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames; + s_init_ip.u4_num_ref_frames = u4_num_ref_frames; + s_init_ip.u4_share_disp_buf = u4_share_disp_buf; + s_init_ip.u4_num_extra_disp_buf = 0; + + s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op); + + s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords; + s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat; + + mCodecCtx = (iv_obj_t*)mMemRecords[0].pv_base; + mCodecCtx->pv_fxns = dec_fxns; + mCodecCtx->u4_size = sizeof(iv_obj_t); + + ALOGD("Initializing decoder"); + status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, + (void *)&s_init_op); + if (status != IV_SUCCESS) { + ALOGE("Error in init: 0x%x", + s_init_op.s_ivd_init_op_t.u4_error_code); + return UNKNOWN_ERROR; + } + } + + /* Reset the plugin state */ + resetPlugin(); + + /* Set the run time (dynamic) parameters */ + setParams(0, IVD_DECODE_FRAME); + + /* Set number of cores/threads to be used by the codec */ + setNumCores(); + + /* Get codec version */ + getVersion(); + + /* Allocate internal picture buffer */ + mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, mStride * mHeight * 3 / 2); + if (NULL == mFlushOutBuffer) { + ALOGE("Could not allocate flushOutputBuffer of size %zu", mStride * mHeight * 3 / 2); + return NO_MEMORY; + } + + return OK; +} + +status_t SoftHEVC::deInitDecoder() { + size_t i; + iv_mem_rec_t *ps_mem_rec; + ps_mem_rec = mMemRecords; + ALOGD("Freeing codec memory"); + for (i = 0; i < mNumMemRecords; i++) { + ivd_aligned_free(ps_mem_rec->pv_base); + ps_mem_rec++; + } + + ivd_aligned_free(mMemRecords); + ivd_aligned_free(mFlushOutBuffer); + return OK; +} + +void SoftHEVC::onReset() { + ALOGD("onReset called"); + SoftVideoDecoderOMXComponent::onReset(); + + resetDecoder(); + resetPlugin(); +} + +void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { + ALOGD("onPortFlushCompleted on port %d", portIndex); + + /* Once the output buffers are flushed, ignore any buffers that are held in decoder */ + if (kOutputPortIndex == portIndex) { + setFlushMode(); + + /* Reset the time stamp arrays */ + memset(mTimeStamps, 0, sizeof(mTimeStamps)); + memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); + + while (true) { + ivd_video_decode_ip_t s_dec_ip; + ivd_video_decode_op_t s_dec_op; + IV_API_CALL_STATUS_T status; + size_t sizeY, sizeUV; + + s_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE; + + s_dec_ip.u4_ts = 0; + s_dec_ip.pv_stream_buffer = NULL; + s_dec_ip.u4_num_Bytes = 0; + + s_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t); + s_dec_op.u4_size = sizeof(ivd_video_decode_op_t); + + sizeY = mStride * mHeight; + sizeUV = sizeY / 4; + s_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = sizeY; + s_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = sizeUV; + s_dec_ip.s_out_buffer.u4_min_out_buf_size[2] = sizeUV; + + s_dec_ip.s_out_buffer.pu1_bufs[0] = mFlushOutBuffer; + s_dec_ip.s_out_buffer.pu1_bufs[1] = + s_dec_ip.s_out_buffer.pu1_bufs[0] + sizeY; + s_dec_ip.s_out_buffer.pu1_bufs[2] = + s_dec_ip.s_out_buffer.pu1_bufs[1] + sizeUV; + s_dec_ip.s_out_buffer.u4_num_bufs = 3; + + status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, + (void *)&s_dec_op); + if (0 == s_dec_op.u4_output_present) { + resetPlugin(); + break; + } + } + } +} + +void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { + IV_API_CALL_STATUS_T status; + + UNUSED(portIndex); + + if (mOutputPortSettingsChange != NONE) { + return; + } + + List &inQueue = getPortQueue(kInputPortIndex); + List &outQueue = getPortQueue(kOutputPortIndex); + + /* If input EOS is seen and decoder is not in flush mode, + * set the decoder in flush mode. + * There can be a case where EOS is sent along with last picture data + * In that case, only after decoding that input data, decoder has to be + * put in flush. This case is handled here */ + + if (mReceivedEOS && !mIsInFlush) { + setFlushMode(); + } + + while (outQueue.size() == kNumBuffers) { + BufferInfo *inInfo; + OMX_BUFFERHEADERTYPE *inHeader; + + BufferInfo *outInfo; + OMX_BUFFERHEADERTYPE *outHeader; + size_t timeStampIx; + + inInfo = NULL; + inHeader = NULL; + + if (!mIsInFlush) { + if (!inQueue.empty()) { + inInfo = *inQueue.begin(); + inHeader = inInfo->mHeader; + } else { + break; + } + } + + outInfo = *outQueue.begin(); + outHeader = outInfo->mHeader; + outHeader->nFlags = 0; + outHeader->nTimeStamp = 0; + outHeader->nOffset = 0; + + if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { + ALOGD("EOS seen on input"); + mReceivedEOS = true; + if (inHeader->nFilledLen == 0) { + inQueue.erase(inQueue.begin()); + inInfo->mOwnedByUs = false; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + setFlushMode(); + } + } + + /* Get a free slot in timestamp array to hold input timestamp */ + { + size_t i; + timeStampIx = 0; + for (i = 0; i < MAX_TIME_STAMPS; i++) { + if (!mTimeStampsValid[i]) { + timeStampIx = i; + break; + } + } + if (inHeader != NULL) { + mTimeStampsValid[timeStampIx] = true; + mTimeStamps[timeStampIx] = inHeader->nTimeStamp; + } + } + + { + ivd_video_decode_ip_t s_dec_ip; + ivd_video_decode_op_t s_dec_op; + WORD32 timeDelay, timeTaken; + size_t sizeY, sizeUV; + + s_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE; + + /* When in flush and after EOS with zero byte input, + * inHeader is set to zero. Hence check for non-null */ + if (inHeader != NULL) { + s_dec_ip.u4_ts = timeStampIx; + s_dec_ip.pv_stream_buffer = inHeader->pBuffer + + inHeader->nOffset; + s_dec_ip.u4_num_Bytes = inHeader->nFilledLen; + } else { + s_dec_ip.u4_ts = 0; + s_dec_ip.pv_stream_buffer = NULL; + s_dec_ip.u4_num_Bytes = 0; + } + + s_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t); + s_dec_op.u4_size = sizeof(ivd_video_decode_op_t); + + sizeY = mStride * mHeight; + sizeUV = sizeY / 4; + s_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = sizeY; + s_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = sizeUV; + s_dec_ip.s_out_buffer.u4_min_out_buf_size[2] = sizeUV; + + s_dec_ip.s_out_buffer.pu1_bufs[0] = outHeader->pBuffer; + s_dec_ip.s_out_buffer.pu1_bufs[1] = + s_dec_ip.s_out_buffer.pu1_bufs[0] + sizeY; + s_dec_ip.s_out_buffer.pu1_bufs[2] = + s_dec_ip.s_out_buffer.pu1_bufs[1] + sizeUV; + s_dec_ip.s_out_buffer.u4_num_bufs = 3; + + GETTIME(&mTimeStart, NULL); + /* Compute time elapsed between end of previous decode() + * to start of current decode() */ + TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); + + status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, + (void *)&s_dec_op); + + GETTIME(&mTimeEnd, NULL); + /* Compute time taken for decode() */ + TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); + + ALOGD("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, + s_dec_op.u4_num_bytes_consumed); + + if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { + /* If the input did not contain picture data, then ignore + * the associated timestamp */ + mTimeStampsValid[timeStampIx] = false; + } + + /* If valid height and width are decoded, + * then look at change in resolution */ + if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { + uint32_t width = s_dec_op.u4_pic_wd; + uint32_t height = s_dec_op.u4_pic_ht; + + if ((width != mWidth || height != mHeight)) { + mWidth = width; + mHeight = height; + mStride = mWidth; + + /* If width and height are greater than the + * the dimensions used during codec create, then + * delete the current instance and recreate an instance with + * new dimensions */ + /* TODO: The following does not work currently, since the decoder + * currently returns 0 x 0 as width height when it is not supported + * Once the decoder is updated to return actual width and height, + * then this can be validated*/ + + if ((mWidth * mHeight) > (mInitWidth * mInitHeight)) { + status_t ret; + ALOGD("Trying reInit"); + ret = deInitDecoder(); + if (OK != ret) { + // TODO: Handle graceful exit + ALOGE("Create failure"); + return; + } + + mInitWidth = mWidth; + mInitHeight = mHeight; + + ret = initDecoder(); + if (OK != ret) { + // TODO: Handle graceful exit + ALOGE("Create failure"); + return; + } + } + updatePortDefinitions(); + + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + return; + } + } + + if (s_dec_op.u4_output_present) { + outHeader->nFilledLen = (mStride * mHeight * 3) / 2; + + outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts]; + mTimeStampsValid[s_dec_op.u4_ts] = false; + + outInfo->mOwnedByUs = false; + outQueue.erase(outQueue.begin()); + outInfo = NULL; + notifyFillBufferDone(outHeader); + outHeader = NULL; + } else { + /* If in flush mode and no output is returned by the codec, + * then come out of flush mode */ + mIsInFlush = false; + + /* If EOS was recieved on input port and there is no output + * from the codec, then signal EOS on output port */ + if (mReceivedEOS) { + outHeader->nFilledLen = 0; + outHeader->nFlags |= OMX_BUFFERFLAG_EOS; + + outInfo->mOwnedByUs = false; + outQueue.erase(outQueue.begin()); + outInfo = NULL; + notifyFillBufferDone(outHeader); + outHeader = NULL; + resetPlugin(); + } + } + } + + // TODO: Handle more than one picture data + if (inHeader != NULL) { + inInfo->mOwnedByUs = false; + inQueue.erase(inQueue.begin()); + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } + } +} + +} // namespace android + +android::SoftOMXComponent *createSoftOMXComponent(const char *name, + const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, + OMX_COMPONENTTYPE **component) { + return new android::SoftHEVC(name, callbacks, appData, component); +} diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.h b/media/libstagefright/codecs/hevcdec/SoftHEVC.h new file mode 100644 index 0000000..20db0e1 --- /dev/null +++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2014 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 SOFT_HEVC_H_ + +#define SOFT_HEVC_H_ + +#include "SoftVideoDecoderOMXComponent.h" +#include + +namespace android { + +#define ivd_aligned_malloc(alignment, size) memalign(alignment, size) +#define ivd_aligned_free(buf) free(buf) + +/** Number of entries in the time-stamp array */ +#define MAX_TIME_STAMPS 64 + +/** Maximum number of cores supported by the codec */ +#define CODEC_MAX_NUM_CORES 4 + +#define CODEC_MAX_WIDTH 1920 + +#define CODEC_MAX_HEIGHT 1088 + +/** Input buffer size */ +#define INPUT_BUF_SIZE (1024 * 1024) + +#define MIN(a, b) ((a) < (b)) ? (a) : (b) + +/** Used to remove warnings about unused parameters */ +#define UNUSED(x) ((void)(x)) + +/** Get time */ +#define GETTIME(a, b) gettimeofday(a, b); + +/** Compute difference between start and end */ +#define TIME_DIFF(start, end, diff) \ + diff = ((end.tv_sec - start.tv_sec) * 1000000) + \ + (end.tv_usec - start.tv_usec); + +struct SoftHEVC: public SoftVideoDecoderOMXComponent { + SoftHEVC(const char *name, const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, OMX_COMPONENTTYPE **component); + +protected: + virtual ~SoftHEVC(); + + virtual void onQueueFilled(OMX_U32 portIndex); + virtual void onPortFlushCompleted(OMX_U32 portIndex); + virtual void onReset(); +private: + // Number of input and output buffers + enum { + kNumBuffers = 8 + }; + + iv_obj_t *mCodecCtx; // Codec context + iv_mem_rec_t *mMemRecords; // Memory records requested by the codec + size_t mNumMemRecords; // Number of memory records requested by the codec + + uint32_t mNewWidth; // New width after change in resolution + uint32_t mNewHeight; // New height after change in resolution + uint32_t mInitWidth; // Width used during codec creation + uint32_t mInitHeight; // Height used during codec creation + size_t mStride; // Stride to be used for display buffers + + size_t mNumCores; // Number of cores to be uesd by the codec + + struct timeval mTimeStart; // Time at the start of decode() + struct timeval mTimeEnd; // Time at the end of decode() + + // Internal buffer to be used to flush out the buffers from decoder + uint8_t *mFlushOutBuffer; + + // Status of entries in the timestamp array + bool mTimeStampsValid[MAX_TIME_STAMPS]; + + // Timestamp array - Since codec does not take 64 bit timestamps, + // they are maintained in the plugin + OMX_S64 mTimeStamps[MAX_TIME_STAMPS]; + + OMX_COLOR_FORMATTYPE mOmxColorFormat; // OMX Color format + IV_COLOR_FORMAT_T mIvColorFormat; // Ittiam Color format + + bool mIsInFlush; // codec is flush mode + bool mReceivedEOS; // EOS is receieved on input port + bool mIsAdapting; // plugin in middle of change in resolution + + status_t initDecoder(); + status_t deInitDecoder(); + status_t setFlushMode(); + status_t setParams(WORD32 stride, IVD_VIDEO_DECODE_MODE_T decMode); + status_t getVersion(); + status_t setNumCores(); + status_t resetDecoder(); + status_t resetPlugin(); + + DISALLOW_EVIL_CONSTRUCTORS (SoftHEVC); +}; + +} // namespace android + +#endif // SOFT_HEVC_H_ diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml index 41e0efb..9b930bc 100644 --- a/media/libstagefright/data/media_codecs_google_video.xml +++ b/media/libstagefright/data/media_codecs_google_video.xml @@ -19,6 +19,7 @@ + diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp index 65f5404..9b6958a 100644 --- a/media/libstagefright/omx/SoftOMXPlugin.cpp +++ b/media/libstagefright/omx/SoftOMXPlugin.cpp @@ -42,6 +42,7 @@ static const struct { { "OMX.google.amrwb.encoder", "amrwbenc", "audio_encoder.amrwb" }, { "OMX.google.h264.decoder", "h264dec", "video_decoder.avc" }, { "OMX.google.h264.encoder", "h264enc", "video_encoder.avc" }, + { "OMX.google.hevc.decoder", "hevcdec", "video_decoder.hevc" }, { "OMX.google.g711.alaw.decoder", "g711dec", "audio_decoder.g711alaw" }, { "OMX.google.g711.mlaw.decoder", "g711dec", "audio_decoder.g711mlaw" }, { "OMX.google.h263.decoder", "mpeg4dec", "video_decoder.h263" }, diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp index eb9fcf7..1c383f7 100644 --- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp +++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp @@ -183,12 +183,12 @@ OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalGetParameter( return OMX_ErrorUnsupportedIndex; } - if (index >= mNumProfileLevels) { + if (profileLevel->nProfileIndex >= mNumProfileLevels) { return OMX_ErrorNoMore; } - profileLevel->eProfile = mProfileLevels[index].mProfile; - profileLevel->eLevel = mProfileLevels[index].mLevel; + profileLevel->eProfile = mProfileLevels[profileLevel->nProfileIndex].mProfile; + profileLevel->eLevel = mProfileLevels[profileLevel->nProfileIndex].mLevel; return OMX_ErrorNone; } -- cgit v1.1 From bd856d78a407853f7779decbcf965f832ee99c31 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 6 Jun 2014 17:11:02 -0700 Subject: Remove SoftOMX HEVC decoder Bug: 14571712 Change-Id: Ie3fb3743ec27a0cfdea612052ba15a06f2c891db --- media/libstagefright/codecs/hevcdec/Android.mk | 22 - media/libstagefright/codecs/hevcdec/SoftHEVC.cpp | 710 ----------------------- media/libstagefright/codecs/hevcdec/SoftHEVC.h | 117 ---- 3 files changed, 849 deletions(-) delete mode 100644 media/libstagefright/codecs/hevcdec/Android.mk delete mode 100644 media/libstagefright/codecs/hevcdec/SoftHEVC.cpp delete mode 100644 media/libstagefright/codecs/hevcdec/SoftHEVC.h (limited to 'media') diff --git a/media/libstagefright/codecs/hevcdec/Android.mk b/media/libstagefright/codecs/hevcdec/Android.mk deleted file mode 100644 index 2fe347b..0000000 --- a/media/libstagefright/codecs/hevcdec/Android.mk +++ /dev/null @@ -1,22 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE := libstagefright_soft_hevcdec -LOCAL_MODULE_TAGS := optional - -LOCAL_STATIC_LIBRARIES := libhevcdec -LOCAL_SRC_FILES := SoftHEVC.cpp - -LOCAL_C_INCLUDES := $(TOP)/external/libhevc/decoder -LOCAL_C_INCLUDES += $(TOP)/external/libhevc/common -LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include -LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax - -LOCAL_SHARED_LIBRARIES := libstagefright -LOCAL_SHARED_LIBRARIES += libstagefright_omx -LOCAL_SHARED_LIBRARIES += libstagefright_foundation -LOCAL_SHARED_LIBRARIES += libutils -LOCAL_SHARED_LIBRARIES += liblog - - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp deleted file mode 100644 index 0aae5ed..0000000 --- a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp +++ /dev/null @@ -1,710 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "SoftHEVC" -#include - -#include "ihevc_typedefs.h" -#include "iv.h" -#include "ivd.h" -#include "ithread.h" -#include "ihevcd_cxa.h" -#include "SoftHEVC.h" - -#include -#include -#include - -namespace android { - -#define componentName "video_decoder.hevc" -#define codingType OMX_VIDEO_CodingHEVC -#define CODEC_MIME_TYPE MEDIA_MIMETYPE_VIDEO_HEVC - -/** Function and structure definitions to keep code similar for each codec */ -#define ivdec_api_function ihevcd_cxa_api_function -#define ivdext_init_ip_t ihevcd_cxa_init_ip_t -#define ivdext_init_op_t ihevcd_cxa_init_op_t -#define ivdext_fill_mem_rec_ip_t ihevcd_cxa_fill_mem_rec_ip_t -#define ivdext_fill_mem_rec_op_t ihevcd_cxa_fill_mem_rec_op_t -#define ivdext_ctl_set_num_cores_ip_t ihevcd_cxa_ctl_set_num_cores_ip_t -#define ivdext_ctl_set_num_cores_op_t ihevcd_cxa_ctl_set_num_cores_op_t - -#define IVDEXT_CMD_CTL_SET_NUM_CORES \ - (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES - -static const CodecProfileLevel kProfileLevels[] = { - { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel1 }, - { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel2 }, - { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel21 }, - { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel3 }, - { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel31 }, - { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel4 }, - { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel41 }, - { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel5 }, - { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel51 }, -}; - -SoftHEVC::SoftHEVC( - const char *name, - const OMX_CALLBACKTYPE *callbacks, - OMX_PTR appData, - OMX_COMPONENTTYPE **component) - : SoftVideoDecoderOMXComponent(name, componentName, codingType, - kProfileLevels, ARRAY_SIZE(kProfileLevels), - CODEC_MAX_WIDTH /* width */, CODEC_MAX_HEIGHT /* height */, callbacks, - appData, component) { - initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, - CODEC_MIME_TYPE); - - mOmxColorFormat = OMX_COLOR_FormatYUV420Planar; - mStride = mWidth; - - if (OMX_COLOR_FormatYUV420Planar == mOmxColorFormat) { - mIvColorFormat = IV_YUV_420P; - } else if (OMX_COLOR_FormatYUV420SemiPlanar == mOmxColorFormat) { - mIvColorFormat = IV_YUV_420SP_UV; - } - - mInitWidth = mWidth; - mInitHeight = mHeight; - - CHECK_EQ(initDecoder(), (status_t)OK); -} - -SoftHEVC::~SoftHEVC() { - ALOGD("In SoftHEVC::~SoftHEVC"); - CHECK_EQ(deInitDecoder(), (status_t)OK); -} - -static size_t GetCPUCoreCount() { - long cpuCoreCount = 1; -#if defined(_SC_NPROCESSORS_ONLN) - cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); -#else - // _SC_NPROC_ONLN must be defined... - cpuCoreCount = sysconf(_SC_NPROC_ONLN); -#endif - CHECK(cpuCoreCount >= 1); - ALOGD("Number of CPU cores: %ld", cpuCoreCount); - return (size_t)cpuCoreCount; -} - -status_t SoftHEVC::getVersion() { - ivd_ctl_getversioninfo_ip_t s_ctl_ip; - ivd_ctl_getversioninfo_op_t s_ctl_op; - UWORD8 au1_buf[512]; - IV_API_CALL_STATUS_T status; - - s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; - s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION; - s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t); - s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t); - s_ctl_ip.pv_version_buffer = au1_buf; - s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf); - - status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, - (void *)&s_ctl_op); - - if (status != IV_SUCCESS) { - ALOGE("Error in getting version number: 0x%x", - s_ctl_op.u4_error_code); - } else { - ALOGD("Ittiam decoder version number: %s", - (char *)s_ctl_ip.pv_version_buffer); - } - return OK; -} - -status_t SoftHEVC::setParams(WORD32 stride, IVD_VIDEO_DECODE_MODE_T decMode) { - ivd_ctl_set_config_ip_t s_ctl_ip; - ivd_ctl_set_config_op_t s_ctl_op; - IV_API_CALL_STATUS_T status; - s_ctl_ip.u4_disp_wd = stride; - s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE; - - s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT; - s_ctl_ip.e_vid_dec_mode = decMode; - s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; - s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS; - s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); - s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t); - - ALOGD("Set the run-time (dynamic) parameters"); - status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, - (void *)&s_ctl_op); - - if (status != IV_SUCCESS) { - ALOGE("Error in setting the run-time parameters: 0x%x", - s_ctl_op.u4_error_code); - - return UNKNOWN_ERROR; - } - return OK; -} - -status_t SoftHEVC::resetPlugin() { - mIsInFlush = false; - mReceivedEOS = false; - memset(mTimeStamps, 0, sizeof(mTimeStamps)); - memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); - - /* Initialize both start and end times */ - gettimeofday(&mTimeStart, NULL); - gettimeofday(&mTimeEnd, NULL); - - return OK; -} - -status_t SoftHEVC::resetDecoder() { - ivd_ctl_reset_ip_t s_ctl_ip; - ivd_ctl_reset_op_t s_ctl_op; - IV_API_CALL_STATUS_T status; - - s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; - s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET; - s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t); - s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t); - - status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, - (void *)&s_ctl_op); - if (IV_SUCCESS != status) { - ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code); - return UNKNOWN_ERROR; - } - - /* Set the run-time (dynamic) parameters */ - setParams(0, IVD_DECODE_FRAME); - - /* Set number of cores/threads to be used by the codec */ - setNumCores(); - - return OK; -} - -status_t SoftHEVC::setNumCores() { - ivdext_ctl_set_num_cores_ip_t s_set_cores_ip; - ivdext_ctl_set_num_cores_op_t s_set_cores_op; - IV_API_CALL_STATUS_T status; - s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL; - s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES; - s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES); - s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t); - s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t); - ALOGD("Set number of cores to %u", s_set_cores_ip.u4_num_cores); - status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip, - (void *)&s_set_cores_op); - if (IV_SUCCESS != status) { - ALOGE("Error in setting number of cores: 0x%x", - s_set_cores_op.u4_error_code); - return UNKNOWN_ERROR; - } - return OK; -} - -status_t SoftHEVC::setFlushMode() { - IV_API_CALL_STATUS_T status; - ivd_ctl_flush_ip_t s_video_flush_ip; - ivd_ctl_flush_op_t s_video_flush_op; - - s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL; - s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH; - s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t); - s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t); - ALOGD("Set the decoder in flush mode "); - - /* Set the decoder in Flush mode, subsequent decode() calls will flush */ - status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip, - (void *)&s_video_flush_op); - - if (status != IV_SUCCESS) { - ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status, - s_video_flush_op.u4_error_code); - return UNKNOWN_ERROR; - } - - mIsInFlush = true; - return OK; -} - -status_t SoftHEVC::initDecoder() { - IV_API_CALL_STATUS_T status; - - UWORD32 u4_num_reorder_frames; - UWORD32 u4_num_ref_frames; - UWORD32 u4_share_disp_buf; - WORD32 i4_level; - - mNumCores = GetCPUCoreCount(); - - /* Initialize number of ref and reorder modes (for HEVC) */ - u4_num_reorder_frames = 16; - u4_num_ref_frames = 16; - u4_share_disp_buf = 0; - - if ((mWidth * mHeight) > (1920 * 1088)) { - i4_level = 50; - } else if ((mWidth * mHeight) > (1280 * 720)) { - i4_level = 41; - } else { - i4_level = 31; - } - - { - iv_num_mem_rec_ip_t s_num_mem_rec_ip; - iv_num_mem_rec_op_t s_num_mem_rec_op; - - s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip); - s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op); - s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC; - - ALOGV("Get number of mem records"); - status = ivdec_api_function(mCodecCtx, (void*)&s_num_mem_rec_ip, - (void*)&s_num_mem_rec_op); - if (IV_SUCCESS != status) { - ALOGE("Error in getting mem records: 0x%x", - s_num_mem_rec_op.u4_error_code); - return UNKNOWN_ERROR; - } - - mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec; - } - - mMemRecords = (iv_mem_rec_t*)ivd_aligned_malloc( - 128, mNumMemRecords * sizeof(iv_mem_rec_t)); - if (mMemRecords == NULL) { - ALOGE("Allocation failure"); - return NO_MEMORY; - } - - { - size_t i; - ivdext_fill_mem_rec_ip_t s_fill_mem_ip; - ivdext_fill_mem_rec_op_t s_fill_mem_op; - iv_mem_rec_t *ps_mem_rec; - - s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = - sizeof(ivdext_fill_mem_rec_ip_t); - s_fill_mem_ip.i4_level = i4_level; - s_fill_mem_ip.u4_num_reorder_frames = u4_num_reorder_frames; - s_fill_mem_ip.u4_num_ref_frames = u4_num_ref_frames; - s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf; - s_fill_mem_ip.u4_num_extra_disp_buf = 0; - s_fill_mem_ip.e_output_format = mIvColorFormat; - - s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC; - s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords; - s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = mWidth; - s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = mHeight; - s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size = - sizeof(ivdext_fill_mem_rec_op_t); - - ps_mem_rec = mMemRecords; - for (i = 0; i < mNumMemRecords; i++) - ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t); - - status = ivdec_api_function(mCodecCtx, (void *)&s_fill_mem_ip, - (void *)&s_fill_mem_op); - - if (IV_SUCCESS != status) { - ALOGE("Error in filling mem records: 0x%x", - s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code); - return UNKNOWN_ERROR; - } - mNumMemRecords = - s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled; - - ps_mem_rec = mMemRecords; - - for (i = 0; i < mNumMemRecords; i++) { - ps_mem_rec->pv_base = ivd_aligned_malloc( - ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size); - if (ps_mem_rec->pv_base == NULL) { - ALOGE("Allocation failure for memory record #%zu of size %u", - i, ps_mem_rec->u4_mem_size); - status = IV_FAIL; - return NO_MEMORY; - } - - ps_mem_rec++; - } - } - - /* Initialize the decoder */ - { - ivdext_init_ip_t s_init_ip; - ivdext_init_op_t s_init_op; - - void *dec_fxns = (void *)ivdec_api_function; - - s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t); - s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT; - s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords; - s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = mWidth; - s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight; - - s_init_ip.i4_level = i4_level; - s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames; - s_init_ip.u4_num_ref_frames = u4_num_ref_frames; - s_init_ip.u4_share_disp_buf = u4_share_disp_buf; - s_init_ip.u4_num_extra_disp_buf = 0; - - s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op); - - s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords; - s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat; - - mCodecCtx = (iv_obj_t*)mMemRecords[0].pv_base; - mCodecCtx->pv_fxns = dec_fxns; - mCodecCtx->u4_size = sizeof(iv_obj_t); - - ALOGD("Initializing decoder"); - status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, - (void *)&s_init_op); - if (status != IV_SUCCESS) { - ALOGE("Error in init: 0x%x", - s_init_op.s_ivd_init_op_t.u4_error_code); - return UNKNOWN_ERROR; - } - } - - /* Reset the plugin state */ - resetPlugin(); - - /* Set the run time (dynamic) parameters */ - setParams(0, IVD_DECODE_FRAME); - - /* Set number of cores/threads to be used by the codec */ - setNumCores(); - - /* Get codec version */ - getVersion(); - - /* Allocate internal picture buffer */ - mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, mStride * mHeight * 3 / 2); - if (NULL == mFlushOutBuffer) { - ALOGE("Could not allocate flushOutputBuffer of size %zu", mStride * mHeight * 3 / 2); - return NO_MEMORY; - } - - return OK; -} - -status_t SoftHEVC::deInitDecoder() { - size_t i; - iv_mem_rec_t *ps_mem_rec; - ps_mem_rec = mMemRecords; - ALOGD("Freeing codec memory"); - for (i = 0; i < mNumMemRecords; i++) { - ivd_aligned_free(ps_mem_rec->pv_base); - ps_mem_rec++; - } - - ivd_aligned_free(mMemRecords); - ivd_aligned_free(mFlushOutBuffer); - return OK; -} - -void SoftHEVC::onReset() { - ALOGD("onReset called"); - SoftVideoDecoderOMXComponent::onReset(); - - resetDecoder(); - resetPlugin(); -} - -void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { - ALOGD("onPortFlushCompleted on port %d", portIndex); - - /* Once the output buffers are flushed, ignore any buffers that are held in decoder */ - if (kOutputPortIndex == portIndex) { - setFlushMode(); - - /* Reset the time stamp arrays */ - memset(mTimeStamps, 0, sizeof(mTimeStamps)); - memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); - - while (true) { - ivd_video_decode_ip_t s_dec_ip; - ivd_video_decode_op_t s_dec_op; - IV_API_CALL_STATUS_T status; - size_t sizeY, sizeUV; - - s_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE; - - s_dec_ip.u4_ts = 0; - s_dec_ip.pv_stream_buffer = NULL; - s_dec_ip.u4_num_Bytes = 0; - - s_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t); - s_dec_op.u4_size = sizeof(ivd_video_decode_op_t); - - sizeY = mStride * mHeight; - sizeUV = sizeY / 4; - s_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = sizeY; - s_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = sizeUV; - s_dec_ip.s_out_buffer.u4_min_out_buf_size[2] = sizeUV; - - s_dec_ip.s_out_buffer.pu1_bufs[0] = mFlushOutBuffer; - s_dec_ip.s_out_buffer.pu1_bufs[1] = - s_dec_ip.s_out_buffer.pu1_bufs[0] + sizeY; - s_dec_ip.s_out_buffer.pu1_bufs[2] = - s_dec_ip.s_out_buffer.pu1_bufs[1] + sizeUV; - s_dec_ip.s_out_buffer.u4_num_bufs = 3; - - status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, - (void *)&s_dec_op); - if (0 == s_dec_op.u4_output_present) { - resetPlugin(); - break; - } - } - } -} - -void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { - IV_API_CALL_STATUS_T status; - - UNUSED(portIndex); - - if (mOutputPortSettingsChange != NONE) { - return; - } - - List &inQueue = getPortQueue(kInputPortIndex); - List &outQueue = getPortQueue(kOutputPortIndex); - - /* If input EOS is seen and decoder is not in flush mode, - * set the decoder in flush mode. - * There can be a case where EOS is sent along with last picture data - * In that case, only after decoding that input data, decoder has to be - * put in flush. This case is handled here */ - - if (mReceivedEOS && !mIsInFlush) { - setFlushMode(); - } - - while (outQueue.size() == kNumBuffers) { - BufferInfo *inInfo; - OMX_BUFFERHEADERTYPE *inHeader; - - BufferInfo *outInfo; - OMX_BUFFERHEADERTYPE *outHeader; - size_t timeStampIx; - - inInfo = NULL; - inHeader = NULL; - - if (!mIsInFlush) { - if (!inQueue.empty()) { - inInfo = *inQueue.begin(); - inHeader = inInfo->mHeader; - } else { - break; - } - } - - outInfo = *outQueue.begin(); - outHeader = outInfo->mHeader; - outHeader->nFlags = 0; - outHeader->nTimeStamp = 0; - outHeader->nOffset = 0; - - if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { - ALOGD("EOS seen on input"); - mReceivedEOS = true; - if (inHeader->nFilledLen == 0) { - inQueue.erase(inQueue.begin()); - inInfo->mOwnedByUs = false; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; - setFlushMode(); - } - } - - /* Get a free slot in timestamp array to hold input timestamp */ - { - size_t i; - timeStampIx = 0; - for (i = 0; i < MAX_TIME_STAMPS; i++) { - if (!mTimeStampsValid[i]) { - timeStampIx = i; - break; - } - } - if (inHeader != NULL) { - mTimeStampsValid[timeStampIx] = true; - mTimeStamps[timeStampIx] = inHeader->nTimeStamp; - } - } - - { - ivd_video_decode_ip_t s_dec_ip; - ivd_video_decode_op_t s_dec_op; - WORD32 timeDelay, timeTaken; - size_t sizeY, sizeUV; - - s_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE; - - /* When in flush and after EOS with zero byte input, - * inHeader is set to zero. Hence check for non-null */ - if (inHeader != NULL) { - s_dec_ip.u4_ts = timeStampIx; - s_dec_ip.pv_stream_buffer = inHeader->pBuffer - + inHeader->nOffset; - s_dec_ip.u4_num_Bytes = inHeader->nFilledLen; - } else { - s_dec_ip.u4_ts = 0; - s_dec_ip.pv_stream_buffer = NULL; - s_dec_ip.u4_num_Bytes = 0; - } - - s_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t); - s_dec_op.u4_size = sizeof(ivd_video_decode_op_t); - - sizeY = mStride * mHeight; - sizeUV = sizeY / 4; - s_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = sizeY; - s_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = sizeUV; - s_dec_ip.s_out_buffer.u4_min_out_buf_size[2] = sizeUV; - - s_dec_ip.s_out_buffer.pu1_bufs[0] = outHeader->pBuffer; - s_dec_ip.s_out_buffer.pu1_bufs[1] = - s_dec_ip.s_out_buffer.pu1_bufs[0] + sizeY; - s_dec_ip.s_out_buffer.pu1_bufs[2] = - s_dec_ip.s_out_buffer.pu1_bufs[1] + sizeUV; - s_dec_ip.s_out_buffer.u4_num_bufs = 3; - - GETTIME(&mTimeStart, NULL); - /* Compute time elapsed between end of previous decode() - * to start of current decode() */ - TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); - - status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, - (void *)&s_dec_op); - - GETTIME(&mTimeEnd, NULL); - /* Compute time taken for decode() */ - TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); - - ALOGD("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, - s_dec_op.u4_num_bytes_consumed); - - if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { - /* If the input did not contain picture data, then ignore - * the associated timestamp */ - mTimeStampsValid[timeStampIx] = false; - } - - /* If valid height and width are decoded, - * then look at change in resolution */ - if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { - uint32_t width = s_dec_op.u4_pic_wd; - uint32_t height = s_dec_op.u4_pic_ht; - - if ((width != mWidth || height != mHeight)) { - mWidth = width; - mHeight = height; - mStride = mWidth; - - /* If width and height are greater than the - * the dimensions used during codec create, then - * delete the current instance and recreate an instance with - * new dimensions */ - /* TODO: The following does not work currently, since the decoder - * currently returns 0 x 0 as width height when it is not supported - * Once the decoder is updated to return actual width and height, - * then this can be validated*/ - - if ((mWidth * mHeight) > (mInitWidth * mInitHeight)) { - status_t ret; - ALOGD("Trying reInit"); - ret = deInitDecoder(); - if (OK != ret) { - // TODO: Handle graceful exit - ALOGE("Create failure"); - return; - } - - mInitWidth = mWidth; - mInitHeight = mHeight; - - ret = initDecoder(); - if (OK != ret) { - // TODO: Handle graceful exit - ALOGE("Create failure"); - return; - } - } - updatePortDefinitions(); - - notify(OMX_EventPortSettingsChanged, 1, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; - return; - } - } - - if (s_dec_op.u4_output_present) { - outHeader->nFilledLen = (mStride * mHeight * 3) / 2; - - outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts]; - mTimeStampsValid[s_dec_op.u4_ts] = false; - - outInfo->mOwnedByUs = false; - outQueue.erase(outQueue.begin()); - outInfo = NULL; - notifyFillBufferDone(outHeader); - outHeader = NULL; - } else { - /* If in flush mode and no output is returned by the codec, - * then come out of flush mode */ - mIsInFlush = false; - - /* If EOS was recieved on input port and there is no output - * from the codec, then signal EOS on output port */ - if (mReceivedEOS) { - outHeader->nFilledLen = 0; - outHeader->nFlags |= OMX_BUFFERFLAG_EOS; - - outInfo->mOwnedByUs = false; - outQueue.erase(outQueue.begin()); - outInfo = NULL; - notifyFillBufferDone(outHeader); - outHeader = NULL; - resetPlugin(); - } - } - } - - // TODO: Handle more than one picture data - if (inHeader != NULL) { - inInfo->mOwnedByUs = false; - inQueue.erase(inQueue.begin()); - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; - } - } -} - -} // namespace android - -android::SoftOMXComponent *createSoftOMXComponent(const char *name, - const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, - OMX_COMPONENTTYPE **component) { - return new android::SoftHEVC(name, callbacks, appData, component); -} diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.h b/media/libstagefright/codecs/hevcdec/SoftHEVC.h deleted file mode 100644 index 20db0e1..0000000 --- a/media/libstagefright/codecs/hevcdec/SoftHEVC.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2014 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 SOFT_HEVC_H_ - -#define SOFT_HEVC_H_ - -#include "SoftVideoDecoderOMXComponent.h" -#include - -namespace android { - -#define ivd_aligned_malloc(alignment, size) memalign(alignment, size) -#define ivd_aligned_free(buf) free(buf) - -/** Number of entries in the time-stamp array */ -#define MAX_TIME_STAMPS 64 - -/** Maximum number of cores supported by the codec */ -#define CODEC_MAX_NUM_CORES 4 - -#define CODEC_MAX_WIDTH 1920 - -#define CODEC_MAX_HEIGHT 1088 - -/** Input buffer size */ -#define INPUT_BUF_SIZE (1024 * 1024) - -#define MIN(a, b) ((a) < (b)) ? (a) : (b) - -/** Used to remove warnings about unused parameters */ -#define UNUSED(x) ((void)(x)) - -/** Get time */ -#define GETTIME(a, b) gettimeofday(a, b); - -/** Compute difference between start and end */ -#define TIME_DIFF(start, end, diff) \ - diff = ((end.tv_sec - start.tv_sec) * 1000000) + \ - (end.tv_usec - start.tv_usec); - -struct SoftHEVC: public SoftVideoDecoderOMXComponent { - SoftHEVC(const char *name, const OMX_CALLBACKTYPE *callbacks, - OMX_PTR appData, OMX_COMPONENTTYPE **component); - -protected: - virtual ~SoftHEVC(); - - virtual void onQueueFilled(OMX_U32 portIndex); - virtual void onPortFlushCompleted(OMX_U32 portIndex); - virtual void onReset(); -private: - // Number of input and output buffers - enum { - kNumBuffers = 8 - }; - - iv_obj_t *mCodecCtx; // Codec context - iv_mem_rec_t *mMemRecords; // Memory records requested by the codec - size_t mNumMemRecords; // Number of memory records requested by the codec - - uint32_t mNewWidth; // New width after change in resolution - uint32_t mNewHeight; // New height after change in resolution - uint32_t mInitWidth; // Width used during codec creation - uint32_t mInitHeight; // Height used during codec creation - size_t mStride; // Stride to be used for display buffers - - size_t mNumCores; // Number of cores to be uesd by the codec - - struct timeval mTimeStart; // Time at the start of decode() - struct timeval mTimeEnd; // Time at the end of decode() - - // Internal buffer to be used to flush out the buffers from decoder - uint8_t *mFlushOutBuffer; - - // Status of entries in the timestamp array - bool mTimeStampsValid[MAX_TIME_STAMPS]; - - // Timestamp array - Since codec does not take 64 bit timestamps, - // they are maintained in the plugin - OMX_S64 mTimeStamps[MAX_TIME_STAMPS]; - - OMX_COLOR_FORMATTYPE mOmxColorFormat; // OMX Color format - IV_COLOR_FORMAT_T mIvColorFormat; // Ittiam Color format - - bool mIsInFlush; // codec is flush mode - bool mReceivedEOS; // EOS is receieved on input port - bool mIsAdapting; // plugin in middle of change in resolution - - status_t initDecoder(); - status_t deInitDecoder(); - status_t setFlushMode(); - status_t setParams(WORD32 stride, IVD_VIDEO_DECODE_MODE_T decMode); - status_t getVersion(); - status_t setNumCores(); - status_t resetDecoder(); - status_t resetPlugin(); - - DISALLOW_EVIL_CONSTRUCTORS (SoftHEVC); -}; - -} // namespace android - -#endif // SOFT_HEVC_H_ -- cgit v1.1 From 3e648747e7e40752580ae7fd0ff2e803623680cd Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 6 Jun 2014 20:05:27 -0700 Subject: add back HEVC SoftOMX decoder Bug: 14571712 Change-Id: Iea399e0cfec1f78584c74089f01821d8552ced40 --- media/libstagefright/codecs/hevcdec/Android.mk | 26 + media/libstagefright/codecs/hevcdec/SoftHEVC.cpp | 710 +++++++++++++++++++++++ media/libstagefright/codecs/hevcdec/SoftHEVC.h | 117 ++++ 3 files changed, 853 insertions(+) create mode 100644 media/libstagefright/codecs/hevcdec/Android.mk create mode 100644 media/libstagefright/codecs/hevcdec/SoftHEVC.cpp create mode 100644 media/libstagefright/codecs/hevcdec/SoftHEVC.h (limited to 'media') diff --git a/media/libstagefright/codecs/hevcdec/Android.mk b/media/libstagefright/codecs/hevcdec/Android.mk new file mode 100644 index 0000000..960602f --- /dev/null +++ b/media/libstagefright/codecs/hevcdec/Android.mk @@ -0,0 +1,26 @@ +ifeq ($(if $(wildcard external/libhevc),1,0),1) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := libstagefright_soft_hevcdec +LOCAL_MODULE_TAGS := optional + +LOCAL_STATIC_LIBRARIES := libhevcdec +LOCAL_SRC_FILES := SoftHEVC.cpp + +LOCAL_C_INCLUDES := $(TOP)/external/libhevc/decoder +LOCAL_C_INCLUDES += $(TOP)/external/libhevc/common +LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include +LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax + +LOCAL_SHARED_LIBRARIES := libstagefright +LOCAL_SHARED_LIBRARIES += libstagefright_omx +LOCAL_SHARED_LIBRARIES += libstagefright_foundation +LOCAL_SHARED_LIBRARIES += libutils +LOCAL_SHARED_LIBRARIES += liblog + + +include $(BUILD_SHARED_LIBRARY) + +endif diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp new file mode 100644 index 0000000..0aae5ed --- /dev/null +++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp @@ -0,0 +1,710 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoftHEVC" +#include + +#include "ihevc_typedefs.h" +#include "iv.h" +#include "ivd.h" +#include "ithread.h" +#include "ihevcd_cxa.h" +#include "SoftHEVC.h" + +#include +#include +#include + +namespace android { + +#define componentName "video_decoder.hevc" +#define codingType OMX_VIDEO_CodingHEVC +#define CODEC_MIME_TYPE MEDIA_MIMETYPE_VIDEO_HEVC + +/** Function and structure definitions to keep code similar for each codec */ +#define ivdec_api_function ihevcd_cxa_api_function +#define ivdext_init_ip_t ihevcd_cxa_init_ip_t +#define ivdext_init_op_t ihevcd_cxa_init_op_t +#define ivdext_fill_mem_rec_ip_t ihevcd_cxa_fill_mem_rec_ip_t +#define ivdext_fill_mem_rec_op_t ihevcd_cxa_fill_mem_rec_op_t +#define ivdext_ctl_set_num_cores_ip_t ihevcd_cxa_ctl_set_num_cores_ip_t +#define ivdext_ctl_set_num_cores_op_t ihevcd_cxa_ctl_set_num_cores_op_t + +#define IVDEXT_CMD_CTL_SET_NUM_CORES \ + (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES + +static const CodecProfileLevel kProfileLevels[] = { + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel1 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel2 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel21 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel3 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel31 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel4 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel41 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel5 }, + { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel51 }, +}; + +SoftHEVC::SoftHEVC( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component) + : SoftVideoDecoderOMXComponent(name, componentName, codingType, + kProfileLevels, ARRAY_SIZE(kProfileLevels), + CODEC_MAX_WIDTH /* width */, CODEC_MAX_HEIGHT /* height */, callbacks, + appData, component) { + initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, + CODEC_MIME_TYPE); + + mOmxColorFormat = OMX_COLOR_FormatYUV420Planar; + mStride = mWidth; + + if (OMX_COLOR_FormatYUV420Planar == mOmxColorFormat) { + mIvColorFormat = IV_YUV_420P; + } else if (OMX_COLOR_FormatYUV420SemiPlanar == mOmxColorFormat) { + mIvColorFormat = IV_YUV_420SP_UV; + } + + mInitWidth = mWidth; + mInitHeight = mHeight; + + CHECK_EQ(initDecoder(), (status_t)OK); +} + +SoftHEVC::~SoftHEVC() { + ALOGD("In SoftHEVC::~SoftHEVC"); + CHECK_EQ(deInitDecoder(), (status_t)OK); +} + +static size_t GetCPUCoreCount() { + long cpuCoreCount = 1; +#if defined(_SC_NPROCESSORS_ONLN) + cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); +#else + // _SC_NPROC_ONLN must be defined... + cpuCoreCount = sysconf(_SC_NPROC_ONLN); +#endif + CHECK(cpuCoreCount >= 1); + ALOGD("Number of CPU cores: %ld", cpuCoreCount); + return (size_t)cpuCoreCount; +} + +status_t SoftHEVC::getVersion() { + ivd_ctl_getversioninfo_ip_t s_ctl_ip; + ivd_ctl_getversioninfo_op_t s_ctl_op; + UWORD8 au1_buf[512]; + IV_API_CALL_STATUS_T status; + + s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; + s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION; + s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t); + s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t); + s_ctl_ip.pv_version_buffer = au1_buf; + s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf); + + status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, + (void *)&s_ctl_op); + + if (status != IV_SUCCESS) { + ALOGE("Error in getting version number: 0x%x", + s_ctl_op.u4_error_code); + } else { + ALOGD("Ittiam decoder version number: %s", + (char *)s_ctl_ip.pv_version_buffer); + } + return OK; +} + +status_t SoftHEVC::setParams(WORD32 stride, IVD_VIDEO_DECODE_MODE_T decMode) { + ivd_ctl_set_config_ip_t s_ctl_ip; + ivd_ctl_set_config_op_t s_ctl_op; + IV_API_CALL_STATUS_T status; + s_ctl_ip.u4_disp_wd = stride; + s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE; + + s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT; + s_ctl_ip.e_vid_dec_mode = decMode; + s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; + s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS; + s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); + s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t); + + ALOGD("Set the run-time (dynamic) parameters"); + status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, + (void *)&s_ctl_op); + + if (status != IV_SUCCESS) { + ALOGE("Error in setting the run-time parameters: 0x%x", + s_ctl_op.u4_error_code); + + return UNKNOWN_ERROR; + } + return OK; +} + +status_t SoftHEVC::resetPlugin() { + mIsInFlush = false; + mReceivedEOS = false; + memset(mTimeStamps, 0, sizeof(mTimeStamps)); + memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); + + /* Initialize both start and end times */ + gettimeofday(&mTimeStart, NULL); + gettimeofday(&mTimeEnd, NULL); + + return OK; +} + +status_t SoftHEVC::resetDecoder() { + ivd_ctl_reset_ip_t s_ctl_ip; + ivd_ctl_reset_op_t s_ctl_op; + IV_API_CALL_STATUS_T status; + + s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; + s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET; + s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t); + s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t); + + status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, + (void *)&s_ctl_op); + if (IV_SUCCESS != status) { + ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code); + return UNKNOWN_ERROR; + } + + /* Set the run-time (dynamic) parameters */ + setParams(0, IVD_DECODE_FRAME); + + /* Set number of cores/threads to be used by the codec */ + setNumCores(); + + return OK; +} + +status_t SoftHEVC::setNumCores() { + ivdext_ctl_set_num_cores_ip_t s_set_cores_ip; + ivdext_ctl_set_num_cores_op_t s_set_cores_op; + IV_API_CALL_STATUS_T status; + s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL; + s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES; + s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES); + s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t); + s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t); + ALOGD("Set number of cores to %u", s_set_cores_ip.u4_num_cores); + status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip, + (void *)&s_set_cores_op); + if (IV_SUCCESS != status) { + ALOGE("Error in setting number of cores: 0x%x", + s_set_cores_op.u4_error_code); + return UNKNOWN_ERROR; + } + return OK; +} + +status_t SoftHEVC::setFlushMode() { + IV_API_CALL_STATUS_T status; + ivd_ctl_flush_ip_t s_video_flush_ip; + ivd_ctl_flush_op_t s_video_flush_op; + + s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL; + s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH; + s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t); + s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t); + ALOGD("Set the decoder in flush mode "); + + /* Set the decoder in Flush mode, subsequent decode() calls will flush */ + status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip, + (void *)&s_video_flush_op); + + if (status != IV_SUCCESS) { + ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status, + s_video_flush_op.u4_error_code); + return UNKNOWN_ERROR; + } + + mIsInFlush = true; + return OK; +} + +status_t SoftHEVC::initDecoder() { + IV_API_CALL_STATUS_T status; + + UWORD32 u4_num_reorder_frames; + UWORD32 u4_num_ref_frames; + UWORD32 u4_share_disp_buf; + WORD32 i4_level; + + mNumCores = GetCPUCoreCount(); + + /* Initialize number of ref and reorder modes (for HEVC) */ + u4_num_reorder_frames = 16; + u4_num_ref_frames = 16; + u4_share_disp_buf = 0; + + if ((mWidth * mHeight) > (1920 * 1088)) { + i4_level = 50; + } else if ((mWidth * mHeight) > (1280 * 720)) { + i4_level = 41; + } else { + i4_level = 31; + } + + { + iv_num_mem_rec_ip_t s_num_mem_rec_ip; + iv_num_mem_rec_op_t s_num_mem_rec_op; + + s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip); + s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op); + s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC; + + ALOGV("Get number of mem records"); + status = ivdec_api_function(mCodecCtx, (void*)&s_num_mem_rec_ip, + (void*)&s_num_mem_rec_op); + if (IV_SUCCESS != status) { + ALOGE("Error in getting mem records: 0x%x", + s_num_mem_rec_op.u4_error_code); + return UNKNOWN_ERROR; + } + + mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec; + } + + mMemRecords = (iv_mem_rec_t*)ivd_aligned_malloc( + 128, mNumMemRecords * sizeof(iv_mem_rec_t)); + if (mMemRecords == NULL) { + ALOGE("Allocation failure"); + return NO_MEMORY; + } + + { + size_t i; + ivdext_fill_mem_rec_ip_t s_fill_mem_ip; + ivdext_fill_mem_rec_op_t s_fill_mem_op; + iv_mem_rec_t *ps_mem_rec; + + s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = + sizeof(ivdext_fill_mem_rec_ip_t); + s_fill_mem_ip.i4_level = i4_level; + s_fill_mem_ip.u4_num_reorder_frames = u4_num_reorder_frames; + s_fill_mem_ip.u4_num_ref_frames = u4_num_ref_frames; + s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf; + s_fill_mem_ip.u4_num_extra_disp_buf = 0; + s_fill_mem_ip.e_output_format = mIvColorFormat; + + s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC; + s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords; + s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = mWidth; + s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = mHeight; + s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size = + sizeof(ivdext_fill_mem_rec_op_t); + + ps_mem_rec = mMemRecords; + for (i = 0; i < mNumMemRecords; i++) + ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t); + + status = ivdec_api_function(mCodecCtx, (void *)&s_fill_mem_ip, + (void *)&s_fill_mem_op); + + if (IV_SUCCESS != status) { + ALOGE("Error in filling mem records: 0x%x", + s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code); + return UNKNOWN_ERROR; + } + mNumMemRecords = + s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled; + + ps_mem_rec = mMemRecords; + + for (i = 0; i < mNumMemRecords; i++) { + ps_mem_rec->pv_base = ivd_aligned_malloc( + ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size); + if (ps_mem_rec->pv_base == NULL) { + ALOGE("Allocation failure for memory record #%zu of size %u", + i, ps_mem_rec->u4_mem_size); + status = IV_FAIL; + return NO_MEMORY; + } + + ps_mem_rec++; + } + } + + /* Initialize the decoder */ + { + ivdext_init_ip_t s_init_ip; + ivdext_init_op_t s_init_op; + + void *dec_fxns = (void *)ivdec_api_function; + + s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t); + s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT; + s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords; + s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = mWidth; + s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight; + + s_init_ip.i4_level = i4_level; + s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames; + s_init_ip.u4_num_ref_frames = u4_num_ref_frames; + s_init_ip.u4_share_disp_buf = u4_share_disp_buf; + s_init_ip.u4_num_extra_disp_buf = 0; + + s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op); + + s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords; + s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat; + + mCodecCtx = (iv_obj_t*)mMemRecords[0].pv_base; + mCodecCtx->pv_fxns = dec_fxns; + mCodecCtx->u4_size = sizeof(iv_obj_t); + + ALOGD("Initializing decoder"); + status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, + (void *)&s_init_op); + if (status != IV_SUCCESS) { + ALOGE("Error in init: 0x%x", + s_init_op.s_ivd_init_op_t.u4_error_code); + return UNKNOWN_ERROR; + } + } + + /* Reset the plugin state */ + resetPlugin(); + + /* Set the run time (dynamic) parameters */ + setParams(0, IVD_DECODE_FRAME); + + /* Set number of cores/threads to be used by the codec */ + setNumCores(); + + /* Get codec version */ + getVersion(); + + /* Allocate internal picture buffer */ + mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, mStride * mHeight * 3 / 2); + if (NULL == mFlushOutBuffer) { + ALOGE("Could not allocate flushOutputBuffer of size %zu", mStride * mHeight * 3 / 2); + return NO_MEMORY; + } + + return OK; +} + +status_t SoftHEVC::deInitDecoder() { + size_t i; + iv_mem_rec_t *ps_mem_rec; + ps_mem_rec = mMemRecords; + ALOGD("Freeing codec memory"); + for (i = 0; i < mNumMemRecords; i++) { + ivd_aligned_free(ps_mem_rec->pv_base); + ps_mem_rec++; + } + + ivd_aligned_free(mMemRecords); + ivd_aligned_free(mFlushOutBuffer); + return OK; +} + +void SoftHEVC::onReset() { + ALOGD("onReset called"); + SoftVideoDecoderOMXComponent::onReset(); + + resetDecoder(); + resetPlugin(); +} + +void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { + ALOGD("onPortFlushCompleted on port %d", portIndex); + + /* Once the output buffers are flushed, ignore any buffers that are held in decoder */ + if (kOutputPortIndex == portIndex) { + setFlushMode(); + + /* Reset the time stamp arrays */ + memset(mTimeStamps, 0, sizeof(mTimeStamps)); + memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); + + while (true) { + ivd_video_decode_ip_t s_dec_ip; + ivd_video_decode_op_t s_dec_op; + IV_API_CALL_STATUS_T status; + size_t sizeY, sizeUV; + + s_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE; + + s_dec_ip.u4_ts = 0; + s_dec_ip.pv_stream_buffer = NULL; + s_dec_ip.u4_num_Bytes = 0; + + s_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t); + s_dec_op.u4_size = sizeof(ivd_video_decode_op_t); + + sizeY = mStride * mHeight; + sizeUV = sizeY / 4; + s_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = sizeY; + s_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = sizeUV; + s_dec_ip.s_out_buffer.u4_min_out_buf_size[2] = sizeUV; + + s_dec_ip.s_out_buffer.pu1_bufs[0] = mFlushOutBuffer; + s_dec_ip.s_out_buffer.pu1_bufs[1] = + s_dec_ip.s_out_buffer.pu1_bufs[0] + sizeY; + s_dec_ip.s_out_buffer.pu1_bufs[2] = + s_dec_ip.s_out_buffer.pu1_bufs[1] + sizeUV; + s_dec_ip.s_out_buffer.u4_num_bufs = 3; + + status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, + (void *)&s_dec_op); + if (0 == s_dec_op.u4_output_present) { + resetPlugin(); + break; + } + } + } +} + +void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { + IV_API_CALL_STATUS_T status; + + UNUSED(portIndex); + + if (mOutputPortSettingsChange != NONE) { + return; + } + + List &inQueue = getPortQueue(kInputPortIndex); + List &outQueue = getPortQueue(kOutputPortIndex); + + /* If input EOS is seen and decoder is not in flush mode, + * set the decoder in flush mode. + * There can be a case where EOS is sent along with last picture data + * In that case, only after decoding that input data, decoder has to be + * put in flush. This case is handled here */ + + if (mReceivedEOS && !mIsInFlush) { + setFlushMode(); + } + + while (outQueue.size() == kNumBuffers) { + BufferInfo *inInfo; + OMX_BUFFERHEADERTYPE *inHeader; + + BufferInfo *outInfo; + OMX_BUFFERHEADERTYPE *outHeader; + size_t timeStampIx; + + inInfo = NULL; + inHeader = NULL; + + if (!mIsInFlush) { + if (!inQueue.empty()) { + inInfo = *inQueue.begin(); + inHeader = inInfo->mHeader; + } else { + break; + } + } + + outInfo = *outQueue.begin(); + outHeader = outInfo->mHeader; + outHeader->nFlags = 0; + outHeader->nTimeStamp = 0; + outHeader->nOffset = 0; + + if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { + ALOGD("EOS seen on input"); + mReceivedEOS = true; + if (inHeader->nFilledLen == 0) { + inQueue.erase(inQueue.begin()); + inInfo->mOwnedByUs = false; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + setFlushMode(); + } + } + + /* Get a free slot in timestamp array to hold input timestamp */ + { + size_t i; + timeStampIx = 0; + for (i = 0; i < MAX_TIME_STAMPS; i++) { + if (!mTimeStampsValid[i]) { + timeStampIx = i; + break; + } + } + if (inHeader != NULL) { + mTimeStampsValid[timeStampIx] = true; + mTimeStamps[timeStampIx] = inHeader->nTimeStamp; + } + } + + { + ivd_video_decode_ip_t s_dec_ip; + ivd_video_decode_op_t s_dec_op; + WORD32 timeDelay, timeTaken; + size_t sizeY, sizeUV; + + s_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE; + + /* When in flush and after EOS with zero byte input, + * inHeader is set to zero. Hence check for non-null */ + if (inHeader != NULL) { + s_dec_ip.u4_ts = timeStampIx; + s_dec_ip.pv_stream_buffer = inHeader->pBuffer + + inHeader->nOffset; + s_dec_ip.u4_num_Bytes = inHeader->nFilledLen; + } else { + s_dec_ip.u4_ts = 0; + s_dec_ip.pv_stream_buffer = NULL; + s_dec_ip.u4_num_Bytes = 0; + } + + s_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t); + s_dec_op.u4_size = sizeof(ivd_video_decode_op_t); + + sizeY = mStride * mHeight; + sizeUV = sizeY / 4; + s_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = sizeY; + s_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = sizeUV; + s_dec_ip.s_out_buffer.u4_min_out_buf_size[2] = sizeUV; + + s_dec_ip.s_out_buffer.pu1_bufs[0] = outHeader->pBuffer; + s_dec_ip.s_out_buffer.pu1_bufs[1] = + s_dec_ip.s_out_buffer.pu1_bufs[0] + sizeY; + s_dec_ip.s_out_buffer.pu1_bufs[2] = + s_dec_ip.s_out_buffer.pu1_bufs[1] + sizeUV; + s_dec_ip.s_out_buffer.u4_num_bufs = 3; + + GETTIME(&mTimeStart, NULL); + /* Compute time elapsed between end of previous decode() + * to start of current decode() */ + TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); + + status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, + (void *)&s_dec_op); + + GETTIME(&mTimeEnd, NULL); + /* Compute time taken for decode() */ + TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); + + ALOGD("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, + s_dec_op.u4_num_bytes_consumed); + + if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { + /* If the input did not contain picture data, then ignore + * the associated timestamp */ + mTimeStampsValid[timeStampIx] = false; + } + + /* If valid height and width are decoded, + * then look at change in resolution */ + if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { + uint32_t width = s_dec_op.u4_pic_wd; + uint32_t height = s_dec_op.u4_pic_ht; + + if ((width != mWidth || height != mHeight)) { + mWidth = width; + mHeight = height; + mStride = mWidth; + + /* If width and height are greater than the + * the dimensions used during codec create, then + * delete the current instance and recreate an instance with + * new dimensions */ + /* TODO: The following does not work currently, since the decoder + * currently returns 0 x 0 as width height when it is not supported + * Once the decoder is updated to return actual width and height, + * then this can be validated*/ + + if ((mWidth * mHeight) > (mInitWidth * mInitHeight)) { + status_t ret; + ALOGD("Trying reInit"); + ret = deInitDecoder(); + if (OK != ret) { + // TODO: Handle graceful exit + ALOGE("Create failure"); + return; + } + + mInitWidth = mWidth; + mInitHeight = mHeight; + + ret = initDecoder(); + if (OK != ret) { + // TODO: Handle graceful exit + ALOGE("Create failure"); + return; + } + } + updatePortDefinitions(); + + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + return; + } + } + + if (s_dec_op.u4_output_present) { + outHeader->nFilledLen = (mStride * mHeight * 3) / 2; + + outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts]; + mTimeStampsValid[s_dec_op.u4_ts] = false; + + outInfo->mOwnedByUs = false; + outQueue.erase(outQueue.begin()); + outInfo = NULL; + notifyFillBufferDone(outHeader); + outHeader = NULL; + } else { + /* If in flush mode and no output is returned by the codec, + * then come out of flush mode */ + mIsInFlush = false; + + /* If EOS was recieved on input port and there is no output + * from the codec, then signal EOS on output port */ + if (mReceivedEOS) { + outHeader->nFilledLen = 0; + outHeader->nFlags |= OMX_BUFFERFLAG_EOS; + + outInfo->mOwnedByUs = false; + outQueue.erase(outQueue.begin()); + outInfo = NULL; + notifyFillBufferDone(outHeader); + outHeader = NULL; + resetPlugin(); + } + } + } + + // TODO: Handle more than one picture data + if (inHeader != NULL) { + inInfo->mOwnedByUs = false; + inQueue.erase(inQueue.begin()); + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } + } +} + +} // namespace android + +android::SoftOMXComponent *createSoftOMXComponent(const char *name, + const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, + OMX_COMPONENTTYPE **component) { + return new android::SoftHEVC(name, callbacks, appData, component); +} diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.h b/media/libstagefright/codecs/hevcdec/SoftHEVC.h new file mode 100644 index 0000000..20db0e1 --- /dev/null +++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2014 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 SOFT_HEVC_H_ + +#define SOFT_HEVC_H_ + +#include "SoftVideoDecoderOMXComponent.h" +#include + +namespace android { + +#define ivd_aligned_malloc(alignment, size) memalign(alignment, size) +#define ivd_aligned_free(buf) free(buf) + +/** Number of entries in the time-stamp array */ +#define MAX_TIME_STAMPS 64 + +/** Maximum number of cores supported by the codec */ +#define CODEC_MAX_NUM_CORES 4 + +#define CODEC_MAX_WIDTH 1920 + +#define CODEC_MAX_HEIGHT 1088 + +/** Input buffer size */ +#define INPUT_BUF_SIZE (1024 * 1024) + +#define MIN(a, b) ((a) < (b)) ? (a) : (b) + +/** Used to remove warnings about unused parameters */ +#define UNUSED(x) ((void)(x)) + +/** Get time */ +#define GETTIME(a, b) gettimeofday(a, b); + +/** Compute difference between start and end */ +#define TIME_DIFF(start, end, diff) \ + diff = ((end.tv_sec - start.tv_sec) * 1000000) + \ + (end.tv_usec - start.tv_usec); + +struct SoftHEVC: public SoftVideoDecoderOMXComponent { + SoftHEVC(const char *name, const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, OMX_COMPONENTTYPE **component); + +protected: + virtual ~SoftHEVC(); + + virtual void onQueueFilled(OMX_U32 portIndex); + virtual void onPortFlushCompleted(OMX_U32 portIndex); + virtual void onReset(); +private: + // Number of input and output buffers + enum { + kNumBuffers = 8 + }; + + iv_obj_t *mCodecCtx; // Codec context + iv_mem_rec_t *mMemRecords; // Memory records requested by the codec + size_t mNumMemRecords; // Number of memory records requested by the codec + + uint32_t mNewWidth; // New width after change in resolution + uint32_t mNewHeight; // New height after change in resolution + uint32_t mInitWidth; // Width used during codec creation + uint32_t mInitHeight; // Height used during codec creation + size_t mStride; // Stride to be used for display buffers + + size_t mNumCores; // Number of cores to be uesd by the codec + + struct timeval mTimeStart; // Time at the start of decode() + struct timeval mTimeEnd; // Time at the end of decode() + + // Internal buffer to be used to flush out the buffers from decoder + uint8_t *mFlushOutBuffer; + + // Status of entries in the timestamp array + bool mTimeStampsValid[MAX_TIME_STAMPS]; + + // Timestamp array - Since codec does not take 64 bit timestamps, + // they are maintained in the plugin + OMX_S64 mTimeStamps[MAX_TIME_STAMPS]; + + OMX_COLOR_FORMATTYPE mOmxColorFormat; // OMX Color format + IV_COLOR_FORMAT_T mIvColorFormat; // Ittiam Color format + + bool mIsInFlush; // codec is flush mode + bool mReceivedEOS; // EOS is receieved on input port + bool mIsAdapting; // plugin in middle of change in resolution + + status_t initDecoder(); + status_t deInitDecoder(); + status_t setFlushMode(); + status_t setParams(WORD32 stride, IVD_VIDEO_DECODE_MODE_T decMode); + status_t getVersion(); + status_t setNumCores(); + status_t resetDecoder(); + status_t resetPlugin(); + + DISALLOW_EVIL_CONSTRUCTORS (SoftHEVC); +}; + +} // namespace android + +#endif // SOFT_HEVC_H_ -- cgit v1.1 From ed83915060af3eaaf62feef2eb2eec1e7d431891 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 6 Jun 2014 14:36:23 -0700 Subject: Remove unneeded code Change-Id: I33c7424f1858e9f3f7f7ab5fb46db09c2714e02e --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 6 ------ 1 file changed, 6 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index edb7448..64bf2b6 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -842,12 +842,6 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { // depend on fragments from the last one decoded. // drain all existing data drainDecoder(); - // force decoder loop to drop the first decoded buffer by resetting these state variables, - // but only if initialization has already happened. - if (mInputBufferCount != 0) { - mInputBufferCount = 1; - mOutputBufferCount = -1; - } } else { while (outputDelayRingBufferSamplesAvailable() > 0) { int32_t ns = outputDelayRingBufferGetSamples(0, -- cgit v1.1 From 6d96582e2310212381489da68bee74c44a0a5926 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 4 Jun 2014 16:21:56 -0700 Subject: Added paused state to NuPlayerDecoder This prevents decoder from requesting new buffer until the decoder is resumed, and prevents processing a potential DISCONTINUITY while the player is still flushing. Bug: 13133027 Change-Id: I2f9fa9f00c8583aa6908809cb7c31ddde07cfaf0 (cherry picked from commit 704e72658b1082264a26a83c50046da34f07d1a1) --- .../nuplayer/NuPlayerDecoder.cpp | 20 ++++++++++++++++++-- .../libmediaplayerservice/nuplayer/NuPlayerDecoder.h | 2 ++ 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 469c9ca..cfbf282 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -37,6 +37,7 @@ NuPlayer::Decoder::Decoder( : mNotify(notify), mNativeWindow(nativeWindow), mBufferGeneration(0), + mPaused(true), mComponentName("decoder") { // Every decoder has its own looper because MediaCodec operations // are blocking, but NuPlayer needs asynchronous operations. @@ -112,6 +113,7 @@ void NuPlayer::Decoder::onConfigure(const sp &format) { mOutputBuffers.size()); requestCodecNotification(); + mPaused = false; } void NuPlayer::Decoder::requestCodecNotification() { @@ -352,6 +354,11 @@ void NuPlayer::Decoder::onFlush() { sp notify = mNotify->dup(); notify->setInt32("what", kWhatFlushCompleted); notify->post(); + mPaused = true; +} + +void NuPlayer::Decoder::onResume() { + mPaused = false; } void NuPlayer::Decoder::onShutdown() { @@ -380,6 +387,7 @@ void NuPlayer::Decoder::onShutdown() { sp notify = mNotify->dup(); notify->setInt32("what", kWhatShutdownCompleted); notify->post(); + mPaused = true; } void NuPlayer::Decoder::onMessageReceived(const sp &msg) { @@ -397,7 +405,9 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { case kWhatCodecNotify: { if (!isStaleReply(msg)) { - while (handleAnInputBuffer()) { + if (!mPaused) { + while (handleAnInputBuffer()) { + } } while (handleAnOutputBuffer()) { @@ -430,6 +440,12 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { break; } + case kWhatResume: + { + onResume(); + break; + } + case kWhatShutdown: { onShutdown(); @@ -447,7 +463,7 @@ void NuPlayer::Decoder::signalFlush() { } void NuPlayer::Decoder::signalResume() { - // nothing to do + (new AMessage(kWhatResume, id()))->post(); } void NuPlayer::Decoder::initiateShutdown() { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index 94243fc..2892584 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -87,11 +87,13 @@ private: void onConfigure(const sp &format); void onFlush(); + void onResume(); void onInputBufferFilled(const sp &msg); void onRenderBuffer(const sp &msg); void onShutdown(); int32_t mBufferGeneration; + bool mPaused; AString mComponentName; bool supportsSeamlessAudioFormatChange(const sp &targetFormat) const; -- cgit v1.1 From bcca9e072c1f288a53ce6862936f57dc36488f96 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Mon, 9 Jun 2014 15:51:38 -0700 Subject: Remove dependency on Parcel::{read,write}IntPtr bug: 15424960 bug: 15107693 Change-Id: Ic3bf37f591e620985c37f345f9a5544fd20ec4a1 --- media/libmedia/ICrypto.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp index 98b183a..0d5f990 100644 --- a/media/libmedia/ICrypto.cpp +++ b/media/libmedia/ICrypto.cpp @@ -131,7 +131,7 @@ struct BpCrypto : public BpInterface { data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples); if (secure) { - data.writeIntPtr((intptr_t)dstPtr); + data.writeInt64(static_cast(reinterpret_cast(dstPtr))); } remote()->transact(DECRYPT, data, &reply); @@ -249,7 +249,7 @@ status_t BnCrypto::onTransact( void *dstPtr; if (secure) { - dstPtr = (void *)data.readIntPtr(); + dstPtr = reinterpret_cast(static_cast(data.readInt64())); } else { dstPtr = malloc(totalSize); } -- cgit v1.1 From d7e8d9a7393b5429f8f13a6794b9b04d37390fb5 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 5 Jun 2014 10:37:26 -0700 Subject: Guard against malformed files b/15433074 Change-Id: I35363def42d38eba49dd5aece566fd345743937e --- media/libstagefright/MPEG4Extractor.cpp | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 76546f3..aabe0ec 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -482,11 +482,20 @@ status_t MPEG4Extractor::readMetaData() { off64_t offset = 0; status_t err; while (true) { + off64_t orig_offset = offset; err = parseChunk(&offset, 0); - if (err == OK) { + + if (offset <= orig_offset) { + // only continue parsing if the offset was advanced, + // otherwise we might end up in an infinite loop + ALOGE("did not advance: 0x%lld->0x%lld", orig_offset, offset); + err = ERROR_MALFORMED; + break; + } else if (err == OK) { continue; + } else if (err != UNKNOWN_ERROR) { + break; } - uint32_t hdr[2]; if (mDataSource->readAt(offset, hdr, 8) < 8) { break; @@ -509,8 +518,6 @@ status_t MPEG4Extractor::readMetaData() { } else { mFileMetaData->setCString(kKeyMIMEType, "audio/mp4"); } - - mInitCheck = OK; } else { mInitCheck = err; } @@ -762,8 +769,25 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { // The smallest valid chunk is 16 bytes long in this case. return ERROR_MALFORMED; } + } else if (chunk_size == 0) { + if (depth == 0) { + // atom extends to end of file + off64_t sourceSize; + if (mDataSource->getSize(&sourceSize) == OK) { + chunk_size = (sourceSize - *offset); + } else { + // XXX could we just pick a "sufficiently large" value here? + ALOGE("atom size is 0, and data source has no size"); + return ERROR_MALFORMED; + } + } else { + // not allowed for non-toplevel atoms, skip it + *offset += 4; + return OK; + } } else if (chunk_size < 8) { // The smallest valid chunk is 8 bytes long. + ALOGE("invalid chunk size: %d", int(chunk_size)); return ERROR_MALFORMED; } -- cgit v1.1 From 5f6af1a8e34381ca2ac2527fcefe220a22f49b53 Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Tue, 10 Jun 2014 08:26:33 -0700 Subject: MediaProfiles: Add 4K video related constants Bug: 15287656 Change-Id: I4c49640a349afb336f52db1636902fc216bff6ad --- media/libmedia/MediaProfiles.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'media') diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp index 1074da9..28238c4 100644 --- a/media/libmedia/MediaProfiles.cpp +++ b/media/libmedia/MediaProfiles.cpp @@ -69,6 +69,7 @@ const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = { {"480p", CAMCORDER_QUALITY_480P}, {"720p", CAMCORDER_QUALITY_720P}, {"1080p", CAMCORDER_QUALITY_1080P}, + {"2160p", CAMCORDER_QUALITY_2160P}, {"qvga", CAMCORDER_QUALITY_QVGA}, {"timelapselow", CAMCORDER_QUALITY_TIME_LAPSE_LOW}, @@ -78,6 +79,7 @@ const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = { {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P}, {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P}, {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P}, + {"timelapse2160p", CAMCORDER_QUALITY_TIME_LAPSE_2160P}, {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA}, }; -- cgit v1.1 From ef0cf50343f8a6d74894f96f5ecb5eec4c5f1bc6 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 11 Jun 2014 10:27:28 -0700 Subject: Log an error when audio/video encoder failed to create Change-Id: I493981cddeb9452c533e2917d8c440897d5e6b49 related-to-bug: 15106730 --- media/libmediaplayerservice/StagefrightRecorder.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 5b7a236..bfc075c 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -932,6 +932,10 @@ sp StagefrightRecorder::createAudioSource() { MediaCodecSource::Create(mLooper, format, audioSource); mAudioSourceNode = audioSource; + if (audioEncoder == NULL) { + ALOGE("Failed to create audio encoder"); + } + return audioEncoder; } @@ -1487,7 +1491,7 @@ status_t StagefrightRecorder::setupVideoEncoder( sp encoder = MediaCodecSource::Create(mLooper, format, cameraSource, flags); if (encoder == NULL) { - ALOGW("Failed to create the encoder"); + ALOGE("Failed to create video encoder"); // When the encoder fails to be created, we need // release the camera source due to the camera's lock // and unlock mechanism. -- cgit v1.1 From b7f24b101d43139b4c747129bfbc4ecf5c468b86 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Wed, 11 Jun 2014 10:05:30 -0700 Subject: AudioSystem: remove unused stream type The audio stream type is not used in the getSampleRate() and getFrameCount() methods. Change-Id: I3d065ae272bd039204cd323cdab9b60460034f2d --- media/libmedia/AudioSystem.cpp | 18 ++++++------------ media/libmedia/AudioTrack.cpp | 10 +++++----- 2 files changed, 11 insertions(+), 17 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index eafb3ad..15b32ff 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -242,11 +242,10 @@ status_t AudioSystem::getOutputSamplingRate(uint32_t* samplingRate, audio_stream return PERMISSION_DENIED; } - return getSamplingRate(output, streamType, samplingRate); + return getSamplingRate(output, samplingRate); } status_t AudioSystem::getSamplingRate(audio_io_handle_t output, - audio_stream_type_t streamType, uint32_t* samplingRate) { OutputDescriptor *outputDesc; @@ -265,13 +264,11 @@ status_t AudioSystem::getSamplingRate(audio_io_handle_t output, gLock.unlock(); } if (*samplingRate == 0) { - ALOGE("AudioSystem::getSamplingRate failed for output %d stream type %d", - output, streamType); + ALOGE("AudioSystem::getSamplingRate failed for output %d", output); return BAD_VALUE; } - ALOGV("getSamplingRate() streamType %d, output %d, sampling rate %u", streamType, output, - *samplingRate); + ALOGV("getSamplingRate() output %d, sampling rate %u", output, *samplingRate); return NO_ERROR; } @@ -289,11 +286,10 @@ status_t AudioSystem::getOutputFrameCount(size_t* frameCount, audio_stream_type_ return PERMISSION_DENIED; } - return getFrameCount(output, streamType, frameCount); + return getFrameCount(output, frameCount); } status_t AudioSystem::getFrameCount(audio_io_handle_t output, - audio_stream_type_t streamType, size_t* frameCount) { OutputDescriptor *outputDesc; @@ -310,13 +306,11 @@ status_t AudioSystem::getFrameCount(audio_io_handle_t output, gLock.unlock(); } if (*frameCount == 0) { - ALOGE("AudioSystem::getFrameCount failed for output %d stream type %d", - output, streamType); + ALOGE("AudioSystem::getFrameCount failed for output %d", output); return BAD_VALUE; } - ALOGV("getFrameCount() streamType %d, output %d, frameCount %d", streamType, output, - *frameCount); + ALOGV("getFrameCount() output %d, frameCount %d", output, *frameCount); return NO_ERROR; } diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 7d3ecc5..6989aaf 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -647,7 +647,7 @@ uint32_t AudioTrack::getSampleRate() const if (isOffloaded_l()) { if (mOutput != AUDIO_IO_HANDLE_NONE) { uint32_t sampleRate = 0; - status_t status = AudioSystem::getSamplingRate(mOutput, mStreamType, &sampleRate); + status_t status = AudioSystem::getSamplingRate(mOutput, &sampleRate); if (status == NO_ERROR) { mSampleRate = sampleRate; } @@ -887,16 +887,16 @@ status_t AudioTrack::createTrack_l(size_t epoch) } size_t afFrameCount; - status = AudioSystem::getFrameCount(output, mStreamType, &afFrameCount); + status = AudioSystem::getFrameCount(output, &afFrameCount); if (status != NO_ERROR) { - ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, mStreamType, status); + ALOGE("getFrameCount(output=%d) status %d", output, status); goto release; } uint32_t afSampleRate; - status = AudioSystem::getSamplingRate(output, mStreamType, &afSampleRate); + status = AudioSystem::getSamplingRate(output, &afSampleRate); if (status != NO_ERROR) { - ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, mStreamType, status); + ALOGE("getSamplingRate(output=%d) status %d", output, status); goto release; } -- cgit v1.1 From 3bcffa136909c1fb6e88ee4efd12ccac18360a85 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 12 Jun 2014 18:38:45 -0700 Subject: force command flush after releasing a reference to shared memory After releasing a reference to a shared memory interface, IPCThreadState::self()->flushCommands() must be called to ensure that the corresponding reference is also cleared immediately in the remote process. Otherwise the binder implementaiton will not push the clear systematically causing the memory region not to be freed. See issues 10711502 and 2801375. Bug: 14057166. Change-Id: If55f36f00d452d6cf00cf83bd2fba1c8f3abcb57 --- media/libmedia/AudioRecord.cpp | 5 ++++- media/libmedia/AudioTrack.cpp | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index db61e85..50b444a 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -105,6 +105,8 @@ AudioRecord::~AudioRecord() } mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this); mAudioRecord.clear(); + mCblkMemory.clear(); + mBufferMemory.clear(); IPCThreadState::self()->flushCommands(); AudioSystem::releaseAudioSessionId(mSessionId, -1); } @@ -546,9 +548,10 @@ status_t AudioRecord::openRecord_l(size_t epoch) mDeathNotifier.clear(); } mAudioRecord = record; - mCblkMemory = iMem; mBufferMemory = bufferMem; + IPCThreadState::self()->flushCommands(); + mCblk = cblk; // note that temp is the (possibly revised) value of frameCount if (temp < frameCount || (frameCount == 0 && temp == 0)) { diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 7d3ecc5..fa8e5c3 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -174,6 +174,8 @@ AudioTrack::~AudioTrack() } mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this); mAudioTrack.clear(); + mCblkMemory.clear(); + mSharedBuffer.clear(); IPCThreadState::self()->flushCommands(); ALOGV("~AudioTrack, releasing session id from %d on behalf of %d", IPCThreadState::self()->getCallingPid(), mClientPid); @@ -1059,8 +1061,9 @@ status_t AudioTrack::createTrack_l(size_t epoch) mDeathNotifier.clear(); } mAudioTrack = track; - mCblkMemory = iMem; + IPCThreadState::self()->flushCommands(); + audio_track_cblk_t* cblk = static_cast(iMemPointer); mCblk = cblk; // note that temp is the (possibly revised) value of frameCount -- cgit v1.1 From 404fced9bfa8fa423ee210a271ca051ffd1bec13 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 11 Jun 2014 14:45:31 -0700 Subject: refactor getTrackInfo() (this is in preparation for supporting other cc source) - split into two methods: getTrackCount() and getTrackInfo() - move track info parcelling to NuPlayer - parcel in the mime type of the subtitle format Bug: 15470448 Change-Id: If00724d8c3a2b2319cb9c5f29d3fe76347bfe947 --- .../nuplayer/HTTPLiveSource.cpp | 8 +- .../nuplayer/HTTPLiveSource.h | 3 +- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 103 ++++++++++++++++----- media/libmediaplayerservice/nuplayer/NuPlayer.h | 5 + .../nuplayer/NuPlayerSource.h | 8 +- media/libstagefright/MediaDefs.cpp | 1 + media/libstagefright/httplive/LiveSession.cpp | 8 +- media/libstagefright/httplive/LiveSession.h | 3 +- media/libstagefright/httplive/M3UParser.cpp | 77 ++++++++------- media/libstagefright/httplive/M3UParser.h | 3 +- 10 files changed, 154 insertions(+), 65 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp index cbedf5c..e8431e9 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp @@ -120,8 +120,12 @@ status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) { return mLiveSession->getDuration(durationUs); } -status_t NuPlayer::HTTPLiveSource::getTrackInfo(Parcel *reply) const { - return mLiveSession->getTrackInfo(reply); +size_t NuPlayer::HTTPLiveSource::getTrackCount() const { + return mLiveSession->getTrackCount(); +} + +sp NuPlayer::HTTPLiveSource::getTrackInfo(size_t trackIndex) const { + return mLiveSession->getTrackInfo(trackIndex); } status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select) { diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h index 4d7251f..6b5f6af 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h @@ -40,7 +40,8 @@ struct NuPlayer::HTTPLiveSource : public NuPlayer::Source { virtual status_t feedMoreTSData(); virtual status_t getDuration(int64_t *durationUs); - virtual status_t getTrackInfo(Parcel *reply) const; + virtual size_t getTrackCount() const; + virtual sp getTrackInfo(size_t trackIndex) const; virtual status_t selectTrack(size_t trackIndex, bool select); virtual status_t seekTo(int64_t seekTimeUs); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 857e703..dc69f73 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -305,6 +305,34 @@ bool NuPlayer::IsFlushingState(FlushStatus state, bool *needShutdown) { } } +void NuPlayer::writeTrackInfo( + Parcel* reply, const sp format) const { + int32_t trackType; + CHECK(format->findInt32("type", &trackType)); + + AString lang; + CHECK(format->findString("language", &lang)); + + reply->writeInt32(2); // write something non-zero + reply->writeInt32(trackType); + reply->writeString16(String16(lang.c_str())); + + if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { + AString mime; + CHECK(format->findString("mime", &mime)); + + int32_t isAuto, isDefault, isForced; + CHECK(format->findInt32("auto", &isAuto)); + CHECK(format->findInt32("default", &isDefault)); + CHECK(format->findInt32("forced", &isForced)); + + reply->writeString16(String16(mime.c_str())); + reply->writeInt32(isAuto); + reply->writeInt32(isDefault); + reply->writeInt32(isForced); + } +} + void NuPlayer::onMessageReceived(const sp &msg) { switch (msg->what()) { case kWhatSetDataSource: @@ -339,16 +367,23 @@ void NuPlayer::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - status_t err = INVALID_OPERATION; + Parcel* reply; + CHECK(msg->findPointer("reply", (void**)&reply)); + + size_t inbandTracks = 0; if (mSource != NULL) { - Parcel* reply; - CHECK(msg->findPointer("reply", (void**)&reply)); - err = mSource->getTrackInfo(reply); + inbandTracks = mSource->getTrackCount(); } - sp response = new AMessage; - response->setInt32("err", err); + // total track count + reply->writeInt32(inbandTracks); + + // write inband tracks + for (size_t i = 0; i < inbandTracks; ++i) { + writeTrackInfo(reply, mSource->getTrackInfo(i)); + } + sp response = new AMessage; response->postReply(replyID); break; } @@ -358,12 +393,19 @@ void NuPlayer::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); + size_t trackIndex; + int32_t select; + CHECK(msg->findSize("trackIndex", &trackIndex)); + CHECK(msg->findInt32("select", &select)); + status_t err = INVALID_OPERATION; + + size_t inbandTracks = 0; if (mSource != NULL) { - size_t trackIndex; - int32_t select; - CHECK(msg->findSize("trackIndex", &trackIndex)); - CHECK(msg->findInt32("select", &select)); + inbandTracks = mSource->getTrackCount(); + } + + if (trackIndex < inbandTracks) { err = mSource->selectTrack(trackIndex, select); } @@ -1187,6 +1229,14 @@ status_t NuPlayer::selectTrack(size_t trackIndex, bool select) { sp response; status_t err = msg->postAndAwaitResponse(&response); + if (err != OK) { + return err; + } + + if (!response->findInt32("err", &err)) { + err = OK; + } + return err; } @@ -1438,21 +1488,7 @@ void NuPlayer::onSourceNotify(const sp &msg) { sp buffer; CHECK(msg->findBuffer("buffer", &buffer)); - int32_t trackIndex; - int64_t timeUs, durationUs; - CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex)); - CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); - CHECK(buffer->meta()->findInt64("durationUs", &durationUs)); - - Parcel in; - in.writeInt32(trackIndex); - in.writeInt64(timeUs); - in.writeInt64(durationUs); - in.writeInt32(buffer->size()); - in.writeInt32(buffer->size()); - in.write(buffer->data(), buffer->size()); - - notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in); + sendSubtitleData(buffer, 0 /* baseIndex */); break; } @@ -1474,6 +1510,23 @@ void NuPlayer::onSourceNotify(const sp &msg) { } } +void NuPlayer::sendSubtitleData(const sp &buffer, int32_t baseIndex) { + int32_t trackIndex; + int64_t timeUs, durationUs; + CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex)); + CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); + CHECK(buffer->meta()->findInt64("durationUs", &durationUs)); + + Parcel in; + in.writeInt32(trackIndex + baseIndex); + in.writeInt64(timeUs); + in.writeInt64(durationUs); + in.writeInt32(buffer->size()); + in.writeInt32(buffer->size()); + in.write(buffer->data(), buffer->size()); + + notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in); +} //////////////////////////////////////////////////////////////////////////////// void NuPlayer::Source::notifyFlagsChanged(uint32_t flags) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index f1d3d55..f95cc11 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -24,6 +24,7 @@ namespace android { +struct ABuffer; struct MetaData; struct NuPlayerDriver; @@ -189,6 +190,10 @@ private: void queueDecoderShutdown( bool audio, bool video, const sp &reply); + void sendSubtitleData(const sp &buffer, int32_t baseIndex); + + void writeTrackInfo(Parcel* reply, const sp format) const; + DISALLOW_EVIL_CONSTRUCTORS(NuPlayer); }; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index 11279fc..f5a1d6d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -72,8 +72,12 @@ struct NuPlayer::Source : public AHandler { return INVALID_OPERATION; } - virtual status_t getTrackInfo(Parcel* /* reply */) const { - return INVALID_OPERATION; + virtual size_t getTrackCount() const { + return 0; + } + + virtual sp getTrackInfo(size_t /* trackIndex */) const { + return NULL; } virtual status_t selectTrack(size_t /* trackIndex */, bool /* select */) { diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp index 8229e55..f38729e 100644 --- a/media/libstagefright/MediaDefs.cpp +++ b/media/libstagefright/MediaDefs.cpp @@ -58,5 +58,6 @@ const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm"; const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt"; const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; +const char *MEDIA_MIMETYPE_TEXT_VTT = "text/vtt"; } // namespace android diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 08a146f..10cdde2 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -926,8 +926,12 @@ bool LiveSession::hasDynamicDuration() const { return false; } -status_t LiveSession::getTrackInfo(Parcel *reply) const { - return mPlaylist->getTrackInfo(reply); +size_t LiveSession::getTrackCount() const { + return mPlaylist->getTrackCount(); +} + +sp LiveSession::getTrackInfo(size_t trackIndex) const { + return mPlaylist->getTrackInfo(trackIndex); } status_t LiveSession::selectTrack(size_t index, bool select) { diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index d7ed56f..ed3818f 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -70,7 +70,8 @@ struct LiveSession : public AHandler { status_t seekTo(int64_t timeUs); status_t getDuration(int64_t *durationUs) const; - status_t getTrackInfo(Parcel *reply) const; + size_t getTrackCount() const; + sp getTrackInfo(size_t trackIndex) const; status_t selectTrack(size_t index, bool select); bool isSeekable() const; diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 785c515..281e0da 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -58,8 +59,8 @@ struct M3UParser::MediaGroup : public RefBase { void pickRandomMediaItems(); status_t selectTrack(size_t index, bool select); - void getTrackInfo(Parcel* reply) const; size_t countTracks() const; + sp getTrackInfo(size_t index) const; protected: virtual ~MediaGroup(); @@ -184,35 +185,42 @@ status_t M3UParser::MediaGroup::selectTrack(size_t index, bool select) { return OK; } -void M3UParser::MediaGroup::getTrackInfo(Parcel* reply) const { - for (size_t i = 0; i < mMediaItems.size(); ++i) { - reply->writeInt32(2); // 2 fields - - if (mType == TYPE_AUDIO) { - reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO); - } else if (mType == TYPE_VIDEO) { - reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO); - } else if (mType == TYPE_SUBS) { - reply->writeInt32(MEDIA_TRACK_TYPE_SUBTITLE); - } else { - reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN); - } +size_t M3UParser::MediaGroup::countTracks() const { + return mMediaItems.size(); +} - const Media &item = mMediaItems.itemAt(i); - const char *lang = item.mLanguage.empty() ? "und" : item.mLanguage.c_str(); - reply->writeString16(String16(lang)); +sp M3UParser::MediaGroup::getTrackInfo(size_t index) const { + if (index >= mMediaItems.size()) { + return NULL; + } - if (mType == TYPE_SUBS) { - // TO-DO: pass in a MediaFormat instead - reply->writeInt32(!!(item.mFlags & MediaGroup::FLAG_AUTOSELECT)); - reply->writeInt32(!!(item.mFlags & MediaGroup::FLAG_DEFAULT)); - reply->writeInt32(!!(item.mFlags & MediaGroup::FLAG_FORCED)); - } + sp format = new AMessage(); + + int32_t trackType; + if (mType == TYPE_AUDIO) { + trackType = MEDIA_TRACK_TYPE_AUDIO; + } else if (mType == TYPE_VIDEO) { + trackType = MEDIA_TRACK_TYPE_VIDEO; + } else if (mType == TYPE_SUBS) { + trackType = MEDIA_TRACK_TYPE_SUBTITLE; + } else { + trackType = MEDIA_TRACK_TYPE_UNKNOWN; + } + format->setInt32("type", trackType); + + const Media &item = mMediaItems.itemAt(index); + const char *lang = item.mLanguage.empty() ? "und" : item.mLanguage.c_str(); + format->setString("language", lang); + + if (mType == TYPE_SUBS) { + // TO-DO: pass in a MediaFormat instead + format->setString("mime", MEDIA_MIMETYPE_TEXT_VTT); + format->setInt32("auto", !!(item.mFlags & MediaGroup::FLAG_AUTOSELECT)); + format->setInt32("default", !!(item.mFlags & MediaGroup::FLAG_DEFAULT)); + format->setInt32("forced", !!(item.mFlags & MediaGroup::FLAG_FORCED)); } -} -size_t M3UParser::MediaGroup::countTracks() const { - return mMediaItems.size(); + return format; } bool M3UParser::MediaGroup::getActiveURI(AString *uri) const { @@ -319,17 +327,24 @@ status_t M3UParser::selectTrack(size_t index, bool select) { return INVALID_OPERATION; } -status_t M3UParser::getTrackInfo(Parcel* reply) const { +size_t M3UParser::getTrackCount() const { size_t trackCount = 0; for (size_t i = 0; i < mMediaGroups.size(); ++i) { trackCount += mMediaGroups.valueAt(i)->countTracks(); } - reply->writeInt32(trackCount); + return trackCount; +} - for (size_t i = 0; i < mMediaGroups.size(); ++i) { - mMediaGroups.valueAt(i)->getTrackInfo(reply); +sp M3UParser::getTrackInfo(size_t index) const { + for (size_t i = 0, ii = index; i < mMediaGroups.size(); ++i) { + sp group = mMediaGroups.valueAt(i); + size_t tracks = group->countTracks(); + if (ii < tracks) { + return group->getTrackInfo(ii); + } + ii -= tracks; } - return OK; + return NULL; } ssize_t M3UParser::getSelectedIndex() const { diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h index ccd6556..fe9fb9d 100644 --- a/media/libstagefright/httplive/M3UParser.h +++ b/media/libstagefright/httplive/M3UParser.h @@ -42,7 +42,8 @@ struct M3UParser : public RefBase { void pickRandomMediaItems(); status_t selectTrack(size_t index, bool select); - status_t getTrackInfo(Parcel* reply) const; + size_t getTrackCount() const; + sp getTrackInfo(size_t index) const; ssize_t getSelectedIndex() const; bool getTypeURI(size_t index, const char *key, AString *uri) const; -- cgit v1.1 From a7fa1d9530b6870f2c7850e3025d7db963661803 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 11 Jun 2014 14:49:23 -0700 Subject: support for CEA-608 closed caption Bug: 15470448 Change-Id: Ic6a527f5c35a8ee0a08a5b043336e4d193216083 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 77 +++++- media/libmediaplayerservice/nuplayer/NuPlayer.h | 4 + .../nuplayer/NuPlayerDecoder.cpp | 268 +++++++++++++++++++++ .../nuplayer/NuPlayerDecoder.h | 30 +++ media/libstagefright/MediaDefs.cpp | 1 + media/libstagefright/mpeg2ts/ESQueue.cpp | 6 + 6 files changed, 383 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index dc69f73..b333043 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -375,14 +375,24 @@ void NuPlayer::onMessageReceived(const sp &msg) { inbandTracks = mSource->getTrackCount(); } + size_t ccTracks = 0; + if (mCCDecoder != NULL) { + ccTracks = mCCDecoder->getTrackCount(); + } + // total track count - reply->writeInt32(inbandTracks); + reply->writeInt32(inbandTracks + ccTracks); // write inband tracks for (size_t i = 0; i < inbandTracks; ++i) { writeTrackInfo(reply, mSource->getTrackInfo(i)); } + // write CC track + for (size_t i = 0; i < ccTracks; ++i) { + writeTrackInfo(reply, mCCDecoder->getTrackInfo(i)); + } + sp response = new AMessage; response->postReply(replyID); break; @@ -404,9 +414,19 @@ void NuPlayer::onMessageReceived(const sp &msg) { if (mSource != NULL) { inbandTracks = mSource->getTrackCount(); } + size_t ccTracks = 0; + if (mCCDecoder != NULL) { + ccTracks = mCCDecoder->getTrackCount(); + } if (trackIndex < inbandTracks) { err = mSource->selectTrack(trackIndex, select); + } else { + trackIndex -= inbandTracks; + + if (trackIndex < ccTracks) { + err = mCCDecoder->selectTrack(trackIndex, select); + } } sp response = new AMessage; @@ -870,6 +890,12 @@ void NuPlayer::onMessageReceived(const sp &msg) { break; } + case kWhatClosedCaptionNotify: + { + onClosedCaptionNotify(msg); + break; + } + default: TRESPASS(); break; @@ -933,6 +959,9 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp *decoder) { AString mime; CHECK(format->findString("mime", &mime)); mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str()); + + sp ccNotify = new AMessage(kWhatClosedCaptionNotify, id()); + mCCDecoder = new CCDecoder(ccNotify); } sp notify = @@ -1073,6 +1102,10 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { mediaTimeUs / 1E6); #endif + if (!audio) { + mCCDecoder->decode(accessUnit); + } + reply->setBuffer("buffer", accessUnit); reply->post(); @@ -1101,14 +1134,15 @@ void NuPlayer::renderBuffer(bool audio, const sp &msg) { sp buffer; CHECK(msg->findBuffer("buffer", &buffer)); + int64_t mediaTimeUs; + CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs)); + int64_t &skipUntilMediaTimeUs = audio ? mSkipRenderingAudioUntilMediaTimeUs : mSkipRenderingVideoUntilMediaTimeUs; if (skipUntilMediaTimeUs >= 0) { - int64_t mediaTimeUs; - CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs)); if (mediaTimeUs < skipUntilMediaTimeUs) { ALOGV("dropping %s buffer at time %lld as requested.", @@ -1122,6 +1156,10 @@ void NuPlayer::renderBuffer(bool audio, const sp &msg) { skipUntilMediaTimeUs = -1; } + if (!audio && mCCDecoder->isSelected()) { + mCCDecoder->display(mediaTimeUs); + } + mRenderer->queueBuffer(audio, buffer, reply); } @@ -1510,6 +1548,39 @@ void NuPlayer::onSourceNotify(const sp &msg) { } } +void NuPlayer::onClosedCaptionNotify(const sp &msg) { + int32_t what; + CHECK(msg->findInt32("what", &what)); + + switch (what) { + case NuPlayer::CCDecoder::kWhatClosedCaptionData: + { + sp buffer; + CHECK(msg->findBuffer("buffer", &buffer)); + + size_t inbandTracks = 0; + if (mSource != NULL) { + inbandTracks = mSource->getTrackCount(); + } + + sendSubtitleData(buffer, inbandTracks); + break; + } + + case NuPlayer::CCDecoder::kWhatTrackAdded: + { + notifyListener(MEDIA_INFO, MEDIA_INFO_METADATA_UPDATE, 0); + + break; + } + + default: + TRESPASS(); + } + + +} + void NuPlayer::sendSubtitleData(const sp &buffer, int32_t baseIndex) { int32_t trackIndex; int64_t timeUs, durationUs; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index f95cc11..5be71fb 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -76,6 +76,7 @@ public: private: struct Decoder; + struct CCDecoder; struct GenericSource; struct HTTPLiveSource; struct Renderer; @@ -98,6 +99,7 @@ private: kWhatScanSources = 'scan', kWhatVideoNotify = 'vidN', kWhatAudioNotify = 'audN', + kWhatClosedCaptionNotify = 'capN', kWhatRendererNotify = 'renN', kWhatReset = 'rset', kWhatSeek = 'seek', @@ -119,6 +121,7 @@ private: sp mVideoDecoder; bool mVideoIsAVC; sp mAudioDecoder; + sp mCCDecoder; sp mRenderer; List > mDeferredActions; @@ -186,6 +189,7 @@ private: void performSetSurface(const sp &wrapper); void onSourceNotify(const sp &msg); + void onClosedCaptionNotify(const sp &msg); void queueDecoderShutdown( bool audio, bool video, const sp &reply); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index cfbf282..5abfb71 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -22,6 +22,7 @@ #include "NuPlayerDecoder.h" #include +#include #include #include #include @@ -535,5 +536,272 @@ bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp &targetF return seamless; } +struct NuPlayer::CCDecoder::CCData { + CCData(uint8_t type, uint8_t data1, uint8_t data2) + : mType(type), mData1(data1), mData2(data2) { + } + + uint8_t mType; + uint8_t mData1; + uint8_t mData2; +}; + +NuPlayer::CCDecoder::CCDecoder(const sp ¬ify) + : mNotify(notify), + mTrackCount(0), + mSelectedTrack(-1) { +} + +size_t NuPlayer::CCDecoder::getTrackCount() const { + return mTrackCount; +} + +sp NuPlayer::CCDecoder::getTrackInfo(size_t index) const { + CHECK(index == 0); + + sp format = new AMessage(); + + format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE); + format->setString("language", "und"); + format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608); + format->setInt32("auto", 1); + format->setInt32("default", 1); + format->setInt32("forced", 0); + + return format; +} + +status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) { + CHECK(index < mTrackCount); + + if (select) { + if (mSelectedTrack == (ssize_t)index) { + ALOGE("track %zu already selected", index); + return BAD_VALUE; + } + ALOGV("selected track %zu", index); + mSelectedTrack = index; + } else { + if (mSelectedTrack != (ssize_t)index) { + ALOGE("track %zu is not selected", index); + return BAD_VALUE; + } + ALOGV("unselected track %zu", index); + mSelectedTrack = -1; + } + + return OK; +} + +bool NuPlayer::CCDecoder::isSelected() const { + return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)mTrackCount; +} + +bool NuPlayer::CCDecoder::isNullPad(CCData *cc) const { + return cc->mData1 < 0x10 && cc->mData2 < 0x10; +} + +void NuPlayer::CCDecoder::dumpBytePair(const sp &ccBuf) const { + size_t offset = 0; + AString out; + + while (offset < ccBuf->size()) { + char tmp[128]; + + CCData *cc = (CCData *) (ccBuf->data() + offset); + + if (isNullPad(cc)) { + // 1 null pad or XDS metadata, ignore + offset += sizeof(CCData); + continue; + } + + if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) { + // 2 basic chars + sprintf(tmp, "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2); + } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19) + && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) { + // 1 special char + sprintf(tmp, "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A) + && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){ + // 1 Spanish/French char + sprintf(tmp, "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B) + && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){ + // 1 Portuguese/German/Danish char + sprintf(tmp, "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19) + && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){ + // Mid-Row Codes (Table 69) + sprintf(tmp, "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c) + && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f) + || + ((cc->mData1 == 0x17 || cc->mData1 == 0x1f) + && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){ + // Misc Control Codes (Table 70) + sprintf(tmp, "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } else if ((cc->mData1 & 0x70) == 0x10 + && (cc->mData2 & 0x40) == 0x40 + && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) { + // Preamble Address Codes (Table 71) + sprintf(tmp, "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } else { + sprintf(tmp, "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } + + if (out.size() > 0) { + out.append(", "); + } + + out.append(tmp); + + offset += sizeof(CCData); + } + + ALOGI("%s", out.c_str()); +} + +bool NuPlayer::CCDecoder::extractFromSEI(const sp &accessUnit) { + int64_t timeUs; + CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); + + sp sei; + if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) { + return false; + } + + bool hasCC = false; + + ABitReader br(sei->data() + 1, sei->size() - 1); + // sei_message() + while (br.numBitsLeft() >= 16) { // at least 16-bit for sei_message() + uint32_t payload_type = 0; + size_t payload_size = 0; + uint8_t last_byte; + + do { + last_byte = br.getBits(8); + payload_type += last_byte; + } while (last_byte == 0xFF); + + do { + last_byte = br.getBits(8); + payload_size += last_byte; + } while (last_byte == 0xFF); + + // sei_payload() + if (payload_type == 4) { + // user_data_registered_itu_t_t35() + + // ATSC A/72: 6.4.2 + uint8_t itu_t_t35_country_code = br.getBits(8); + uint16_t itu_t_t35_provider_code = br.getBits(16); + uint32_t user_identifier = br.getBits(32); + uint8_t user_data_type_code = br.getBits(8); + + payload_size -= 1 + 2 + 4 + 1; + + if (itu_t_t35_country_code == 0xB5 + && itu_t_t35_provider_code == 0x0031 + && user_identifier == 'GA94' + && user_data_type_code == 0x3) { + hasCC = true; + + // MPEG_cc_data() + // ATSC A/53 Part 4: 6.2.3.1 + br.skipBits(1); //process_em_data_flag + bool process_cc_data_flag = br.getBits(1); + br.skipBits(1); //additional_data_flag + size_t cc_count = br.getBits(5); + br.skipBits(8); // em_data; + payload_size -= 2; + + if (process_cc_data_flag) { + AString out; + + sp ccBuf = new ABuffer(cc_count * sizeof(CCData)); + ccBuf->setRange(0, 0); + + for (size_t i = 0; i < cc_count; i++) { + uint8_t marker = br.getBits(5); + CHECK_EQ(marker, 0x1f); + + bool cc_valid = br.getBits(1); + uint8_t cc_type = br.getBits(2); + // remove odd parity bit + uint8_t cc_data_1 = br.getBits(8) & 0x7f; + uint8_t cc_data_2 = br.getBits(8) & 0x7f; + + if (cc_valid + && (cc_type == 0 || cc_type == 1)) { + CCData cc(cc_type, cc_data_1, cc_data_2); + if (!isNullPad(&cc)) { + memcpy(ccBuf->data() + ccBuf->size(), + (void *)&cc, sizeof(cc)); + ccBuf->setRange(0, ccBuf->size() + sizeof(CCData)); + } + } + } + payload_size -= cc_count * 3; + + mCCMap.add(timeUs, ccBuf); + break; + } + } else { + ALOGV("Malformed SEI payload type 4"); + } + } else { + ALOGV("Unsupported SEI payload type %d", payload_type); + } + + // skipping remaining bits of this payload + br.skipBits(payload_size * 8); + } + + return hasCC; +} + +void NuPlayer::CCDecoder::decode(const sp &accessUnit) { + if (extractFromSEI(accessUnit) && mTrackCount == 0) { + mTrackCount++; + + ALOGI("Found CEA-608 track"); + sp msg = mNotify->dup(); + msg->setInt32("what", kWhatTrackAdded); + msg->post(); + } + // TODO: extract CC from other sources +} + +void NuPlayer::CCDecoder::display(int64_t timeUs) { + ssize_t index = mCCMap.indexOfKey(timeUs); + if (index < 0) { + ALOGV("cc for timestamp %" PRId64 " not found", timeUs); + return; + } + + sp &ccBuf = mCCMap.editValueAt(index); + + if (ccBuf->size() > 0) { +#if 0 + dumpBytePair(ccBuf); +#endif + + ccBuf->meta()->setInt32("trackIndex", mSelectedTrack); + ccBuf->meta()->setInt64("timeUs", timeUs); + ccBuf->meta()->setInt64("durationUs", 0ll); + + sp msg = mNotify->dup(); + msg->setInt32("what", kWhatClosedCaptionData); + msg->setBuffer("buffer", ccBuf); + msg->post(); + } + + // remove all entries before timeUs + mCCMap.removeItemsAt(0, index + 1); +} + } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index 2892584..1a4f4ab 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -101,6 +101,36 @@ private: DISALLOW_EVIL_CONSTRUCTORS(Decoder); }; +struct NuPlayer::CCDecoder : public RefBase { + enum { + kWhatClosedCaptionData, + kWhatTrackAdded, + }; + + CCDecoder(const sp ¬ify); + + size_t getTrackCount() const; + sp getTrackInfo(size_t index) const; + status_t selectTrack(size_t index, bool select); + bool isSelected() const; + void decode(const sp &accessUnit); + void display(int64_t timeUs); + +private: + struct CCData; + + sp mNotify; + KeyedVector > mCCMap; + size_t mTrackCount; + int32_t mSelectedTrack; + + bool isNullPad(CCData *cc) const; + void dumpBytePair(const sp &ccBuf) const; + bool extractFromSEI(const sp &accessUnit); + + DISALLOW_EVIL_CONSTRUCTORS(CCDecoder); +}; + } // namespace android #endif // NUPLAYER_DECODER_H_ diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp index f38729e..d48dd84 100644 --- a/media/libstagefright/MediaDefs.cpp +++ b/media/libstagefright/MediaDefs.cpp @@ -59,5 +59,6 @@ const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm"; const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt"; const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; const char *MEDIA_MIMETYPE_TEXT_VTT = "text/vtt"; +const char *MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608"; } // namespace android diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp index f7abf01..3c8f03e 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.cpp +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp @@ -777,6 +777,12 @@ sp ElementaryStreamQueue::dequeueAccessUnitH264() { unsigned nalType = mBuffer->data()[pos.nalOffset] & 0x1f; + if (nalType == 6) { + sp sei = new ABuffer(pos.nalSize); + memcpy(sei->data(), mBuffer->data() + pos.nalOffset, pos.nalSize); + accessUnit->meta()->setBuffer("sei", sei); + } + #if !LOG_NDEBUG char tmp[128]; sprintf(tmp, "0x%02x", nalType); -- cgit v1.1 From 7791cf11186a22b3f84d98cfde67393bee748cb0 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 10 Jun 2014 14:24:40 -0700 Subject: Fix logging Make the log message specify whether it was an encoder or a decoder that failed to instantiate. Change-Id: Ie357775114c8dea722d87381c13affdfb19dcde4 --- media/libstagefright/ACodec.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index d3c508d..9ab1417 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -3888,6 +3888,7 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp &msg) { AString componentName; uint32_t quirks = 0; + int32_t encoder = false; if (msg->findString("componentName", &componentName)) { ssize_t index = matchingCodecs.add(); OMXCodec::CodecNameAndQuirks *entry = &matchingCodecs.editItemAt(index); @@ -3900,7 +3901,6 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp &msg) { } else { CHECK(msg->findString("mime", &mime)); - int32_t encoder; if (!msg->findInt32("encoder", &encoder)) { encoder = false; } @@ -3936,10 +3936,10 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp &msg) { if (node == NULL) { if (!mime.empty()) { - ALOGE("Unable to instantiate a decoder for type '%s'.", - mime.c_str()); + ALOGE("Unable to instantiate a %scoder for type '%s'.", + encoder ? "en" : "de", mime.c_str()); } else { - ALOGE("Unable to instantiate decoder '%s'.", componentName.c_str()); + ALOGE("Unable to instantiate codec '%s'.", componentName.c_str()); } mCodec->signalError(OMX_ErrorComponentNotFound); -- cgit v1.1 From 8da8b2e80ccdb10ff2445f503829f803d3a6ab9f Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 13 Jun 2014 14:13:44 -0700 Subject: Fail more gracefully on allocation failure Check allocations when the size is read from a file and might therefore be invalid. b/14388161 Change-Id: Ia08cc0a6107f275a70e793ef3b50c0ce16ceeee0 --- media/libstagefright/MPEG4Extractor.cpp | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 297f4fc..23b221d 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -369,7 +369,7 @@ MPEG4Extractor::~MPEG4Extractor() { SINF *sinf = mFirstSINF; while (sinf) { SINF *next = sinf->next; - delete sinf->IPMPData; + delete[] sinf->IPMPData; delete sinf; sinf = next; } @@ -694,7 +694,10 @@ status_t MPEG4Extractor::parseDrmSINF( return ERROR_MALFORMED; } sinf->len = dataLen - 3; - sinf->IPMPData = new char[sinf->len]; + sinf->IPMPData = new (std::nothrow) char[sinf->len]; + if (sinf->IPMPData == NULL) { + return ERROR_MALFORMED; + } data_offset += 2; if (mDataSource->readAt(data_offset, sinf->IPMPData, sinf->len) < sinf->len) { @@ -1112,7 +1115,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { return ERROR_MALFORMED; } - pssh.data = new uint8_t[pssh.datalen]; + pssh.data = new (std::nothrow) uint8_t[pssh.datalen]; + if (pssh.data == NULL) { + return ERROR_MALFORMED; + } ALOGV("allocated pssh @ %p", pssh.data); ssize_t requested = (ssize_t) pssh.datalen; if (mDataSource->readAt(data_offset + 24, pssh.data, requested) < requested) { @@ -1794,7 +1800,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { size = 0; } - uint8_t *buffer = new uint8_t[size + chunk_size]; + uint8_t *buffer = new (std::nothrow) uint8_t[size + chunk_size]; + if (buffer == NULL) { + return ERROR_MALFORMED; + } if (size > 0) { memcpy(buffer, data, size); @@ -2111,7 +2120,10 @@ status_t MPEG4Extractor::parseITunesMetaData(off64_t offset, size_t size) { return ERROR_MALFORMED; } - uint8_t *buffer = new uint8_t[size + 1]; + uint8_t *buffer = new (std::nothrow) uint8_t[size + 1]; + if (buffer == NULL) { + return ERROR_MALFORMED; + } if (mDataSource->readAt( offset, buffer, size) != (ssize_t)size) { delete[] buffer; @@ -2298,7 +2310,10 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept return ERROR_MALFORMED; } - uint8_t *buffer = new uint8_t[size]; + uint8_t *buffer = new (std::nothrow) uint8_t[size]; + if (buffer == NULL) { + return ERROR_MALFORMED; + } if (mDataSource->readAt( offset, buffer, size) != (ssize_t)size) { delete[] buffer; @@ -2917,7 +2932,11 @@ status_t MPEG4Source::start(MetaData *params) { mGroup->add_buffer(new MediaBuffer(max_size)); - mSrcBuffer = new uint8_t[max_size]; + mSrcBuffer = new (std::nothrow) uint8_t[max_size]; + if (mSrcBuffer == NULL) { + // file probably specified a bad max size + return ERROR_MALFORMED; + } mStarted = true; -- cgit v1.1 From faabb51ceef13bf1e3f692219ac410c1cd75d0de Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Wed, 11 Jun 2014 16:55:06 -0700 Subject: AudioTrack construction with audio attributes Store audio attributes in AudioTrack class. When an AudioTrack is "set" with non null audio attributes, derive a stream type that reflects the attributes. When an AudioTrack is "set" without attributes, and only has a stream type, derive default audio attributes. Change-Id: I322b91fa9a7e193118960c5e78cdddd85d66f9ad --- media/libmedia/AudioTrack.cpp | 173 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 163 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index e6827ee..000185b 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -103,6 +103,10 @@ AudioTrack::AudioTrack() mPreviousSchedulingGroup(SP_DEFAULT), mPausedPosition(0) { + mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN; + mAttributes.usage = AUDIO_USAGE_UNKNOWN; + mAttributes.flags = 0x0; + strcpy(mAttributes.tags, ""); } AudioTrack::AudioTrack( @@ -129,7 +133,7 @@ AudioTrack::AudioTrack( mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, - offloadInfo, uid, pid); + offloadInfo, uid, pid, NULL /*no audio attributes*/); } AudioTrack::AudioTrack( @@ -156,7 +160,7 @@ AudioTrack::AudioTrack( mStatus = set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags, cbf, user, notificationFrames, sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, - uid, pid); + uid, pid, NULL /*no audio attributes*/); } AudioTrack::~AudioTrack() @@ -199,7 +203,8 @@ status_t AudioTrack::set( transfer_type transferType, const audio_offload_info_t *offloadInfo, int uid, - pid_t pid) + pid_t pid, + audio_attributes_t* pAttributes) { ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, " "flags #%x, notificationFrames %u, sessionId %d, transferType %d", @@ -259,18 +264,34 @@ status_t AudioTrack::set( if (streamType == AUDIO_STREAM_DEFAULT) { streamType = AUDIO_STREAM_MUSIC; } - if (uint32_t(streamType) >= AUDIO_STREAM_CNT) { - ALOGE("Invalid stream type %d", streamType); - return BAD_VALUE; + + if (pAttributes == NULL) { + if (uint32_t(streamType) >= AUDIO_STREAM_CNT) { + ALOGE("Invalid stream type %d", streamType); + return BAD_VALUE; + } + setAttributesFromStreamType(streamType); + mStreamType = streamType; + } else { + if (!isValidAttributes(pAttributes)) { + ALOGE("Invalid attributes: usage=%d content=%d flags=0x%x tags=[%s]", + pAttributes->usage, pAttributes->content_type, pAttributes->flags, + pAttributes->tags); + } + // stream type shouldn't be looked at, this track has audio attributes + memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t)); + setStreamTypeFromAttributes(mAttributes); + ALOGV("Building AudioTrack with attributes: usage=%d content=%d flags=0x%x tags=[%s]", + mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags); } - mStreamType = streamType; status_t status; if (sampleRate == 0) { - status = AudioSystem::getOutputSamplingRate(&sampleRate, streamType); + // TODO replace with new APM method with support for audio_attributes_t + status = AudioSystem::getOutputSamplingRate(&sampleRate, mStreamType); if (status != NO_ERROR) { ALOGE("Could not get output sample rate for stream type %d; status %d", - streamType, status); + mStreamType, status); return status; } } @@ -314,7 +335,7 @@ status_t AudioTrack::set( ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST); } // only allow deep buffering for music stream type - if (streamType != AUDIO_STREAM_MUSIC) { + if (mStreamType != AUDIO_STREAM_MUSIC) { flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER); } @@ -620,6 +641,7 @@ status_t AudioTrack::setSampleRate(uint32_t rate) } uint32_t afSamplingRate; + // TODO replace with new APM method with support for audio_attributes_t if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) { return NO_INIT; } @@ -867,6 +889,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) return NO_INIT; } + // TODO replace with new APM method with support for audio_attributes_t audio_io_handle_t output = AudioSystem::getOutput(mStreamType, mSampleRate, mFormat, mChannelMask, mFlags, mOffloadInfo); if (output == AUDIO_IO_HANDLE_NONE) { @@ -1858,6 +1881,136 @@ uint32_t AudioTrack::getUnderrunFrames() const return mProxy->getUnderrunFrames(); } +void AudioTrack::setAttributesFromStreamType(audio_stream_type_t streamType) { + mAttributes.flags = 0x0; + + switch(streamType) { + case AUDIO_STREAM_DEFAULT: + case AUDIO_STREAM_MUSIC: + mAttributes.content_type = AUDIO_CONTENT_TYPE_MUSIC; + mAttributes.usage = AUDIO_USAGE_MEDIA; + break; + case AUDIO_STREAM_VOICE_CALL: + mAttributes.content_type = AUDIO_CONTENT_TYPE_SPEECH; + mAttributes.usage = AUDIO_USAGE_VOICE_COMMUNICATION; + break; + case AUDIO_STREAM_ENFORCED_AUDIBLE: + mAttributes.flags |= AUDIO_FLAG_AUDIBILITY_ENFORCED; + // intended fall through, attributes in common with STREAM_SYSTEM + case AUDIO_STREAM_SYSTEM: + mAttributes.content_type = AUDIO_CONTENT_TYPE_SONIFICATION; + mAttributes.usage = AUDIO_USAGE_ASSISTANCE_SONIFICATION; + break; + case AUDIO_STREAM_RING: + mAttributes.content_type = AUDIO_CONTENT_TYPE_SONIFICATION; + mAttributes.usage = AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE; + break; + case AUDIO_STREAM_ALARM: + mAttributes.content_type = AUDIO_CONTENT_TYPE_SONIFICATION; + mAttributes.usage = AUDIO_USAGE_ALARM; + break; + case AUDIO_STREAM_NOTIFICATION: + mAttributes.content_type = AUDIO_CONTENT_TYPE_SONIFICATION; + mAttributes.usage = AUDIO_USAGE_NOTIFICATION; + break; + case AUDIO_STREAM_BLUETOOTH_SCO: + mAttributes.content_type = AUDIO_CONTENT_TYPE_SPEECH; + mAttributes.usage = AUDIO_USAGE_VOICE_COMMUNICATION; + mAttributes.flags |= AUDIO_FLAG_SCO; + break; + case AUDIO_STREAM_DTMF: + mAttributes.content_type = AUDIO_CONTENT_TYPE_SONIFICATION; + mAttributes.usage = AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING; + break; + case AUDIO_STREAM_TTS: + mAttributes.content_type = AUDIO_CONTENT_TYPE_SPEECH; + mAttributes.usage = AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY; + break; + default: + ALOGE("invalid stream type %d when converting to attributes", streamType); + } +} + +void AudioTrack::setStreamTypeFromAttributes(audio_attributes_t& aa) { + // flags to stream type mapping + if ((aa.flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) { + mStreamType = AUDIO_STREAM_ENFORCED_AUDIBLE; + return; + } + if ((aa.flags & AUDIO_FLAG_SCO) == AUDIO_FLAG_SCO) { + mStreamType = AUDIO_STREAM_BLUETOOTH_SCO; + return; + } + + // usage to stream type mapping + switch (aa.usage) { + case AUDIO_USAGE_MEDIA: + case AUDIO_USAGE_GAME: + case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY: + case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: + mStreamType = AUDIO_STREAM_MUSIC; + return; + case AUDIO_USAGE_ASSISTANCE_SONIFICATION: + mStreamType = AUDIO_STREAM_SYSTEM; + return; + case AUDIO_USAGE_VOICE_COMMUNICATION: + mStreamType = AUDIO_STREAM_VOICE_CALL; + return; + + case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING: + mStreamType = AUDIO_STREAM_DTMF; + return; + + case AUDIO_USAGE_ALARM: + mStreamType = AUDIO_STREAM_ALARM; + return; + case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE: + mStreamType = AUDIO_STREAM_RING; + return; + + case AUDIO_USAGE_NOTIFICATION: + case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST: + case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT: + case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED: + case AUDIO_USAGE_NOTIFICATION_EVENT: + mStreamType = AUDIO_STREAM_NOTIFICATION; + return; + + case AUDIO_USAGE_UNKNOWN: + default: + mStreamType = AUDIO_STREAM_MUSIC; + } +} + +bool AudioTrack::isValidAttributes(const audio_attributes_t *paa) { + // has flags that map to a strategy? + if ((paa->flags & (AUDIO_FLAG_AUDIBILITY_ENFORCED | AUDIO_FLAG_SCO)) != 0) { + return true; + } + + // has known usage? + switch (paa->usage) { + case AUDIO_USAGE_UNKNOWN: + case AUDIO_USAGE_MEDIA: + case AUDIO_USAGE_VOICE_COMMUNICATION: + case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING: + case AUDIO_USAGE_ALARM: + case AUDIO_USAGE_NOTIFICATION: + case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE: + case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST: + case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT: + case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED: + case AUDIO_USAGE_NOTIFICATION_EVENT: + case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY: + case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: + case AUDIO_USAGE_ASSISTANCE_SONIFICATION: + case AUDIO_USAGE_GAME: + break; + default: + return false; + } + return true; +} // ========================================================================= void AudioTrack::DeathNotifier::binderDied(const wp& who __unused) -- cgit v1.1 From 5bd3f38638acab633d181359cc9ec27b80f84d43 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Fri, 13 Jun 2014 16:06:54 -0700 Subject: AudioPolicyManager: return output for audio attributes In AudioPolicyManager, support querying an output or playback strategy for audio attributes, instead of a stream type, In AudioTrack creation, use the output returned for the track's attributes. Change-Id: I0fef05845ba676404775e2e338c10e6a96237268 --- media/libmedia/AudioSystem.cpp | 26 ++++++++++++++++ media/libmedia/AudioTrack.cpp | 15 ++++----- media/libmedia/IAudioPolicyService.cpp | 57 +++++++++++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 15b32ff..f5e7a78 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -245,6 +245,19 @@ status_t AudioSystem::getOutputSamplingRate(uint32_t* samplingRate, audio_stream return getSamplingRate(output, samplingRate); } +status_t AudioSystem::getOutputSamplingRateForAttr(uint32_t* samplingRate, + const audio_attributes_t *attr) +{ + if (attr == NULL) { + return BAD_VALUE; + } + audio_io_handle_t output = getOutputForAttr(attr); + if (output == 0) { + return PERMISSION_DENIED; + } + return getSamplingRate(output, samplingRate); +} + status_t AudioSystem::getSamplingRate(audio_io_handle_t output, uint32_t* samplingRate) { @@ -633,6 +646,19 @@ audio_io_handle_t AudioSystem::getOutput(audio_stream_type_t stream, return aps->getOutput(stream, samplingRate, format, channelMask, flags, offloadInfo); } +audio_io_handle_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo) +{ + if (attr == NULL) return 0; + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return 0; + return aps->getOutputForAttr(attr, samplingRate, format, channelMask, flags, offloadInfo); +} + status_t AudioSystem::startOutput(audio_io_handle_t output, audio_stream_type_t stream, int session) diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 000185b..77419f0 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -287,8 +287,7 @@ status_t AudioTrack::set( status_t status; if (sampleRate == 0) { - // TODO replace with new APM method with support for audio_attributes_t - status = AudioSystem::getOutputSamplingRate(&sampleRate, mStreamType); + status = AudioSystem::getOutputSamplingRateForAttr(&sampleRate, &mAttributes); if (status != NO_ERROR) { ALOGE("Could not get output sample rate for stream type %d; status %d", mStreamType, status); @@ -641,8 +640,7 @@ status_t AudioTrack::setSampleRate(uint32_t rate) } uint32_t afSamplingRate; - // TODO replace with new APM method with support for audio_attributes_t - if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) { + if (AudioSystem::getOutputSamplingRateForAttr(&afSamplingRate, &mAttributes) != NO_ERROR) { return NO_INIT; } // Resampler implementation limits input sampling rate to 2 x output sampling rate. @@ -889,13 +887,12 @@ status_t AudioTrack::createTrack_l(size_t epoch) return NO_INIT; } - // TODO replace with new APM method with support for audio_attributes_t - audio_io_handle_t output = AudioSystem::getOutput(mStreamType, mSampleRate, mFormat, + audio_io_handle_t output = AudioSystem::getOutputForAttr(&mAttributes, mSampleRate, mFormat, mChannelMask, mFlags, mOffloadInfo); if (output == AUDIO_IO_HANDLE_NONE) { - ALOGE("Could not get audio output for stream type %d, sample rate %u, format %#x, " - "channel mask %#x, flags %#x", - mStreamType, mSampleRate, mFormat, mChannelMask, mFlags); + ALOGE("Could not get audio output for stream type %d, usage %d, sample rate %u, format %#x," + " channel mask %#x, flags %#x", + mStreamType, mAttributes.usage, mSampleRate, mFormat, mChannelMask, mFlags); return BAD_VALUE; } { diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 77d131b..41a9065 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -64,7 +64,8 @@ enum { RELEASE_AUDIO_PATCH, LIST_AUDIO_PATCHES, SET_AUDIO_PORT_CONFIG, - REGISTER_CLIENT + REGISTER_CLIENT, + GET_OUTPUT_FOR_ATTR }; class BpAudioPolicyService : public BpInterface @@ -155,6 +156,36 @@ public: return static_cast (reply.readInt32()); } + virtual audio_io_handle_t getOutputForAttr( + const audio_attributes_t *attr, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + if (attr == NULL) { + ALOGE("Writing NULL audio attributes - shouldn't happen"); + return (audio_io_handle_t) 0; + } + data.write(attr, sizeof(audio_attributes_t)); + data.writeInt32(samplingRate); + data.writeInt32(static_cast (format)); + data.writeInt32(channelMask); + data.writeInt32(static_cast (flags)); + // hasOffloadInfo + if (offloadInfo == NULL) { + data.writeInt32(0); + } else { + data.writeInt32(1); + data.write(offloadInfo, sizeof(audio_offload_info_t)); + } + remote()->transact(GET_OUTPUT_FOR_ATTR, data, &reply); + return static_cast (reply.readInt32()); + } + virtual status_t startOutput(audio_io_handle_t output, audio_stream_type_t stream, int session) @@ -614,6 +645,30 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } break; + case GET_OUTPUT_FOR_ATTR: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + audio_attributes_t *attr = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t)); + data.read(attr, sizeof(audio_attributes_t)); + uint32_t samplingRate = data.readInt32(); + audio_format_t format = (audio_format_t) data.readInt32(); + audio_channel_mask_t channelMask = data.readInt32(); + audio_output_flags_t flags = + static_cast (data.readInt32()); + bool hasOffloadInfo = data.readInt32() != 0; + audio_offload_info_t offloadInfo; + if (hasOffloadInfo) { + data.read(&offloadInfo, sizeof(audio_offload_info_t)); + } + audio_io_handle_t output = getOutputForAttr(attr, + samplingRate, + format, + channelMask, + flags, + hasOffloadInfo ? &offloadInfo : NULL); + reply->writeInt32(static_cast (output)); + return NO_ERROR; + } break; + case START_OUTPUT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_io_handle_t output = static_cast (data.readInt32()); -- cgit v1.1 From 3c1da7224155516a08d94598eb64b64204bf10f8 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 18 Jun 2014 12:29:28 -0700 Subject: AString: add startsWithIgnoreCase and endsWithIgnoreCase Change-Id: I340159aa14d4d3d28ea675c6c5b8a82f7e731069 --- media/libstagefright/foundation/AString.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'media') diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp index f2d501e..894f65c 100644 --- a/media/libstagefright/foundation/AString.cpp +++ b/media/libstagefright/foundation/AString.cpp @@ -328,6 +328,20 @@ bool AString::endsWith(const char *suffix) const { return !strcmp(mData + mSize - suffixLen, suffix); } +bool AString::startsWithIgnoreCase(const char *prefix) const { + return !strncasecmp(mData, prefix, strlen(prefix)); +} + +bool AString::endsWithIgnoreCase(const char *suffix) const { + size_t suffixLen = strlen(suffix); + + if (mSize < suffixLen) { + return false; + } + + return !strcasecmp(mData + mSize - suffixLen, suffix); +} + AString StringPrintf(const char *format, ...) { va_list ap; va_start(ap, format); -- cgit v1.1 From ab5cdbaf65ca509681d2726aacdf3ac8bfb6b3fa Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Mon, 9 Jun 2014 17:22:27 -0700 Subject: AudioTrack: add support for compressed audio Add support for compressed audio playback by use of an AudioTrack attached to a direct output thread. Bug: 9428304. Change-Id: I4a61be9cf0e31003ca85935d6e0ee38ca8192e03 --- media/libmedia/AudioTrack.cpp | 67 +++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 15 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 77419f0..5c82cfb 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -635,7 +635,7 @@ void AudioTrack::getAuxEffectSendLevel(float* level) const status_t AudioTrack::setSampleRate(uint32_t rate) { - if (mIsTimed || isOffloaded()) { + if (mIsTimed || isOffloadedOrDirect()) { return INVALID_OPERATION; } @@ -666,7 +666,7 @@ uint32_t AudioTrack::getSampleRate() const // sample rate can be updated during playback by the offloaded decoder so we need to // query the HAL and update if needed. // FIXME use Proxy return channel to update the rate from server and avoid polling here - if (isOffloaded_l()) { + if (isOffloadedOrDirect_l()) { if (mOutput != AUDIO_IO_HANDLE_NONE) { uint32_t sampleRate = 0; status_t status = AudioSystem::getSamplingRate(mOutput, &sampleRate); @@ -680,7 +680,7 @@ uint32_t AudioTrack::getSampleRate() const status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount) { - if (mSharedBuffer == 0 || mIsTimed || isOffloaded()) { + if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) { return INVALID_OPERATION; } @@ -714,7 +714,7 @@ void AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount) status_t AudioTrack::setMarkerPosition(uint32_t marker) { // The only purpose of setting marker position is to get a callback - if (mCbf == NULL || isOffloaded()) { + if (mCbf == NULL || isOffloadedOrDirect()) { return INVALID_OPERATION; } @@ -727,7 +727,7 @@ status_t AudioTrack::setMarkerPosition(uint32_t marker) status_t AudioTrack::getMarkerPosition(uint32_t *marker) const { - if (isOffloaded()) { + if (isOffloadedOrDirect()) { return INVALID_OPERATION; } if (marker == NULL) { @@ -743,7 +743,7 @@ status_t AudioTrack::getMarkerPosition(uint32_t *marker) const status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod) { // The only purpose of setting position update period is to get a callback - if (mCbf == NULL || isOffloaded()) { + if (mCbf == NULL || isOffloadedOrDirect()) { return INVALID_OPERATION; } @@ -756,7 +756,7 @@ status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod) status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) const { - if (isOffloaded()) { + if (isOffloadedOrDirect()) { return INVALID_OPERATION; } if (updatePeriod == NULL) { @@ -771,7 +771,7 @@ status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) const status_t AudioTrack::setPosition(uint32_t position) { - if (mSharedBuffer == 0 || mIsTimed || isOffloaded()) { + if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) { return INVALID_OPERATION; } if (position > mFrameCount) { @@ -804,10 +804,10 @@ status_t AudioTrack::getPosition(uint32_t *position) const } AutoMutex lock(mLock); - if (isOffloaded_l()) { + if (isOffloadedOrDirect_l()) { uint32_t dspFrames = 0; - if ((mState == STATE_PAUSED) || (mState == STATE_PAUSED_STOPPING)) { + if (isOffloaded_l() && ((mState == STATE_PAUSED) || (mState == STATE_PAUSED_STOPPING))) { ALOGV("getPosition called in paused state, return cached position %u", mPausedPosition); *position = mPausedPosition; return NO_ERROR; @@ -842,7 +842,7 @@ status_t AudioTrack::getBufferPosition(uint32_t *position) status_t AudioTrack::reload() { - if (mSharedBuffer == 0 || mIsTimed || isOffloaded()) { + if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) { return INVALID_OPERATION; } @@ -1038,6 +1038,10 @@ status_t AudioTrack::createTrack_l(size_t epoch) trackFlags |= IAudioFlinger::TRACK_OFFLOAD; } + if (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) { + trackFlags |= IAudioFlinger::TRACK_DIRECT; + } + size_t temp = frameCount; // temp may be replaced by a revised value of frameCount, // but we will still need the original value also sp track = audioFlinger->createTrack(mStreamType, @@ -1129,6 +1133,16 @@ status_t AudioTrack::createTrack_l(size_t epoch) //return NO_INIT; } } + if (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) { + if (trackFlags & IAudioFlinger::TRACK_DIRECT) { + ALOGV("AUDIO_OUTPUT_FLAG_DIRECT successful"); + } else { + ALOGW("AUDIO_OUTPUT_FLAG_DIRECT denied by server"); + mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_DIRECT); + // FIXME This is a warning, not an error, so don't return error status + //return NO_INIT; + } + } // We retain a copy of the I/O handle, but don't own the reference mOutput = output; @@ -1324,6 +1338,16 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking) return INVALID_OPERATION; } + if (isDirect()) { + AutoMutex lock(mLock); + int32_t flags = android_atomic_and( + ~(CBLK_UNDERRUN | CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL | CBLK_BUFFER_END), + &mCblk->mFlags); + if (flags & CBLK_INVALID) { + return DEAD_OBJECT; + } + } + if (ssize_t(userSize) < 0 || (buffer == NULL && userSize != 0)) { // Sanity-check: user is most-likely passing an error code, and it would // make the return value ambiguous (actualSize vs error). @@ -1472,7 +1496,7 @@ nsecs_t AudioTrack::processAudioBuffer() // for offloaded tracks restoreTrack_l() will just update the sequence and clear // AudioSystem cache. We should not exit here but after calling the callback so // that the upper layers can recreate the track - if (!isOffloaded_l() || (mSequence == mObservedSequence)) { + if (!isOffloadedOrDirect_l() || (mSequence == mObservedSequence)) { status_t status = restoreTrack_l("processAudioBuffer"); mLock.unlock(); // Run again immediately, but with a new IAudioTrack @@ -1598,7 +1622,7 @@ nsecs_t AudioTrack::processAudioBuffer() mObservedSequence = sequence; mCbf(EVENT_NEW_IAUDIOTRACK, mUserData, NULL); // for offloaded tracks, just wait for the upper layers to recreate the track - if (isOffloaded()) { + if (isOffloadedOrDirect()) { return NS_INACTIVE; } } @@ -1756,7 +1780,7 @@ nsecs_t AudioTrack::processAudioBuffer() status_t AudioTrack::restoreTrack_l(const char *from) { ALOGW("dead IAudioTrack, %s, creating a new one from %s()", - isOffloaded_l() ? "Offloaded" : "PCM", from); + isOffloadedOrDirect_l() ? "Offloaded or Direct" : "PCM", from); ++mSequence; status_t result; @@ -1764,7 +1788,7 @@ status_t AudioTrack::restoreTrack_l(const char *from) // output parameters in createTrack_l() AudioSystem::clearAudioConfigCache(); - if (isOffloaded_l()) { + if (isOffloadedOrDirect_l()) { // FIXME re-creation of offloaded tracks is not yet implemented return DEAD_OBJECT; } @@ -1850,6 +1874,19 @@ bool AudioTrack::isOffloaded() const return isOffloaded_l(); } +bool AudioTrack::isDirect() const +{ + AutoMutex lock(mLock); + return isDirect_l(); +} + +bool AudioTrack::isOffloadedOrDirect() const +{ + AutoMutex lock(mLock); + return isOffloadedOrDirect_l(); +} + + status_t AudioTrack::dump(int fd, const Vector& args __unused) const { -- cgit v1.1 From 2f46e8152fb881d3a1d7afd223f1ed51f6e358b8 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 12 Jun 2014 12:08:56 -0700 Subject: MatroskaExtractor: track specific seeking Divide cues based on tracks to support track specific seeking. Bug: 15595215 Change-Id: Ibb853b0955c62af72243ed29253f939d07628ae4 --- media/libstagefright/Android.mk | 1 + .../libstagefright/matroska/MatroskaExtractor.cpp | 110 ++++++++++++++++----- media/libstagefright/matroska/MatroskaExtractor.h | 11 ++- 3 files changed, 96 insertions(+), 26 deletions(-) (limited to 'media') diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index d9e39ff..11c5970 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -68,6 +68,7 @@ LOCAL_C_INCLUDES:= \ $(TOP)/external/flac/include \ $(TOP)/external/tremolo \ $(TOP)/external/openssl/include \ + $(TOP)/external/libvpx/libwebm \ LOCAL_SHARED_LIBRARIES := \ libbinder \ diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index d7bec59..2587ec7 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -20,8 +20,6 @@ #include "MatroskaExtractor.h" -#include "mkvparser.hpp" - #include #include #include @@ -89,7 +87,7 @@ private: //////////////////////////////////////////////////////////////////////////////// struct BlockIterator { - BlockIterator(MatroskaExtractor *extractor, unsigned long trackNum); + BlockIterator(MatroskaExtractor *extractor, unsigned long trackNum, unsigned long index); bool eos() const; @@ -106,6 +104,7 @@ struct BlockIterator { private: MatroskaExtractor *mExtractor; long long mTrackNum; + unsigned long mIndex; const mkvparser::Cluster *mCluster; const mkvparser::BlockEntry *mBlockEntry; @@ -157,6 +156,53 @@ private: MatroskaSource &operator=(const MatroskaSource &); }; +const mkvparser::Track* MatroskaExtractor::TrackInfo::getTrack() const { + return mExtractor->mSegment->GetTracks()->GetTrackByNumber(mTrackNum); +} + +// This function does exactly the same as mkvparser::Cues::Find, except that it +// searches in our own track based vectors. We should not need this once mkvparser +// adds the same functionality. +const mkvparser::CuePoint::TrackPosition *MatroskaExtractor::TrackInfo::find( + long long timeNs) const { + ALOGV("mCuePoints.size %zu", mCuePoints.size()); + if (mCuePoints.empty()) { + return NULL; + } + + const mkvparser::CuePoint* cp = mCuePoints.itemAt(0); + const mkvparser::Track* track = getTrack(); + if (timeNs <= cp->GetTime(mExtractor->mSegment)) { + return cp->Find(track); + } + + // Binary searches through relevant cues; assumes cues are ordered by timecode. + // If we do detect out-of-order cues, return NULL. + size_t lo = 0; + size_t hi = mCuePoints.size(); + while (lo < hi) { + const size_t mid = lo + (hi - lo) / 2; + const mkvparser::CuePoint* const midCp = mCuePoints.itemAt(mid); + const long long cueTimeNs = midCp->GetTime(mExtractor->mSegment); + if (cueTimeNs <= timeNs) { + lo = mid + 1; + } else { + hi = mid; + } + } + + if (lo == 0) { + return NULL; + } + + cp = mCuePoints.itemAt(lo - 1); + if (cp->GetTime(mExtractor->mSegment) > timeNs) { + return NULL; + } + + return cp->Find(track); +} + MatroskaSource::MatroskaSource( const sp &extractor, size_t index) : mExtractor(extractor), @@ -164,7 +210,8 @@ MatroskaSource::MatroskaSource( mType(OTHER), mIsAudio(false), mBlockIter(mExtractor.get(), - mExtractor->mTracks.itemAt(index).mTrackNum), + mExtractor->mTracks.itemAt(index).mTrackNum, + index), mNALSizeLen(0) { sp meta = mExtractor->mTracks.itemAt(index).mMeta; @@ -214,9 +261,10 @@ sp MatroskaSource::getFormat() { //////////////////////////////////////////////////////////////////////////////// BlockIterator::BlockIterator( - MatroskaExtractor *extractor, unsigned long trackNum) + MatroskaExtractor *extractor, unsigned long trackNum, unsigned long index) : mExtractor(extractor), mTrackNum(trackNum), + mIndex(index), mCluster(NULL), mBlockEntry(NULL), mBlockEntryIndex(0) { @@ -364,9 +412,20 @@ void BlockIterator::seek( } const mkvparser::CuePoint* pCP; + mkvparser::Tracks const *pTracks = pSegment->GetTracks(); + unsigned long int trackCount = pTracks->GetTracksCount(); while (!pCues->DoneParsing()) { pCues->LoadCuePoint(); pCP = pCues->GetLast(); + CHECK(pCP); + + for (size_t index = 0; index < trackCount; ++index) { + const mkvparser::Track *pTrack = pTracks->GetTrackByIndex(index); + if (pTrack && pTrack->GetType() == 1 && pCP->Find(pTrack)) { // VIDEO_TRACK + MatroskaExtractor::TrackInfo& track = mExtractor->mTracks.editItemAt(index); + track.mCuePoints.push_back(pCP); + } + } if (pCP->GetTime(pSegment) >= seekTimeNs) { ALOGV("Parsed past relevant Cue"); @@ -374,22 +433,25 @@ void BlockIterator::seek( } } - // The Cue index is built around video keyframes - mkvparser::Tracks const *pTracks = pSegment->GetTracks(); - const mkvparser::Track *pTrack = NULL; - for (size_t index = 0; index < pTracks->GetTracksCount(); ++index) { - pTrack = pTracks->GetTrackByIndex(index); - if (pTrack && pTrack->GetType() == 1) { // VIDEO_TRACK - ALOGV("Video track located at %zu", index); - break; + const mkvparser::CuePoint::TrackPosition *pTP = NULL; + const mkvparser::Track *thisTrack = pTracks->GetTrackByIndex(mIndex); + if (thisTrack->GetType() == 1) { // video + MatroskaExtractor::TrackInfo& track = mExtractor->mTracks.editItemAt(mIndex); + pTP = track.find(seekTimeNs); + } else { + // The Cue index is built around video keyframes + for (size_t index = 0; index < trackCount; ++index) { + const mkvparser::Track *pTrack = pTracks->GetTrackByIndex(index); + if (pTrack && pTrack->GetType() == 1 && pCues->Find(seekTimeNs, pTrack, pCP, pTP)) { + ALOGV("Video track located at %zu", index); + break; + } } } + // Always *search* based on the video track, but finalize based on mTrackNum - const mkvparser::CuePoint::TrackPosition* pTP; - if (pTrack && pTrack->GetType() == 1) { - pCues->Find(seekTimeNs, pTrack, pCP, pTP); - } else { + if (!pTP) { ALOGE("Did not locate the video track for seeking"); return; } @@ -410,10 +472,13 @@ void BlockIterator::seek( if (isAudio || block()->IsKey()) { // Accept the first key frame - *actualFrameTimeUs = (block()->GetTime(mCluster) + 500LL) / 1000LL; - ALOGV("Requested seek point: %" PRId64 " actual: %" PRId64, - seekTimeUs, *actualFrameTimeUs); - break; + int64_t frameTimeUs = (block()->GetTime(mCluster) + 500LL) / 1000LL; + if (thisTrack->GetType() == 1 || frameTimeUs >= seekTimeUs) { + *actualFrameTimeUs = frameTimeUs; + ALOGV("Requested seek point: %" PRId64 " actual: %" PRId64, + seekTimeUs, *actualFrameTimeUs); + break; + } } } } @@ -964,6 +1029,7 @@ void MatroskaExtractor::addTracks() { TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1); trackInfo->mTrackNum = track->GetNumber(); trackInfo->mMeta = meta; + trackInfo->mExtractor = this; } } @@ -978,7 +1044,7 @@ void MatroskaExtractor::findThumbnails() { continue; } - BlockIterator iter(this, info->mTrackNum); + BlockIterator iter(this, info->mTrackNum, i); int32_t j = 0; int64_t thumbnailTimeUs = 0; size_t maxBlockSize = 0; diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h index cf200f3..db36bf8 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.h +++ b/media/libstagefright/matroska/MatroskaExtractor.h @@ -18,14 +18,12 @@ #define MATROSKA_EXTRACTOR_H_ +#include "mkvparser.hpp" + #include #include #include -namespace mkvparser { -struct Segment; -}; - namespace android { struct AMessage; @@ -58,6 +56,11 @@ private: struct TrackInfo { unsigned long mTrackNum; sp mMeta; + const MatroskaExtractor *mExtractor; + Vector mCuePoints; + + const mkvparser::Track* getTrack() const; + const mkvparser::CuePoint::TrackPosition *find(long long timeNs) const; }; Mutex mLock; -- cgit v1.1 From 34fb29696b0f3abf61b10f8d053b1f33d501de0a Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 18 Jun 2014 16:30:56 -0700 Subject: libmedia: 64-bit compile warnings Change-Id: I600f062fa7148c01851023c1240c39939e648002 --- media/libmedia/AudioRecord.cpp | 22 +++++++++++---------- media/libmedia/AudioSystem.cpp | 6 +++--- media/libmedia/AudioTrack.cpp | 29 ++++++++++++++-------------- media/libmedia/AudioTrackShared.cpp | 12 ++++++------ media/libmedia/CharacterEncodingDetector.cpp | 10 +++++----- media/libmedia/IMediaMetadataRetriever.cpp | 6 ++++-- media/libmedia/IMediaRecorder.cpp | 8 +++++--- media/libmedia/MediaProfiles.cpp | 6 +++--- media/libmedia/SoundPool.cpp | 10 +++++++--- media/libmedia/mediametadataretriever.cpp | 6 ++++-- media/libmedia/mediaplayer.cpp | 14 ++++++++------ media/libmedia/mediarecorder.cpp | 5 ++++- 12 files changed, 76 insertions(+), 58 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 50b444a..f865d38 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -18,7 +18,9 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "AudioRecord" +#include #include + #include #include #include @@ -468,7 +470,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) if (frameCount == 0) { frameCount = minFrameCount; } else if (frameCount < minFrameCount) { - ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount); + ALOGE("frameCount %zu < minFrameCount %zu", frameCount, minFrameCount); return BAD_VALUE; } @@ -555,17 +557,17 @@ status_t AudioRecord::openRecord_l(size_t epoch) mCblk = cblk; // note that temp is the (possibly revised) value of frameCount if (temp < frameCount || (frameCount == 0 && temp == 0)) { - ALOGW("Requested frameCount %u but received frameCount %u", frameCount, temp); + ALOGW("Requested frameCount %zu but received frameCount %zu", frameCount, temp); } frameCount = temp; mAwaitBoost = false; if (mFlags & AUDIO_INPUT_FLAG_FAST) { if (trackFlags & IAudioFlinger::TRACK_FAST) { - ALOGV("AUDIO_INPUT_FLAG_FAST successful; frameCount %u", frameCount); + ALOGV("AUDIO_INPUT_FLAG_FAST successful; frameCount %zu", frameCount); mAwaitBoost = true; } else { - ALOGV("AUDIO_INPUT_FLAG_FAST denied by server; frameCount %u", frameCount); + ALOGV("AUDIO_INPUT_FLAG_FAST denied by server; frameCount %zu", frameCount); // once denied, do not request again if IAudioRecord is re-created mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST); } @@ -740,7 +742,7 @@ ssize_t AudioRecord::read(void* buffer, size_t userSize) if (ssize_t(userSize) < 0 || (buffer == NULL && userSize != 0)) { // sanity-check. user is most-likely passing an error code, and it would // make the return value ambiguous (actualSize vs error). - ALOGE("AudioRecord::read(buffer=%p, size=%u (%d)", buffer, userSize, userSize); + ALOGE("AudioRecord::read(buffer=%p, size=%zu (%zu)", buffer, userSize, userSize); return BAD_VALUE; } @@ -921,10 +923,10 @@ nsecs_t AudioRecord::processAudioBuffer() size_t nonContig; status_t err = obtainBuffer(&audioBuffer, requested, NULL, &nonContig); LOG_ALWAYS_FATAL_IF((err != NO_ERROR) != (audioBuffer.frameCount == 0), - "obtainBuffer() err=%d frameCount=%u", err, audioBuffer.frameCount); + "obtainBuffer() err=%d frameCount=%zu", err, audioBuffer.frameCount); requested = &ClientProxy::kNonBlocking; size_t avail = audioBuffer.frameCount + nonContig; - ALOGV("obtainBuffer(%u) returned %u = %u + %u err %d", + ALOGV("obtainBuffer(%u) returned %zu = %zu + %zu err %d", mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err); if (err != NO_ERROR) { if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR) { @@ -952,8 +954,8 @@ nsecs_t AudioRecord::processAudioBuffer() // Sanity check on returned size if (ssize_t(readSize) < 0 || readSize > reqSize) { - ALOGE("EVENT_MORE_DATA requested %u bytes but callback returned %d bytes", - reqSize, (int) readSize); + ALOGE("EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes", + reqSize, ssize_t(readSize)); return NS_NEVER; } @@ -1092,7 +1094,7 @@ bool AudioRecord::AudioRecordThread::threadLoop() ns = 1000000000LL; // fall through default: - LOG_ALWAYS_FATAL_IF(ns < 0, "processAudioBuffer() returned %lld", ns); + LOG_ALWAYS_FATAL_IF(ns < 0, "processAudioBuffer() returned %" PRId64, ns); pauseInternal(ns); return true; } diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index f5e7a78..a47d45c 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -323,7 +323,7 @@ status_t AudioSystem::getFrameCount(audio_io_handle_t output, return BAD_VALUE; } - ALOGV("getFrameCount() output %d, frameCount %d", output, *frameCount); + ALOGV("getFrameCount() output %d, frameCount %zu", output, *frameCount); return NO_ERROR; } @@ -489,7 +489,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle OutputDescriptor *outputDesc = new OutputDescriptor(*desc); gOutputs.add(ioHandle, outputDesc); - ALOGV("ioConfigChanged() new output samplingRate %u, format %#x channel mask %#x frameCount %u " + ALOGV("ioConfigChanged() new output samplingRate %u, format %#x channel mask %#x frameCount %zu " "latency %d", outputDesc->samplingRate, outputDesc->format, outputDesc->channelMask, outputDesc->frameCount, outputDesc->latency); @@ -514,7 +514,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle desc = (const OutputDescriptor *)param2; ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %#x channel mask %#x " - "frameCount %d latency %d", + "frameCount %zu latency %d", ioHandle, desc->samplingRate, desc->format, desc->channelMask, desc->frameCount, desc->latency); OutputDescriptor *outputDesc = gOutputs.valueAt(index); diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 5c82cfb..898d58d 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -15,12 +15,13 @@ ** limitations under the License. */ - //#define LOG_NDEBUG 0 #define LOG_TAG "AudioTrack" +#include #include #include + #include #include #include @@ -89,7 +90,7 @@ status_t AudioTrack::getMinFrameCount( streamType, sampleRate); return BAD_VALUE; } - ALOGV("getMinFrameCount=%d: afFrameCount=%d, minBufCount=%d, afSampleRate=%d, afLatency=%d", + ALOGV("getMinFrameCount=%zu: afFrameCount=%zu, minBufCount=%d, afSampleRate=%d, afLatency=%d", *frameCount, afFrameCount, minBufCount, afSampleRate, afLatency); return NO_ERROR; } @@ -250,7 +251,7 @@ status_t AudioTrack::set( ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); - ALOGV("set() streamType %d frameCount %u flags %04x", streamType, frameCount, flags); + ALOGV("set() streamType %d frameCount %zu flags %04x", streamType, frameCount, flags); AutoMutex lock(mLock); @@ -993,14 +994,14 @@ status_t AudioTrack::createTrack_l(size_t epoch) // Ensure that buffer depth covers at least audio hardware latency uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate); - ALOGV("afFrameCount=%d, minBufCount=%d, afSampleRate=%u, afLatency=%d", + ALOGV("afFrameCount=%zu, minBufCount=%d, afSampleRate=%u, afLatency=%d", afFrameCount, minBufCount, afSampleRate, afLatency); if (minBufCount <= nBuffering) { minBufCount = nBuffering; } size_t minFrameCount = (afFrameCount*mSampleRate*minBufCount)/afSampleRate; - ALOGV("minFrameCount: %u, afFrameCount=%d, minBufCount=%d, sampleRate=%u, afSampleRate=%u" + ALOGV("minFrameCount: %zu, afFrameCount=%zu, minBufCount=%d, sampleRate=%u, afSampleRate=%u" ", afLatency=%d", minFrameCount, afFrameCount, minBufCount, mSampleRate, afSampleRate, afLatency); @@ -1008,7 +1009,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) frameCount = minFrameCount; } else if (frameCount < minFrameCount) { // not ALOGW because it happens all the time when playing key clicks over A2DP - ALOGV("Minimum buffer size corrected from %d to %d", + ALOGV("Minimum buffer size corrected from %zu to %zu", frameCount, minFrameCount); frameCount = minFrameCount; } @@ -1095,14 +1096,14 @@ status_t AudioTrack::createTrack_l(size_t epoch) // In current design, AudioTrack client checks and ensures frame count validity before // passing it to AudioFlinger so AudioFlinger should not return a different value except // for fast track as it uses a special method of assigning frame count. - ALOGW("Requested frameCount %u but received frameCount %u", frameCount, temp); + ALOGW("Requested frameCount %zu but received frameCount %zu", frameCount, temp); } frameCount = temp; mAwaitBoost = false; if (mFlags & AUDIO_OUTPUT_FLAG_FAST) { if (trackFlags & IAudioFlinger::TRACK_FAST) { - ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %u", frameCount); + ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu", frameCount); mAwaitBoost = true; if (mSharedBuffer == 0) { // Theoretically double-buffering is not required for fast tracks, @@ -1113,7 +1114,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) } } } else { - ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %u", frameCount); + ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu", frameCount); // once denied, do not request again if IAudioTrack is re-created mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST); if (mSharedBuffer == 0) { @@ -1680,10 +1681,10 @@ nsecs_t AudioTrack::processAudioBuffer() size_t nonContig; status_t err = obtainBuffer(&audioBuffer, requested, NULL, &nonContig); LOG_ALWAYS_FATAL_IF((err != NO_ERROR) != (audioBuffer.frameCount == 0), - "obtainBuffer() err=%d frameCount=%u", err, audioBuffer.frameCount); + "obtainBuffer() err=%d frameCount=%zu", err, audioBuffer.frameCount); requested = &ClientProxy::kNonBlocking; size_t avail = audioBuffer.frameCount + nonContig; - ALOGV("obtainBuffer(%u) returned %u = %u + %u err %d", + ALOGV("obtainBuffer(%u) returned %zu = %zu + %zu err %d", mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err); if (err != NO_ERROR) { if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR || @@ -1718,8 +1719,8 @@ nsecs_t AudioTrack::processAudioBuffer() // Sanity check on returned size if (ssize_t(writtenSize) < 0 || writtenSize > reqSize) { - ALOGE("EVENT_MORE_DATA requested %u bytes but callback returned %d bytes", - reqSize, (int) writtenSize); + ALOGE("EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes", + reqSize, ssize_t(writtenSize)); return NS_NEVER; } @@ -2105,7 +2106,7 @@ bool AudioTrack::AudioTrackThread::threadLoop() ns = 1000000000LL; // fall through default: - LOG_ALWAYS_FATAL_IF(ns < 0, "processAudioBuffer() returned %lld", ns); + LOG_ALWAYS_FATAL_IF(ns < 0, "processAudioBuffer() returned %" PRId64, ns); pauseInternal(ns); return true; } diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index 0dbfa62..eec025e 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -135,7 +135,7 @@ status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *reques // pipe should not be overfull if (!(0 <= filled && (size_t) filled <= mFrameCount)) { if (mIsOut) { - ALOGE("Shared memory control block is corrupt (filled=%d, mFrameCount=%u); " + ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); " "shutting down", filled, mFrameCount); mIsShutdown = true; status = NO_INIT; @@ -338,7 +338,7 @@ size_t ClientProxy::getFramesFilled() { ssize_t filled = rear - front; // pipe should not be overfull if (!(0 <= filled && (size_t) filled <= mFrameCount)) { - ALOGE("Shared memory control block is corrupt (filled=%d); shutting down", filled); + ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled); return 0; } return (size_t)filled; @@ -555,7 +555,7 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush) ssize_t filled = rear - front; // pipe should not already be overfull if (!(0 <= filled && (size_t) filled <= mFrameCount)) { - ALOGE("Shared memory control block is corrupt (filled=%d); shutting down", filled); + ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled); mIsShutdown = true; } if (mIsShutdown) { @@ -642,7 +642,7 @@ void ServerProxy::releaseBuffer(Buffer* buffer) } // FIXME AudioRecord wakeup needs to be optimized; it currently wakes up client every time if (!mIsOut || (mAvailToClient + stepCount >= minimum)) { - ALOGV("mAvailToClient=%u stepCount=%u minimum=%u", mAvailToClient, stepCount, minimum); + ALOGV("mAvailToClient=%zu stepCount=%zu minimum=%zu", mAvailToClient, stepCount, minimum); int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex); if (!(old & CBLK_FUTEX_WAKE)) { (void) syscall(__NR_futex, &cblk->mFutex, @@ -675,7 +675,7 @@ size_t AudioTrackServerProxy::framesReady() ssize_t filled = rear - cblk->u.mStreaming.mFront; // pipe should not already be overfull if (!(0 <= filled && (size_t) filled <= mFrameCount)) { - ALOGE("Shared memory control block is corrupt (filled=%d); shutting down", filled); + ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled); mIsShutdown = true; return 0; } @@ -834,7 +834,7 @@ void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer) size_t newPosition = position + stepCount; int32_t setFlags = 0; if (!(position <= newPosition && newPosition <= mFrameCount)) { - ALOGW("%s newPosition %u outside [%u, %u]", __func__, newPosition, position, mFrameCount); + ALOGW("%s newPosition %zu outside [%zu, %zu]", __func__, newPosition, position, mFrameCount); newPosition = mFrameCount; } else if (mState.mLoopCount != 0 && newPosition == mState.mLoopEnd) { if (mState.mLoopCount == -1 || --mState.mLoopCount != 0) { diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp index 4992798..7d1ddfd 100644 --- a/media/libmedia/CharacterEncodingDetector.cpp +++ b/media/libmedia/CharacterEncodingDetector.cpp @@ -112,7 +112,7 @@ void CharacterEncodingDetector::detectAndConvert() { if (allprintable) { // since 'buf' is empty, ICU would return a UTF-8 matcher with low confidence, so // no need to even call it - ALOGV("all tags are printable, assuming ascii (%d)", strlen(buf)); + ALOGV("all tags are printable, assuming ascii (%zu)", strlen(buf)); } else { ucsdet_setText(csd, buf, strlen(buf), &status); int32_t matches; @@ -267,11 +267,11 @@ const UCharsetMatch *CharacterEncodingDetector::getPreferred( Vector matches; UErrorCode status = U_ZERO_ERROR; - ALOGV("%d matches", nummatches); + ALOGV("%zu matches", nummatches); for (size_t i = 0; i < nummatches; i++) { const char *encname = ucsdet_getName(ucma[i], &status); int confidence = ucsdet_getConfidence(ucma[i], &status); - ALOGV("%d: %s %d", i, encname, confidence); + ALOGV("%zu: %s %d", i, encname, confidence); matches.push_back(ucma[i]); } @@ -287,7 +287,7 @@ const UCharsetMatch *CharacterEncodingDetector::getPreferred( return matches[0]; } - ALOGV("considering %d matches", num); + ALOGV("considering %zu matches", num); // keep track of how many "special" characters result when converting the input using each // encoding @@ -315,7 +315,7 @@ const UCharsetMatch *CharacterEncodingDetector::getPreferred( freqcoverage = frequent_ja_coverage; } - ALOGV("%d: %s %d", i, encname, confidence); + ALOGV("%zu: %s %d", i, encname, confidence); UConverter *conv = ucnv_open(encname, &status); const char *source = input; const char *sourceLimit = input + len; diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp index 432d890..38f717c 100644 --- a/media/libmedia/IMediaMetadataRetriever.cpp +++ b/media/libmedia/IMediaMetadataRetriever.cpp @@ -15,8 +15,10 @@ ** limitations under the License. */ +#include #include #include + #include #include #include @@ -125,7 +127,7 @@ public: sp getFrameAtTime(int64_t timeUs, int option) { - ALOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option); + ALOGV("getTimeAtTime: time(%" PRId64 " us) and option(%d)", timeUs, option); Parcel data, reply; data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); data.writeInt64(timeUs); @@ -237,7 +239,7 @@ status_t BnMediaMetadataRetriever::onTransact( CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); int64_t timeUs = data.readInt64(); int option = data.readInt32(); - ALOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option); + ALOGV("getTimeAtTime: time(%" PRId64 " us) and option(%d)", timeUs, option); #ifndef DISABLE_GROUP_SCHEDULE_HACK setSchedPolicy(data); #endif diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp index 8e58162..95af006 100644 --- a/media/libmedia/IMediaRecorder.cpp +++ b/media/libmedia/IMediaRecorder.cpp @@ -17,6 +17,10 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "IMediaRecorder" + +#include +#include + #include #include #include @@ -24,8 +28,6 @@ #include #include #include -#include - namespace android { @@ -167,7 +169,7 @@ public: } status_t setOutputFile(int fd, int64_t offset, int64_t length) { - ALOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length); + ALOGV("setOutputFile(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeFileDescriptor(fd); diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp index 28238c4..e9e453b 100644 --- a/media/libmedia/MediaProfiles.cpp +++ b/media/libmedia/MediaProfiles.cpp @@ -475,7 +475,7 @@ static bool isTimelapseProfile(camcorder_quality quality) { } void MediaProfiles::initRequiredProfileRefs(const Vector& cameraIds) { - ALOGV("Number of camera ids: %d", cameraIds.size()); + ALOGV("Number of camera ids: %zu", cameraIds.size()); CHECK(cameraIds.size() > 0); mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()]; for (size_t i = 0, n = cameraIds.size(); i < n; ++i) { @@ -602,14 +602,14 @@ void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() { int index = getCamcorderProfileIndex(cameraId, profile->mQuality); if (index != -1) { - ALOGV("Profile quality %d for camera %d already exists", + ALOGV("Profile quality %d for camera %zu already exists", profile->mQuality, cameraId); CHECK(index == refIndex); continue; } // Insert the new profile - ALOGV("Add a profile: quality %d=>%d for camera %d", + ALOGV("Add a profile: quality %d=>%d for camera %zu", mCamcorderProfiles[info->mRefProfileIndex]->mQuality, profile->mQuality, cameraId); diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp index a55e09c..2aa0592 100644 --- a/media/libmedia/SoundPool.cpp +++ b/media/libmedia/SoundPool.cpp @@ -16,6 +16,9 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "SoundPool" + +#include + #include #define USE_SHARED_MEM_BUFFER @@ -212,7 +215,7 @@ int SoundPool::load(const char* path, int priority __unused) int SoundPool::load(int fd, int64_t offset, int64_t length, int priority __unused) { - ALOGV("load: fd=%d, offset=%lld, length=%lld, priority=%d", + ALOGV("load: fd=%d, offset=%" PRId64 ", length=%" PRId64 ", priority=%d", fd, offset, length, priority); Mutex::Autolock lock(&mLock); sp sample = new Sample(++mNextSampleID, fd, offset, length); @@ -462,7 +465,8 @@ Sample::Sample(int sampleID, int fd, int64_t offset, int64_t length) mFd = dup(fd); mOffset = offset; mLength = length; - ALOGV("create sampleID=%d, fd=%d, offset=%lld, length=%lld", mSampleID, mFd, mLength, mOffset); + ALOGV("create sampleID=%d, fd=%d, offset=%" PRId64 " length=%" PRId64, + mSampleID, mFd, mLength, mOffset); } void Sample::init() @@ -516,7 +520,7 @@ status_t Sample::doLoad() ALOGE("Unable to load sample: %s", mUrl); goto error; } - ALOGV("pointer = %p, size = %u, sampleRate = %u, numChannels = %d", + ALOGV("pointer = %p, size = %zu, sampleRate = %u, numChannels = %d", mHeap->getBase(), mSize, sampleRate, numChannels); if (sampleRate > kMaxSampleRate) { diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp index 1d6bb6f..39a239d 100644 --- a/media/libmedia/mediametadataretriever.cpp +++ b/media/libmedia/mediametadataretriever.cpp @@ -18,6 +18,8 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaMetadataRetriever" +#include + #include #include #include @@ -114,7 +116,7 @@ status_t MediaMetadataRetriever::setDataSource( status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length) { - ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); + ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length); Mutex::Autolock _l(mLock); if (mRetriever == 0) { ALOGE("retriever is not initialized"); @@ -129,7 +131,7 @@ status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t l sp MediaMetadataRetriever::getFrameAtTime(int64_t timeUs, int option) { - ALOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option); + ALOGV("getFrameAtTime: time(%" PRId64 " us) option(%d)", timeUs, option); Mutex::Autolock _l(mLock); if (mRetriever == 0) { ALOGE("retriever is not initialized"); diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 0be01a9..406f9f2 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -17,12 +17,14 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaPlayer" -#include -#include +#include +#include #include +#include #include -#include + +#include #include #include @@ -157,7 +159,7 @@ status_t MediaPlayer::setDataSource( status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length) { - ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); + ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length); status_t err = UNKNOWN_ERROR; const sp& service(getMediaPlayerService()); if (service != 0) { @@ -194,7 +196,7 @@ status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply) (mCurrentState != MEDIA_PLAYER_STATE_ERROR) && ((mCurrentState & MEDIA_PLAYER_IDLE) != MEDIA_PLAYER_IDLE); if ((mPlayer != NULL) && hasBeenInitialized) { - ALOGV("invoke %d", request.dataSize()); + ALOGV("invoke %zu", request.dataSize()); return mPlayer->invoke(request, reply); } ALOGE("invoke failed: wrong state %X", mCurrentState); @@ -818,7 +820,7 @@ void MediaPlayer::died() audio_format_t* pFormat, const sp& heap, size_t *pSize) { - ALOGV("decode(%d, %lld, %lld)", fd, offset, length); + ALOGV("decode(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length); status_t status; const sp& service = getMediaPlayerService(); if (service != 0) { diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp index 3710e46..c8192e9 100644 --- a/media/libmedia/mediarecorder.cpp +++ b/media/libmedia/mediarecorder.cpp @@ -17,6 +17,9 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaRecorder" + +#include + #include #include #include @@ -286,7 +289,7 @@ status_t MediaRecorder::setOutputFile(const char* path) status_t MediaRecorder::setOutputFile(int fd, int64_t offset, int64_t length) { - ALOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length); + ALOGV("setOutputFile(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length); if (mMediaRecorder == NULL) { ALOGE("media recorder is not initialized yet"); return INVALID_OPERATION; -- cgit v1.1 From 77342f72fdf96603938a95fcbb9888ec90e71e68 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 18 Jun 2014 16:31:32 -0700 Subject: libmediaplayerservice: 64-bit compile warnings Change-Id: I333e52dc377becc774f3fa971c230ecb55ea8d7b --- media/libmediaplayerservice/MediaPlayerService.cpp | 14 +++++++------- media/libmediaplayerservice/MetadataRetrieverClient.cpp | 4 ++-- media/libmediaplayerservice/MidiFile.cpp | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 778eb9a..76632a7 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -307,7 +307,7 @@ sp MediaPlayerService::listenForRemoteDisplay( return new RemoteDisplay(client, iface.string()); } -status_t MediaPlayerService::AudioCache::dump(int fd, const Vector& args) const +status_t MediaPlayerService::AudioCache::dump(int fd, const Vector& /*args*/) const { const size_t SIZE = 256; char buffer[SIZE]; @@ -673,8 +673,8 @@ status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64 ALOGV("st_dev = %llu", sb.st_dev); ALOGV("st_mode = %u", sb.st_mode); - ALOGV("st_uid = %lu", sb.st_uid); - ALOGV("st_gid = %lu", sb.st_gid); + ALOGV("st_uid = %lu", static_cast(sb.st_uid)); + ALOGV("st_gid = %lu", static_cast(sb.st_gid)); ALOGV("st_size = %llu", sb.st_size); if (offset >= sb.st_size) { @@ -803,7 +803,7 @@ status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter) } status_t MediaPlayerService::Client::getMetadata( - bool update_only, bool apply_filter, Parcel *reply) + bool update_only, bool /*apply_filter*/, Parcel *reply) { sp player = getPlayer(); if (player == 0) return UNKNOWN_ERROR; @@ -1926,8 +1926,8 @@ bool CallbackThread::threadLoop() { status_t MediaPlayerService::AudioCache::open( uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask, audio_format_t format, int bufferCount, - AudioCallback cb, void *cookie, audio_output_flags_t flags, - const audio_offload_info_t *offloadInfo) + AudioCallback cb, void *cookie, audio_output_flags_t /*flags*/, + const audio_offload_info_t* /*offloadInfo*/) { ALOGV("open(%u, %d, 0x%x, %d, %d)", sampleRate, channelCount, channelMask, format, bufferCount); if (mHeap->getHeapID() < 0) { @@ -1994,7 +1994,7 @@ status_t MediaPlayerService::AudioCache::wait() } void MediaPlayerService::AudioCache::notify( - void* cookie, int msg, int ext1, int ext2, const Parcel *obj) + void* cookie, int msg, int ext1, int ext2, const Parcel* /*obj*/) { ALOGV("notify(%p, %d, %d, %d)", cookie, msg, ext1, ext2); AudioCache* p = static_cast(cookie); diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp index 80c7e0a..a91b0e5 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp +++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp @@ -147,8 +147,8 @@ status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t } ALOGV("st_dev = %llu", sb.st_dev); ALOGV("st_mode = %u", sb.st_mode); - ALOGV("st_uid = %lu", sb.st_uid); - ALOGV("st_gid = %lu", sb.st_gid); + ALOGV("st_uid = %lu", static_cast(sb.st_uid)); + ALOGV("st_gid = %lu", static_cast(sb.st_gid)); ALOGV("st_size = %llu", sb.st_size); if (offset >= sb.st_size) { diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp index deeddd1..749ef96 100644 --- a/media/libmediaplayerservice/MidiFile.cpp +++ b/media/libmediaplayerservice/MidiFile.cpp @@ -114,7 +114,7 @@ MidiFile::~MidiFile() { } status_t MidiFile::setDataSource( - const sp &httpService, + const sp & /*httpService*/, const char* path, const KeyedVector *) { ALOGV("MidiFile::setDataSource url=%s", path); -- cgit v1.1 From 0f6a0435713c435e1aaeacbfd9ce7abb6a5b19a9 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 18 Jun 2014 16:32:00 -0700 Subject: libnbaio: 64-bit compile warnings Change-Id: I9517c32193031dcc7af7b2104e985d66805b84aa --- media/libnbaio/MonoPipe.cpp | 6 ++++-- media/libnbaio/NBAIO.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp index 4adf018..0b65861 100644 --- a/media/libnbaio/MonoPipe.cpp +++ b/media/libnbaio/MonoPipe.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #define LOG_TAG "MonoPipe" //#define LOG_NDEBUG 0 @@ -87,7 +89,7 @@ MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBl static const uint64_t kUnsignedHiBitsMask = ~(0xFFFFFFFFull); if ((N & kSignedHiBitsMask) || (D & kUnsignedHiBitsMask)) { ALOGE("Cannot reduce sample rate to local clock frequency ratio to fit" - " in a 32/32 bit rational. (max reduction is 0x%016llx/0x%016llx" + " in a 32/32 bit rational. (max reduction is 0x%016" PRIx64 "/0x%016" PRIx64 "). getNextWriteTimestamp calls will be non-functional", N, D); return; } @@ -308,7 +310,7 @@ int64_t MonoPipe::offsetTimestampByAudioFrames(int64_t ts, size_t audFrames) // error, but then zero out the ratio in the linear transform so // that we don't try to do any conversions from now on. This // MonoPipe's getNextWriteTimestamp is now broken for good. - ALOGE("Overflow when attempting to convert %d audio frames to" + ALOGE("Overflow when attempting to convert %zu audio frames to" " duration in local time. getNextWriteTimestamp will fail from" " now on.", audFrames); mSamplesToLocalTime.a_to_b_numer = 0; diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index ff3284c..d641e74 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -137,7 +137,7 @@ ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers, NBAIO_Format counterOffers[], size_t& numCounterOffers) { - ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u", + ALOGV("negotiate offers=%p numOffers=%zu countersOffers=%p numCounterOffers=%zu", offers, numOffers, counterOffers, numCounterOffers); if (Format_isValid(mFormat)) { for (size_t i = 0; i < numOffers; ++i) { -- cgit v1.1 From 7b6c7b89241397261d52602cbeaa559962efbfec Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Fri, 20 Jun 2014 13:29:08 -0700 Subject: libeffects: 64-bit compile warnings Change-Id: I210129f5742b046f7ceef48194f039352eff596d --- .../libeffects/lvm/wrapper/Bundle/EffectBundle.cpp | 29 ++++++++++++---------- .../libeffects/lvm/wrapper/Reverb/EffectReverb.cpp | 29 ++++++++++++---------- 2 files changed, 32 insertions(+), 26 deletions(-) (limited to 'media') diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index db5c78f..695767d 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -19,11 +19,13 @@ #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) //#define LOG_NDEBUG 0 -#include #include +#include +#include #include #include -#include + +#include #include "EffectBundle.h" @@ -560,11 +562,12 @@ int LvmBundle_init(EffectContext *pContext){ MemTab.Region[i].pBaseAddress = malloc(MemTab.Region[i].Size); if (MemTab.Region[i].pBaseAddress == LVM_NULL){ - ALOGV("\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate %ld bytes " - "for region %u\n", MemTab.Region[i].Size, i ); + ALOGV("\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate %" PRIu32 + " bytes for region %u\n", MemTab.Region[i].Size, i ); bMallocFailure = LVM_TRUE; }else{ - ALOGV("\tLvmBundle_init CreateInstance allocated %ld bytes for region %u at %p\n", + ALOGV("\tLvmBundle_init CreateInstance allocated %" PRIu32 + " bytes for region %u at %p\n", MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress); } } @@ -576,11 +579,11 @@ int LvmBundle_init(EffectContext *pContext){ if(bMallocFailure == LVM_TRUE){ for (int i=0; i #include +#include +#include #include #include -#include + +#include #include "EffectReverb.h" // from Reverb/lib #include "LVREV.h" @@ -269,7 +271,7 @@ extern "C" int EffectCreate(const effect_uuid_t *uuid, pContext->InFrames32 = (LVM_INT32 *)malloc(LVREV_MAX_FRAME_SIZE * sizeof(LVM_INT32) * 2); pContext->OutFrames32 = (LVM_INT32 *)malloc(LVREV_MAX_FRAME_SIZE * sizeof(LVM_INT32) * 2); - ALOGV("\tEffectCreate %p, size %d", pContext, sizeof(ReverbContext)); + ALOGV("\tEffectCreate %p, size %zu", pContext, sizeof(ReverbContext)); ALOGV("\tEffectCreate end\n"); return 0; } /* end EffectCreate */ @@ -570,15 +572,15 @@ void Reverb_free(ReverbContext *pContext){ for (int i=0; i Date: Tue, 17 Jun 2014 14:48:32 -0700 Subject: Parse trex and mehd boxes Also get duration from mvhd if available, use that in addition to track durations to determine total length of file, clear track header struct so we don't read uninitialized garbage from it, and take composition time offset into account for proper ordering when B frames are used. b/15669839 Change-Id: Ibf3e35b5c7299bac11d0e78a391545fc325dd2d0 --- .../nuplayer/GenericSource.cpp | 8 ++ media/libstagefright/AwesomePlayer.cpp | 7 ++ media/libstagefright/MPEG4Extractor.cpp | 131 ++++++++++++++++++--- media/libstagefright/include/MPEG4Extractor.h | 11 +- 4 files changed, 141 insertions(+), 16 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 06aac33..5cf9238 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -67,6 +67,14 @@ void NuPlayer::GenericSource::initFromDataSource( CHECK(extractor != NULL); + sp fileMeta = extractor->getMetaData(); + if (fileMeta != NULL) { + int64_t duration; + if (fileMeta->findInt64(kKeyDuration, &duration)) { + mDurationUs = duration; + } + } + for (size_t i = 0; i < extractor->countTracks(); ++i) { sp meta = extractor->getTrackMetaData(i); diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index d679be1..f35a5b1 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -408,6 +408,13 @@ status_t AwesomePlayer::setDataSource_l(const sp &extractor) { totalBitRate += bitrate; } + sp fileMeta = mExtractor->getMetaData(); + if (fileMeta != NULL) { + int64_t duration; + if (fileMeta->findInt64(kKeyDuration, &duration)) { + mDurationUs = duration; + } + } mBitrate = totalBitRate; diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 23b221d..1b9551f 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -51,6 +51,7 @@ public: int32_t timeScale, const sp &sampleTable, Vector &sidx, + const Trex *trex, off64_t firstMoofOffset); virtual status_t start(MetaData *params = NULL); @@ -74,6 +75,7 @@ private: uint32_t mCurrentSampleIndex; uint32_t mCurrentFragmentIndex; Vector &mSegments; + const Trex *mTrex; off64_t mFirstMoofOffset; off64_t mCurrentMoofOffset; off64_t mNextMoofOffset; @@ -141,6 +143,7 @@ private: off64_t offset; size_t size; uint32_t duration; + int32_t compositionOffset; uint8_t iv[16]; Vector clearsizes; Vector encryptedsizes; @@ -343,8 +346,7 @@ static bool AdjustChannelsAndRate(uint32_t fourcc, uint32_t *channels, uint32_t } MPEG4Extractor::MPEG4Extractor(const sp &source) - : mSidxDuration(0), - mMoofOffset(0), + : mMoofOffset(0), mDataSource(source), mInitCheck(NO_INIT), mHasVideo(false), @@ -1163,6 +1165,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->timescale = ntohl(timescale); + // 14496-12 says all ones means indeterminate, but some files seem to use + // 0 instead. We treat both the same. int64_t duration = 0; if (version == 1) { if (mDataSource->readAt( @@ -1170,7 +1174,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { < (ssize_t)sizeof(duration)) { return ERROR_IO; } - duration = ntoh64(duration); + if (duration != -1) { + duration = ntoh64(duration); + } } else { uint32_t duration32; if (mDataSource->readAt( @@ -1178,13 +1184,14 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { < (ssize_t)sizeof(duration32)) { return ERROR_IO; } - // ffmpeg sets duration to -1, which is incorrect. if (duration32 != 0xffffffff) { duration = ntohl(duration32); } } - mLastTrack->meta->setInt64( - kKeyDuration, (duration * 1000000) / mLastTrack->timescale); + if (duration != 0) { + mLastTrack->meta->setInt64( + kKeyDuration, (duration * 1000000) / mLastTrack->timescale); + } uint8_t lang[2]; off64_t lang_offset; @@ -1724,11 +1731,11 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { { *offset += chunk_size; - if (chunk_data_size < 24) { + if (chunk_data_size < 32) { return ERROR_MALFORMED; } - uint8_t header[24]; + uint8_t header[32]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { @@ -1736,14 +1743,27 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { } uint64_t creationTime; + uint64_t duration = 0; if (header[0] == 1) { creationTime = U64_AT(&header[4]); mHeaderTimescale = U32_AT(&header[20]); + duration = U64_AT(&header[24]); + if (duration == 0xffffffffffffffff) { + duration = 0; + } } else if (header[0] != 0) { return ERROR_MALFORMED; } else { creationTime = U32_AT(&header[4]); mHeaderTimescale = U32_AT(&header[12]); + uint32_t d32 = U32_AT(&header[16]); + if (d32 == 0xffffffff) { + d32 = 0; + } + duration = d32; + } + if (duration != 0) { + mFileMetaData->setInt64(kKeyDuration, duration * 1000000 / mHeaderTimescale); } String8 s; @@ -1754,6 +1774,50 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { break; } + case FOURCC('m', 'e', 'h', 'd'): + { + *offset += chunk_size; + + if (chunk_data_size < 8) { + return ERROR_MALFORMED; + } + + uint8_t flags[4]; + if (mDataSource->readAt( + data_offset, flags, sizeof(flags)) + < (ssize_t)sizeof(flags)) { + return ERROR_IO; + } + + uint64_t duration = 0; + if (flags[0] == 1) { + // 64 bit + if (chunk_data_size < 12) { + return ERROR_MALFORMED; + } + mDataSource->getUInt64(data_offset + 4, &duration); + if (duration == 0xffffffffffffffff) { + duration = 0; + } + } else if (flags[0] == 0) { + // 32 bit + uint32_t d32; + mDataSource->getUInt32(data_offset + 4, &d32); + if (d32 == 0xffffffff) { + d32 = 0; + } + duration = d32; + } else { + return ERROR_MALFORMED; + } + + if (duration != 0) { + mFileMetaData->setInt64(kKeyDuration, duration * 1000000 / mHeaderTimescale); + } + + break; + } + case FOURCC('m', 'd', 'a', 't'): { ALOGV("mdat chunk, drm: %d", mIsDrm); @@ -1790,6 +1854,26 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { break; } + case FOURCC('t', 'r', 'e', 'x'): + { + *offset += chunk_size; + + if (chunk_data_size < 24) { + return ERROR_IO; + } + uint32_t duration; + Trex trex; + if (!mDataSource->getUInt32(data_offset + 4, &trex.track_ID) || + !mDataSource->getUInt32(data_offset + 8, &trex.default_sample_description_index) || + !mDataSource->getUInt32(data_offset + 12, &trex.default_sample_duration) || + !mDataSource->getUInt32(data_offset + 16, &trex.default_sample_size) || + !mDataSource->getUInt32(data_offset + 20, &trex.default_sample_flags)) { + return ERROR_IO; + } + mTrex.add(trex); + break; + } + case FOURCC('t', 'x', '3', 'g'): { uint32_t type; @@ -2014,12 +2098,11 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) { mSidxEntries.add(se); } - mSidxDuration = total_duration * 1000000 / timeScale; - ALOGV("duration: %lld", mSidxDuration); + uint64_t sidxDuration = total_duration * 1000000 / timeScale; int64_t metaDuration; if (!mLastTrack->meta->findInt64(kKeyDuration, &metaDuration) || metaDuration == 0) { - mLastTrack->meta->setInt64(kKeyDuration, mSidxDuration); + mLastTrack->meta->setInt64(kKeyDuration, sidxDuration); } return OK; } @@ -2492,11 +2575,24 @@ sp MPEG4Extractor::getTrack(size_t index) { return NULL; } + + Trex *trex = NULL; + int32_t trackId; + if (track->meta->findInt32(kKeyTrackID, &trackId)) { + for (size_t i = 0; i < mTrex.size(); i++) { + Trex *t = &mTrex.editItemAt(index); + if (t->track_ID == (uint32_t) trackId) { + trex = t; + break; + } + } + } + ALOGV("getTrack called, pssh: %d", mPssh.size()); return new MPEG4Source( track->meta, mDataSource, track->timescale, track->sampleTable, - mSidxEntries, mMoofOffset); + mSidxEntries, trex, mMoofOffset); } // static @@ -2826,6 +2922,7 @@ MPEG4Source::MPEG4Source( int32_t timeScale, const sp &sampleTable, Vector &sidx, + const Trex *trex, off64_t firstMoofOffset) : mFormat(format), mDataSource(dataSource), @@ -2834,6 +2931,7 @@ MPEG4Source::MPEG4Source( mCurrentSampleIndex(0), mCurrentFragmentIndex(0), mSegments(sidx), + mTrex(trex), mFirstMoofOffset(firstMoofOffset), mCurrentMoofOffset(firstMoofOffset), mCurrentTime(0), @@ -2850,6 +2948,8 @@ MPEG4Source::MPEG4Source( mWantsNALFragments(false), mSrcBuffer(NULL) { + memset(&mTrackFragmentHeaderInfo, 0, sizeof(mTrackFragmentHeaderInfo)); + mFormat->findInt32(kKeyCryptoMode, &mCryptoMode); mDefaultIVSize = 0; mFormat->findInt32(kKeyCryptoDefaultIVSize, &mDefaultIVSize); @@ -3421,8 +3521,8 @@ status_t MPEG4Source::parseTrackFragmentRun(off64_t offset, off64_t size) { } else if (mTrackFragmentHeaderInfo.mFlags & TrackFragmentHeaderInfo::kDefaultSampleDurationPresent) { sampleDuration = mTrackFragmentHeaderInfo.mDefaultSampleDuration; - } else { - sampleDuration = mTrackFragmentHeaderInfo.mDefaultSampleDuration; + } else if (mTrex) { + sampleDuration = mTrex->default_sample_duration; } if (flags & kSampleSizePresent) { @@ -3491,6 +3591,7 @@ status_t MPEG4Source::parseTrackFragmentRun(off64_t offset, off64_t size) { tmp.offset = dataOffset; tmp.size = sampleSize; tmp.duration = sampleDuration; + tmp.compositionOffset = sampleCtsOffset; mCurrentSamples.add(tmp); dataOffset += sampleSize; @@ -3893,7 +3994,7 @@ status_t MPEG4Source::fragmentedRead( const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex]; offset = smpl->offset; size = smpl->size; - cts = mCurrentTime; + cts = mCurrentTime + smpl->compositionOffset; mCurrentTime += smpl->duration; isSyncSample = (mCurrentSampleIndex == 0); // XXX diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h index 7b4bc6d..1fe6fcf 100644 --- a/media/libstagefright/include/MPEG4Extractor.h +++ b/media/libstagefright/include/MPEG4Extractor.h @@ -39,6 +39,14 @@ struct SidxEntry { uint32_t mDurationUs; }; +struct Trex { + uint32_t track_ID; + uint32_t default_sample_description_index; + uint32_t default_sample_duration; + uint32_t default_sample_size; + uint32_t default_sample_flags; +}; + class MPEG4Extractor : public MediaExtractor { public: // Extractor assumes ownership of "source". @@ -74,11 +82,12 @@ private: }; Vector mSidxEntries; - uint64_t mSidxDuration; off64_t mMoofOffset; Vector mPssh; + Vector mTrex; + sp mDataSource; status_t mInitCheck; bool mHasVideo; -- cgit v1.1 From dcd89ecad321e2e052322fe2b1907d50d762b311 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 24 Jun 2014 10:49:08 -0700 Subject: Improve MTP error checking Change-Id: I1ab02ca0e99a1c284411fb368a773fb481d72ab2 --- media/mtp/MtpServer.cpp | 65 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 23 deletions(-) (limited to 'media') diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp index 157f2ce..3892fb1 100644 --- a/media/mtp/MtpServer.cpp +++ b/media/mtp/MtpServer.cpp @@ -325,6 +325,14 @@ bool MtpServer::handleRequest() { mSendObjectHandle = kInvalidObjectHandle; } + int containertype = mRequest.getContainerType(); + if (containertype != MTP_CONTAINER_TYPE_COMMAND) { + ALOGE("wrong container type %d", containertype); + return false; + } + + ALOGV("got command %s (%x)", MtpDebug::getOperationCodeName(operation), operation); + switch (operation) { case MTP_OPERATION_GET_DEVICE_INFO: response = doGetDeviceInfo(); @@ -415,7 +423,8 @@ bool MtpServer::handleRequest() { response = doEndEditObject(); break; default: - ALOGE("got unsupported command %s", MtpDebug::getOperationCodeName(operation)); + ALOGE("got unsupported command %s (%x)", + MtpDebug::getOperationCodeName(operation), operation); response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED; break; } @@ -950,22 +959,28 @@ MtpResponseCode MtpServer::doSendObject() { fchmod(mfr.fd, mFilePermission); umask(mask); - if (initialData > 0) + if (initialData > 0) { ret = write(mfr.fd, mData.getData(), initialData); + } - if (mSendObjectFileSize - initialData > 0) { - mfr.offset = initialData; - if (mSendObjectFileSize == 0xFFFFFFFF) { - // tell driver to read until it receives a short packet - mfr.length = 0xFFFFFFFF; - } else { - mfr.length = mSendObjectFileSize - initialData; - } + if (ret < 0) { + ALOGE("failed to write initial data"); + result = MTP_RESPONSE_GENERAL_ERROR; + } else { + if (mSendObjectFileSize - initialData > 0) { + mfr.offset = initialData; + if (mSendObjectFileSize == 0xFFFFFFFF) { + // tell driver to read until it receives a short packet + mfr.length = 0xFFFFFFFF; + } else { + mfr.length = mSendObjectFileSize - initialData; + } - ALOGV("receiving %s\n", (const char *)mSendObjectFilePath); - // transfer the file - ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr); - ALOGV("MTP_RECEIVE_FILE returned %d\n", ret); + ALOGV("receiving %s\n", (const char *)mSendObjectFilePath); + // transfer the file + ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr); + ALOGV("MTP_RECEIVE_FILE returned %d\n", ret); + } } close(mfr.fd); @@ -1131,15 +1146,19 @@ MtpResponseCode MtpServer::doSendPartialObject() { length -= initialData; } - if (length > 0) { - mtp_file_range mfr; - mfr.fd = edit->mFD; - mfr.offset = offset; - mfr.length = length; - - // transfer the file - ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr); - ALOGV("MTP_RECEIVE_FILE returned %d", ret); + if (ret < 0) { + ALOGE("failed to write initial data"); + } else { + if (length > 0) { + mtp_file_range mfr; + mfr.fd = edit->mFD; + mfr.offset = offset; + mfr.length = length; + + // transfer the file + ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr); + ALOGV("MTP_RECEIVE_FILE returned %d", ret); + } } if (ret < 0) { mResponse.setParameter(1, 0); -- cgit v1.1 From d239cb6e6898bdf2300e9038111727a9056c58ee Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 18 Jun 2014 16:32:27 -0700 Subject: mtp: 64-bit compile warnings Change-Id: I9ebc270c990d2f83311cec8fef8f1d2842ebf291 --- media/mtp/MtpServer.cpp | 9 +++++---- media/mtp/MtpStorageInfo.cpp | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp index 3892fb1..aa43967 100644 --- a/media/mtp/MtpServer.cpp +++ b/media/mtp/MtpServer.cpp @@ -802,7 +802,7 @@ MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) { int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format); if (result != MTP_RESPONSE_OK) return result; - if (offset + length > fileLength) + if (offset + length > (uint64_t)fileLength) length = fileLength - offset; const char* filePath = (const char *)pathBuf; @@ -1005,7 +1005,7 @@ done: static void deleteRecursive(const char* path) { char pathbuf[PATH_MAX]; - int pathLength = strlen(path); + size_t pathLength = strlen(path); if (pathLength >= sizeof(pathbuf) - 1) { ALOGE("path too long: %s\n", path); } @@ -1127,12 +1127,13 @@ MtpResponseCode MtpServer::doSendPartialObject() { // can't start writing past the end of the file if (offset > edit->mSize) { - ALOGD("writing past end of object, offset: %lld, edit->mSize: %lld", offset, edit->mSize); + ALOGD("writing past end of object, offset: %" PRIu64 ", edit->mSize: %" PRIu64, + offset, edit->mSize); return MTP_RESPONSE_GENERAL_ERROR; } const char* filePath = (const char *)edit->mPath; - ALOGV("receiving partial %s %lld %" PRIu32 "\n", filePath, offset, length); + ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length); // read the header, and possibly some data int ret = mData.read(mFD); diff --git a/media/mtp/MtpStorageInfo.cpp b/media/mtp/MtpStorageInfo.cpp index dcd37cd..2b1a9ae 100644 --- a/media/mtp/MtpStorageInfo.cpp +++ b/media/mtp/MtpStorageInfo.cpp @@ -16,6 +16,8 @@ #define LOG_TAG "MtpStorageInfo" +#include + #include "MtpDebug.h" #include "MtpDataPacket.h" #include "MtpStorageInfo.h" @@ -63,7 +65,7 @@ void MtpStorageInfo::read(MtpDataPacket& packet) { void MtpStorageInfo::print() { ALOGD("Storage Info %08X:\n\tmStorageType: %d\n\tmFileSystemType: %d\n\tmAccessCapability: %d\n", mStorageID, mStorageType, mFileSystemType, mAccessCapability); - ALOGD("\tmMaxCapacity: %lld\n\tmFreeSpaceBytes: %lld\n\tmFreeSpaceObjects: %d\n", + ALOGD("\tmMaxCapacity: %" PRIu64 "\n\tmFreeSpaceBytes: %" PRIu64 "\n\tmFreeSpaceObjects: %d\n", mMaxCapacity, mFreeSpaceBytes, mFreeSpaceObjects); ALOGD("\tmStorageDescription: %s\n\tmVolumeIdentifier: %s\n", mStorageDescription, mVolumeIdentifier); -- cgit v1.1 From c8efda9e9cd61dfe8e486c93fa8940b77cc3cceb Mon Sep 17 00:00:00 2001 From: Rachad Date: Mon, 19 May 2014 18:01:41 -0700 Subject: Add HEVC encoder support to ACodec Bug: 14571712 Change-Id: Idaec2394d569541f3963befe722f46f6b0007937 --- media/libstagefright/ACodec.cpp | 60 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 8f154be..5156d3e 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -2035,6 +2035,10 @@ status_t ACodec::setupVideoEncoder(const char *mime, const sp &msg) { err = setupAVCEncoderParameters(msg); break; + case OMX_VIDEO_CodingHEVC: + err = setupHEVCEncoderParameters(msg); + break; + case OMX_VIDEO_CodingVP8: case OMX_VIDEO_CodingVP9: err = setupVPXEncoderParameters(msg); @@ -2371,6 +2375,62 @@ status_t ACodec::setupAVCEncoderParameters(const sp &msg) { return configureBitrate(bitrate, bitrateMode); } +status_t ACodec::setupHEVCEncoderParameters(const sp &msg) { + int32_t bitrate, iFrameInterval; + if (!msg->findInt32("bitrate", &bitrate) + || !msg->findInt32("i-frame-interval", &iFrameInterval)) { + return INVALID_OPERATION; + } + + OMX_VIDEO_CONTROLRATETYPE bitrateMode = getBitrateMode(msg); + + float frameRate; + if (!msg->findFloat("frame-rate", &frameRate)) { + int32_t tmp; + if (!msg->findInt32("frame-rate", &tmp)) { + return INVALID_OPERATION; + } + frameRate = (float)tmp; + } + + OMX_VIDEO_PARAM_HEVCTYPE hevcType; + InitOMXParams(&hevcType); + hevcType.nPortIndex = kPortIndexOutput; + + status_t err = OK; + err = mOMX->getParameter( + mNode, (OMX_INDEXTYPE)OMX_IndexParamVideoHevc, &hevcType, sizeof(hevcType)); + if (err != OK) { + return err; + } + + int32_t profile; + if (msg->findInt32("profile", &profile)) { + int32_t level; + if (!msg->findInt32("level", &level)) { + return INVALID_OPERATION; + } + + err = verifySupportForProfileAndLevel(profile, level); + if (err != OK) { + return err; + } + + hevcType.eProfile = static_cast(profile); + hevcType.eLevel = static_cast(level); + } + + // TODO: Need OMX structure definition for setting iFrameInterval + + err = mOMX->setParameter( + mNode, (OMX_INDEXTYPE)OMX_IndexParamVideoHevc, &hevcType, sizeof(hevcType)); + if (err != OK) { + return err; + } + + return configureBitrate(bitrate, bitrateMode); +} + status_t ACodec::setupVPXEncoderParameters(const sp &msg) { int32_t bitrate; int32_t iFrameInterval = 0; -- cgit v1.1 From 1130c49ee00e2faf0e21152da88cda07299232da Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 25 Jun 2014 18:06:53 -0700 Subject: HLS: only queue discontinuity for first block Bug: 15020526 Change-Id: I15f9ab0f38dc510e584c668eea73ece61844d413 --- media/libstagefright/httplive/PlaylistFetcher.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'media') diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 326d85b..2af0998 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -896,6 +896,9 @@ void PlaylistFetcher::onDownloadNext() { ? ATSParser::DISCONTINUITY_FORMATCHANGE : ATSParser::DISCONTINUITY_SEEK, NULL /* extra */); + + seekDiscontinuity = false; + explicitDiscontinuity = false; } } -- cgit v1.1 From a5750e0dad9e90f2195ce36f2c4457fa04b2b83e Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 18 Jun 2014 16:34:45 -0700 Subject: libstagefright: 64-bit compile warnings Change-Id: I3d1146714fa23be3d4e696599b6f70cac1f9d28b --- media/libstagefright/AACWriter.cpp | 12 +++-- media/libstagefright/AMRWriter.cpp | 12 +++-- media/libstagefright/AudioPlayer.cpp | 14 +++--- media/libstagefright/AudioSource.cpp | 10 ++-- media/libstagefright/AwesomePlayer.cpp | 18 ++++--- media/libstagefright/CameraSource.cpp | 16 +++--- media/libstagefright/CameraSourceTimeLapse.cpp | 6 ++- media/libstagefright/DataURISource.cpp | 2 +- media/libstagefright/ESDS.cpp | 2 +- media/libstagefright/MPEG2TSWriter.cpp | 2 +- media/libstagefright/MPEG4Extractor.cpp | 30 +++++------ media/libstagefright/MPEG4Writer.cpp | 58 +++++++++++----------- media/libstagefright/MediaBuffer.cpp | 2 +- media/libstagefright/MediaCodec.cpp | 2 +- media/libstagefright/MediaCodecSource.cpp | 7 ++- media/libstagefright/MediaMuxer.cpp | 2 +- media/libstagefright/NuCachedSource2.cpp | 14 +++--- media/libstagefright/NuMediaExtractor.cpp | 2 +- media/libstagefright/OggExtractor.cpp | 18 +++---- .../StagefrightMetadataRetriever.cpp | 8 +-- media/libstagefright/SurfaceMediaSource.cpp | 10 ++-- media/libstagefright/TimedEventQueue.cpp | 9 ++-- media/libstagefright/Utils.cpp | 4 +- media/libstagefright/VBRISeeker.cpp | 9 ++-- media/libstagefright/WAVExtractor.cpp | 2 +- .../codecs/on2/enc/SoftVPXEncoder.cpp | 2 +- media/libstagefright/omx/GraphicBufferSource.cpp | 31 +++++++----- media/libstagefright/omx/OMXMaster.cpp | 2 +- 28 files changed, 170 insertions(+), 136 deletions(-) (limited to 'media') diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp index deee8e7..353920e 100644 --- a/media/libstagefright/AACWriter.cpp +++ b/media/libstagefright/AACWriter.cpp @@ -14,6 +14,12 @@ * limitations under the License. */ +#include +#include +#include +#include +#include + //#define LOG_NDEBUG 0 #define LOG_TAG "AACWriter" #include @@ -27,10 +33,6 @@ #include #include #include -#include -#include -#include -#include namespace android { @@ -348,7 +350,7 @@ status_t AACWriter::threadFunc() { mResumed = false; } timestampUs -= previousPausedDurationUs; - ALOGV("time stamp: %lld, previous paused duration: %lld", + ALOGV("time stamp: %" PRId64 ", previous paused duration: %" PRId64, timestampUs, previousPausedDurationUs); if (timestampUs > maxTimestampUs) { maxTimestampUs = timestampUs; diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp index 653ca36..9aa7d95 100644 --- a/media/libstagefright/AMRWriter.cpp +++ b/media/libstagefright/AMRWriter.cpp @@ -14,6 +14,12 @@ * limitations under the License. */ +#include +#include +#include +#include +#include + #include #include #include @@ -22,10 +28,6 @@ #include #include #include -#include -#include -#include -#include namespace android { @@ -235,7 +237,7 @@ status_t AMRWriter::threadFunc() { mResumed = false; } timestampUs -= previousPausedDurationUs; - ALOGV("time stamp: %lld, previous paused duration: %lld", + ALOGV("time stamp: %" PRId64 ", previous paused duration: %" PRId64, timestampUs, previousPausedDurationUs); if (timestampUs > maxTimestampUs) { maxTimestampUs = timestampUs; diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index 2669849..fdac8fc 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + //#define LOG_NDEBUG 0 #define LOG_TAG "AudioPlayer" #include @@ -566,12 +568,12 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) { int64_t timeToCompletionUs = (1000000ll * numFramesPendingPlayout) / mSampleRate; - ALOGV("total number of frames played: %lld (%lld us)", + ALOGV("total number of frames played: %" PRId64 " (%lld us)", (mNumFramesPlayed + numAdditionalFrames), 1000000ll * (mNumFramesPlayed + numAdditionalFrames) / mSampleRate); - ALOGV("%d frames left to play, %lld us (%.2f secs)", + ALOGV("%d frames left to play, %" PRId64 " us (%.2f secs)", numFramesPendingPlayout, timeToCompletionUs, timeToCompletionUs / 1E6); @@ -628,7 +630,7 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) { mPositionTimeRealUs = ((mNumFramesPlayed + size_done / mFrameSize) * 1000000) / mSampleRate; - ALOGV("buffer->size() = %d, " + ALOGV("buffer->size() = %zu, " "mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f", mInputBuffer->range_length(), mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6); @@ -746,7 +748,7 @@ int64_t AudioPlayer::getOutputPlayPositionUs_l() // HAL position is relative to the first buffer we sent at mStartPosUs const int64_t renderedDuration = mStartPosUs + playedUs; - ALOGV("getOutputPlayPositionUs_l %lld", renderedDuration); + ALOGV("getOutputPlayPositionUs_l %" PRId64, renderedDuration); return renderedDuration; } @@ -758,7 +760,7 @@ int64_t AudioPlayer::getMediaTimeUs() { return mSeekTimeUs; } mPositionTimeRealUs = getOutputPlayPositionUs_l(); - ALOGV("getMediaTimeUs getOutputPlayPositionUs_l() mPositionTimeRealUs %lld", + ALOGV("getMediaTimeUs getOutputPlayPositionUs_l() mPositionTimeRealUs %" PRId64, mPositionTimeRealUs); return mPositionTimeRealUs; } @@ -796,7 +798,7 @@ bool AudioPlayer::getMediaTimeMapping( status_t AudioPlayer::seekTo(int64_t time_us) { Mutex::Autolock autoLock(mLock); - ALOGV("seekTo( %lld )", time_us); + ALOGV("seekTo( %" PRId64 " )", time_us); mSeeking = true; mPositionTimeRealUs = mPositionTimeMediaUs = -1; diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index d0e0e8e..d9aed01 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +#include +#include + //#define LOG_NDEBUG 0 #define LOG_TAG "AudioSource" #include @@ -26,7 +29,6 @@ #include #include #include -#include namespace android { @@ -136,7 +138,7 @@ void AudioSource::releaseQueuedFrames_l() { } void AudioSource::waitOutstandingEncodingFrames_l() { - ALOGV("waitOutstandingEncodingFrames_l: %lld", mNumClientOwnedBuffers); + ALOGV("waitOutstandingEncodingFrames_l: %" PRId64, mNumClientOwnedBuffers); while (mNumClientOwnedBuffers > 0) { mFrameEncodingCompletionCondition.wait(mLock); } @@ -269,7 +271,7 @@ void AudioSource::signalBufferReturned(MediaBuffer *buffer) { status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) { int64_t timeUs = systemTime() / 1000ll; - ALOGV("dataCallbackTimestamp: %lld us", timeUs); + ALOGV("dataCallbackTimestamp: %" PRId64 " us", timeUs); Mutex::Autolock autoLock(mLock); if (!mStarted) { ALOGW("Spurious callback from AudioRecord. Drop the audio data."); @@ -279,7 +281,7 @@ status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) { // Drop retrieved and previously lost audio data. if (mNumFramesReceived == 0 && timeUs < mStartTimeUs) { (void) mRecord->getInputFramesLost(); - ALOGV("Drop audio data at %lld/%lld us", timeUs, mStartTimeUs); + ALOGV("Drop audio data at %" PRId64 "/%" PRId64 " us", timeUs, mStartTimeUs); return OK; } diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index f35a5b1..63799e1 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -19,7 +19,9 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "AwesomePlayer" #define ATRACE_TAG ATRACE_TAG_VIDEO + #include + #include #include @@ -1715,7 +1717,7 @@ void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) { } if (mAudioPlayer != NULL) { - ALOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6); + ALOGV("seeking audio to %" PRId64 " us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6); // If we don't have a video time, seek audio to the originally // requested seek time instead. @@ -1779,7 +1781,7 @@ void AwesomePlayer::onVideoEvent() { if (!mVideoBuffer) { MediaSource::ReadOptions options; if (mSeeking != NO_SEEK) { - ALOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6); + ALOGV("seeking to %" PRId64 " us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6); options.setSeekTo( mSeekTimeUs, @@ -1849,7 +1851,7 @@ void AwesomePlayer::onVideoEvent() { if (mSeeking == SEEK_VIDEO_ONLY) { if (mSeekTimeUs > timeUs) { - ALOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us", + ALOGI("XXX mSeekTimeUs = %" PRId64 " us, timeUs = %" PRId64 " us", mSeekTimeUs, timeUs); } } @@ -1947,13 +1949,13 @@ void AwesomePlayer::onVideoEvent() { if (latenessUs > 40000) { // We're more than 40ms late. - ALOGV("we're late by %lld us (%.2f secs)", + ALOGV("we're late by %" PRId64 " us (%.2f secs)", latenessUs, latenessUs / 1E6); if (!(mFlags & SLOW_DECODER_HACK) || mSinceLastDropped > FRAME_DROP_FREQ) { - ALOGV("we're late by %lld us (%.2f secs) dropping " + ALOGV("we're late by %" PRId64 " us (%.2f secs) dropping " "one after %d frames", latenessUs, latenessUs / 1E6, mSinceLastDropped); @@ -2315,12 +2317,12 @@ status_t AwesomePlayer::finishSetDataSource_l() { if (finalStatus != OK || (metaDataSize >= 0 - && cachedDataRemaining >= metaDataSize) + && (off64_t)cachedDataRemaining >= metaDataSize) || (mFlags & PREPARE_CANCELLED)) { break; } - ALOGV("now cached %d bytes of data", cachedDataRemaining); + ALOGV("now cached %zu bytes of data", cachedDataRemaining); if (metaDataSize < 0 && cachedDataRemaining >= kMinBytesForSniffing) { @@ -2699,7 +2701,7 @@ status_t AwesomePlayer::selectAudioTrack_l( status_t AwesomePlayer::selectTrack(size_t trackIndex, bool select) { ATRACE_CALL(); - ALOGV("selectTrack: trackIndex = %d and select=%d", trackIndex, select); + ALOGV("selectTrack: trackIndex = %zu and select=%d", trackIndex, select); Mutex::Autolock autoLock(mLock); size_t trackCount = mExtractor->countTracks(); if (mTextDriver != NULL) { diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index b31e9e8..2b50763 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + //#define LOG_NDEBUG 0 #define LOG_TAG "CameraSource" #include @@ -77,7 +79,7 @@ void CameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) { void CameraSourceListener::postData(int32_t msgType, const sp &dataPtr, camera_frame_metadata_t * /* metadata */) { - ALOGV("postData(%d, ptr:%p, size:%d)", + ALOGV("postData(%d, ptr:%p, size:%zu)", msgType, dataPtr->pointer(), dataPtr->size()); sp source = mSource.promote(); @@ -711,7 +713,7 @@ status_t CameraSource::reset() { if (NO_ERROR != mFrameCompleteCondition.waitRelative(mLock, mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) { - ALOGW("Timed out waiting for outstanding frames being encoded: %d", + ALOGW("Timed out waiting for outstanding frames being encoded: %zu", mFramesBeingEncoded.size()); } } @@ -722,7 +724,7 @@ status_t CameraSource::reset() { } if (mCollectStats) { - ALOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us", + ALOGI("Frames received/encoded/dropped: %d/%d/%d in %" PRId64 " us", mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped, mLastFrameTimestampUs - mFirstFrameTimeUs); } @@ -809,7 +811,7 @@ status_t CameraSource::read( ALOGW("camera recording proxy is gone"); return ERROR_END_OF_STREAM; } - ALOGW("Timed out waiting for incoming camera video frames: %lld us", + ALOGW("Timed out waiting for incoming camera video frames: %" PRId64 " us", mLastFrameTimestampUs); } } @@ -832,10 +834,10 @@ status_t CameraSource::read( void CameraSource::dataCallbackTimestamp(int64_t timestampUs, int32_t msgType, const sp &data) { - ALOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs); + ALOGV("dataCallbackTimestamp: timestamp %" PRId64 " us", timestampUs); Mutex::Autolock autoLock(mLock); if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) { - ALOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs); + ALOGV("Drop frame at %" PRId64 "/%" PRId64 " us", timestampUs, mStartTimeUs); releaseOneRecordingFrame(data); return; } @@ -874,7 +876,7 @@ void CameraSource::dataCallbackTimestamp(int64_t timestampUs, mFramesReceived.push_back(data); int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs); mFrameTimes.push_back(timeUs); - ALOGV("initial delay: %lld, current time stamp: %lld", + ALOGV("initial delay: %" PRId64 ", current time stamp: %" PRId64, mStartTimeUs, timeUs); mFrameAvailableCondition.signal(); } diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp index 15ba967..0acd9d0 100644 --- a/media/libstagefright/CameraSourceTimeLapse.cpp +++ b/media/libstagefright/CameraSourceTimeLapse.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + //#define LOG_NDEBUG 0 #define LOG_TAG "CameraSourceTimeLapse" @@ -79,7 +81,7 @@ CameraSourceTimeLapse::CameraSourceTimeLapse( mSkipCurrentFrame(false) { mTimeBetweenFrameCaptureUs = timeBetweenFrameCaptureUs; - ALOGD("starting time lapse mode: %lld us", + ALOGD("starting time lapse mode: %" PRId64 " us", mTimeBetweenFrameCaptureUs); mVideoWidth = videoSize.width; @@ -266,7 +268,7 @@ bool CameraSourceTimeLapse::skipFrameAndModifyTimeStamp(int64_t *timestampUs) { // Really make sure that this video recording frame will not be dropped. if (*timestampUs < mStartTimeUs) { - ALOGI("set timestampUs to start time stamp %lld us", mStartTimeUs); + ALOGI("set timestampUs to start time stamp %" PRId64 " us", mStartTimeUs); *timestampUs = mStartTimeUs; } return false; diff --git a/media/libstagefright/DataURISource.cpp b/media/libstagefright/DataURISource.cpp index 377bc85..2c39314 100644 --- a/media/libstagefright/DataURISource.cpp +++ b/media/libstagefright/DataURISource.cpp @@ -85,7 +85,7 @@ status_t DataURISource::initCheck() const { } ssize_t DataURISource::readAt(off64_t offset, void *data, size_t size) { - if (offset >= mBuffer->size()) { + if ((offset < 0) || (offset >= (off64_t)mBuffer->size())) { return 0; } diff --git a/media/libstagefright/ESDS.cpp b/media/libstagefright/ESDS.cpp index 4a0c35c..427bf7b 100644 --- a/media/libstagefright/ESDS.cpp +++ b/media/libstagefright/ESDS.cpp @@ -91,7 +91,7 @@ status_t ESDS::skipDescriptorHeader( } while (more); - ALOGV("tag=0x%02x data_size=%d", *tag, *data_size); + ALOGV("tag=0x%02x data_size=%zu", *tag, *data_size); if (*data_size > size) { return ERROR_MALFORMED; diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp index 78c12e1..9856f92 100644 --- a/media/libstagefright/MPEG2TSWriter.cpp +++ b/media/libstagefright/MPEG2TSWriter.cpp @@ -682,7 +682,7 @@ void MPEG2TSWriter::onMessageReceived(const sp &msg) { break; } - ALOGV("writing access unit at time %.2f secs (index %d)", + ALOGV("writing access unit at time %.2f secs (index %zu)", minTimeUs / 1E6, minIndex); source = mSources.editItemAt(minIndex); diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 1b9551f..207acc8 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -16,17 +16,19 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MPEG4Extractor" -#include - -#include "include/MPEG4Extractor.h" -#include "include/SampleTable.h" -#include "include/ESDS.h" #include +#include #include #include #include +#include + +#include "include/MPEG4Extractor.h" +#include "include/SampleTable.h" +#include "include/ESDS.h" + #include #include #include @@ -411,7 +413,7 @@ size_t MPEG4Extractor::countTracks() { track = track->next; } - ALOGV("MPEG4Extractor::countTracks: %d tracks", n); + ALOGV("MPEG4Extractor::countTracks: %zu tracks", n); return n; } @@ -792,7 +794,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { } } else if (chunk_size < 8) { // The smallest valid chunk is 8 bytes long. - ALOGE("invalid chunk size: %d", int(chunk_size)); + ALOGE("invalid chunk size: %" PRIu64, chunk_size); return ERROR_MALFORMED; } @@ -803,7 +805,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { #if 0 static const char kWhitespace[] = " "; const char *indent = &kWhitespace[sizeof(kWhitespace) - 1 - 2 * depth]; - printf("%sfound chunk '%s' of size %lld\n", indent, chunk, chunk_size); + printf("%sfound chunk '%s' of size %" PRIu64 "\n", indent, chunk, chunk_size); char buffer[256]; size_t n = chunk_size; @@ -859,7 +861,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('e', 'd', 't', 's'): { if (chunk_type == FOURCC('s', 't', 'b', 'l')) { - ALOGV("sampleTable chunk is %d bytes long.", (size_t)chunk_size); + ALOGV("sampleTable chunk is %" PRIu64 " bytes long.", chunk_size); if (mDataSource->flags() & (DataSource::kWantsPrefetching @@ -2052,7 +2054,7 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) { offset += 16; size -= 16; } - ALOGV("sidx pres/off: %Ld/%Ld", earliestPresentationTime, firstOffset); + ALOGV("sidx pres/off: %" PRIu64 "/%" PRIu64, earliestPresentationTime, firstOffset); if (size < 4) { return -EINVAL; @@ -2588,7 +2590,7 @@ sp MPEG4Extractor::getTrack(size_t index) { } } - ALOGV("getTrack called, pssh: %d", mPssh.size()); + ALOGV("getTrack called, pssh: %zu", mPssh.size()); return new MPEG4Source( track->meta, mDataSource, track->timescale, track->sampleTable, @@ -3549,7 +3551,7 @@ status_t MPEG4Source::parseTrackFragmentRun(off64_t offset, off64_t size) { sampleCtsOffset = 0; } - if (size < sampleCount * bytesPerSample) { + if (size < (off64_t)sampleCount * bytesPerSample) { return -EINVAL; } @@ -3583,7 +3585,7 @@ status_t MPEG4Source::parseTrackFragmentRun(off64_t offset, off64_t size) { offset += 4; } - ALOGV("adding sample %d at offset 0x%08llx, size %u, duration %u, " + ALOGV("adding sample %d at offset 0x%08" PRIx64 ", size %u, duration %u, " " flags 0x%08x", i + 1, dataOffset, sampleSize, sampleDuration, (flags & kFirstSampleFlagsPresent) && i == 0 @@ -4301,7 +4303,7 @@ static bool BetterSniffMPEG4( char chunkstring[5]; MakeFourCCString(chunkType, chunkstring); - ALOGV("saw chunk type %s, size %lld @ %lld", chunkstring, chunkSize, offset); + ALOGV("saw chunk type %s, size %" PRIu64 " @ %lld", chunkstring, chunkSize, offset); switch (chunkType) { case FOURCC('f', 't', 'y', 'p'): { diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 24e53b3..4b8440b 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -16,13 +16,17 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MPEG4Writer" -#include -#include #include - +#include +#include #include #include +#include +#include +#include + +#include #include #include @@ -34,10 +38,6 @@ #include #include #include -#include -#include -#include -#include #include "include/ESDS.h" @@ -441,7 +441,7 @@ status_t MPEG4Writer::addSource(const sp &source) { // At most 2 tracks can be supported. if (mTracks.size() >= 2) { - ALOGE("Too many tracks (%d) to add", mTracks.size()); + ALOGE("Too many tracks (%zu) to add", mTracks.size()); return ERROR_UNSUPPORTED; } @@ -555,8 +555,8 @@ int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { size = MAX_MOOV_BOX_SIZE; } - ALOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" - " moov size %lld bytes", + ALOGI("limits: %" PRId64 "/%" PRId64 " bytes/us, bit rate: %d bps and the" + " estimated moov size %" PRId64 " bytes", mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); return factor * size; } @@ -592,8 +592,8 @@ status_t MPEG4Writer::start(MetaData *param) { // If file size is set to be larger than the 32 bit file // size limit, treat it as an error. if (mMaxFileSizeLimitBytes > kMax32BitFileSize) { - ALOGW("32-bit file size limit (%lld bytes) too big. " - "It is changed to %lld bytes", + ALOGW("32-bit file size limit (%" PRId64 " bytes) too big. " + "It is changed to %" PRId64 " bytes", mMaxFileSizeLimitBytes, kMax32BitFileSize); mMaxFileSizeLimitBytes = kMax32BitFileSize; } @@ -854,7 +854,7 @@ status_t MPEG4Writer::reset() { } if (mTracks.size() > 1) { - ALOGD("Duration from tracks range is [%lld, %lld] us", + ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", minDurationUs, maxDurationUs); } @@ -1321,12 +1321,12 @@ bool MPEG4Writer::reachedEOS() { } void MPEG4Writer::setStartTimestampUs(int64_t timeUs) { - ALOGI("setStartTimestampUs: %lld", timeUs); + ALOGI("setStartTimestampUs: %" PRId64, timeUs); CHECK_GE(timeUs, 0ll); Mutex::Autolock autoLock(mLock); if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { mStartTimestampUs = timeUs; - ALOGI("Earliest track starting time: %lld", mStartTimestampUs); + ALOGI("Earliest track starting time: %" PRId64, mStartTimestampUs); } } @@ -1527,7 +1527,7 @@ void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { { int64_t timeUs; if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { - ALOGV("Receive request to track progress status for every %lld us", timeUs); + ALOGV("Receive request to track progress status for every %" PRId64 " us", timeUs); mTrackEveryTimeDurationUs = timeUs; mTrackingProgressStatus = true; } @@ -1561,7 +1561,7 @@ void MPEG4Writer::bufferChunk(const Chunk& chunk) { } void MPEG4Writer::writeChunkToFile(Chunk* chunk) { - ALOGV("writeChunkToFile: %lld from %s track", + ALOGV("writeChunkToFile: %" PRId64 " from %s track", chunk->mTimeStampUs, chunk->mTrack->isAudio()? "audio": "video"); int32_t isFirstSample = true; @@ -1737,7 +1737,7 @@ status_t MPEG4Writer::Track::start(MetaData *params) { startTimeOffsetUs = kInitialDelayTimeUs; } startTimeUs += startTimeOffsetUs; - ALOGI("Start time offset: %lld us", startTimeOffsetUs); + ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs); } meta->setInt64(kKeyTime, startTimeUs); @@ -1817,7 +1817,7 @@ static void getNalUnitType(uint8_t byte, uint8_t* type) { static const uint8_t *findNextStartCode( const uint8_t *data, size_t length) { - ALOGV("findNextStartCode: %p %d", data, length); + ALOGV("findNextStartCode: %p %zu", data, length); size_t bytesLeft = length; while (bytesLeft > 4 && @@ -2238,7 +2238,7 @@ status_t MPEG4Writer::Track::threadEntry() { } timestampUs = decodingTimeUs; - ALOGV("decoding time: %lld and ctts offset time: %lld", + ALOGV("decoding time: %" PRId64 " and ctts offset time: %" PRId64, timestampUs, cttsOffsetTimeUs); // Update ctts box table if necessary @@ -2291,7 +2291,7 @@ status_t MPEG4Writer::Track::threadEntry() { return ERROR_MALFORMED; } - ALOGV("%s media time stamp: %lld and previous paused duration %lld", + ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64, trackName, timestampUs, previousPausedDurationUs); if (timestampUs > mTrackDurationUs) { mTrackDurationUs = timestampUs; @@ -2306,7 +2306,7 @@ status_t MPEG4Writer::Track::threadEntry() { ((timestampUs * mTimeScale + 500000LL) / 1000000LL - (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); if (currDurationTicks < 0ll) { - ALOGE("timestampUs %lld < lastTimestampUs %lld for %s track", + ALOGE("timestampUs %" PRId64 " < lastTimestampUs %" PRId64 " for %s track", timestampUs, lastTimestampUs, trackName); copy->release(); return UNKNOWN_ERROR; @@ -2347,7 +2347,7 @@ status_t MPEG4Writer::Track::threadEntry() { } previousSampleSize = sampleSize; } - ALOGV("%s timestampUs/lastTimestampUs: %lld/%lld", + ALOGV("%s timestampUs/lastTimestampUs: %" PRId64 "/%" PRId64, trackName, timestampUs, lastTimestampUs); lastDurationUs = timestampUs - lastTimestampUs; lastDurationTicks = currDurationTicks; @@ -2455,7 +2455,7 @@ status_t MPEG4Writer::Track::threadEntry() { ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", count, nZeroLengthFrames, mStszTableEntries->count(), trackName); if (mIsAudio) { - ALOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs()); + ALOGI("Audio track drift time: %" PRId64 " us", mOwner->getDriftTimeUs()); } if (err == ERROR_END_OF_STREAM) { @@ -2538,11 +2538,11 @@ void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { } void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { - ALOGV("trackProgressStatus: %lld us", timeUs); + ALOGV("trackProgressStatus: %" PRId64 " us", timeUs); if (mTrackEveryTimeDurationUs > 0 && timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { - ALOGV("Fire time tracking progress status at %lld us", timeUs); + ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs); mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); mPreviousTrackTimeUs = timeUs; } @@ -2576,13 +2576,13 @@ void MPEG4Writer::trackProgressStatus( } void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { - ALOGV("setDriftTimeUs: %lld us", driftTimeUs); + ALOGV("setDriftTimeUs: %" PRId64 " us", driftTimeUs); Mutex::Autolock autolock(mLock); mDriftTimeUs = driftTimeUs; } int64_t MPEG4Writer::getDriftTimeUs() { - ALOGV("getDriftTimeUs: %lld us", mDriftTimeUs); + ALOGV("getDriftTimeUs: %" PRId64 " us", mDriftTimeUs); Mutex::Autolock autolock(mLock); return mDriftTimeUs; } @@ -3038,7 +3038,7 @@ void MPEG4Writer::Track::writeCttsBox() { return; } - ALOGV("ctts box has %d entries with range [%lld, %lld]", + ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]", mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs); mOwner->beginBox("ctts"); diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp index 8af0880..1f80a47 100644 --- a/media/libstagefright/MediaBuffer.cpp +++ b/media/libstagefright/MediaBuffer.cpp @@ -134,7 +134,7 @@ size_t MediaBuffer::range_length() const { void MediaBuffer::set_range(size_t offset, size_t length) { if ((mGraphicBuffer == NULL) && (offset + length > mSize)) { - ALOGE("offset = %d, length = %d, mSize = %d", offset, length, mSize); + ALOGE("offset = %zu, length = %zu, mSize = %zu", offset, length, mSize); } CHECK((mGraphicBuffer != NULL) || (offset + length <= mSize)); diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index b9c5904..14c8028 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -1456,7 +1456,7 @@ void MediaCodec::extractCSD(const sp &format) { ++i; } - ALOGV("Found %u pieces of codec specific data.", mCSD.size()); + ALOGV("Found %zu pieces of codec specific data.", mCSD.size()); } status_t MediaCodec::queueCSDInputBuffer(size_t bufferIndex) { diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index 924173c..9868ecf 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -17,6 +17,9 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaCodecSource" #define DEBUG_DRIFT_TIME 0 + +#include + #include #include #include @@ -677,7 +680,7 @@ status_t MediaCodecSource::doMoreWork() { } mbuf->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs); - ALOGV("[video] time %lld us (%.2f secs), dts/pts diff %lld", + ALOGV("[video] time %" PRId64 " us (%.2f secs), dts/pts diff %" PRId64, timeUs, timeUs / 1E6, decodingTimeUs - timeUs); } else { int64_t driftTimeUs = 0; @@ -687,7 +690,7 @@ status_t MediaCodecSource::doMoreWork() { mDriftTimeQueue.erase(mDriftTimeQueue.begin()); mbuf->meta_data()->setInt64(kKeyDriftTime, driftTimeUs); #endif // DEBUG_DRIFT_TIME - ALOGV("[audio] time %lld us (%.2f secs), drift %lld", + ALOGV("[audio] time %" PRId64 " us (%.2f secs), drift %" PRId64, timeUs, timeUs / 1E6, driftTimeUs); } mbuf->meta_data()->setInt64(kKeyTime, timeUs); diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp index 90335ee..c7c6f34 100644 --- a/media/libstagefright/MediaMuxer.cpp +++ b/media/libstagefright/MediaMuxer.cpp @@ -176,7 +176,7 @@ status_t MediaMuxer::writeSampleData(const sp &buffer, size_t trackInde } if (trackIndex >= mTrackList.size()) { - ALOGE("WriteSampleData() get an invalid index %d", trackIndex); + ALOGE("WriteSampleData() get an invalid index %zu", trackIndex); return -EINVAL; } diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index 61cf0ad..c1feff8 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + //#define LOG_NDEBUG 0 #define LOG_TAG "NuCachedSource2" #include @@ -135,7 +137,7 @@ size_t PageCache::releaseFromStart(size_t maxBytes) { } void PageCache::copy(size_t from, void *data, size_t size) { - ALOGV("copy from %d size %d", from, size); + ALOGV("copy from %zu size %zu", from, size); if (size == 0) { return; @@ -333,7 +335,7 @@ void NuCachedSource2::fetchInternal() { mNumRetriesLeft = 0; } - ALOGE("source returned error %d, %d retries left", n, mNumRetriesLeft); + ALOGE("source returned error %zd, %d retries left", n, mNumRetriesLeft); mCache->releasePage(page); } else if (n == 0) { ALOGI("ERROR_END_OF_STREAM"); @@ -464,14 +466,14 @@ void NuCachedSource2::restartPrefetcherIfNecessary_l( size_t actualBytes = mCache->releaseFromStart(maxBytes); mCacheOffset += actualBytes; - ALOGI("restarting prefetcher, totalSize = %d", mCache->totalSize()); + ALOGI("restarting prefetcher, totalSize = %zu", mCache->totalSize()); mFetching = true; } ssize_t NuCachedSource2::readAt(off64_t offset, void *data, size_t size) { Mutex::Autolock autoSerializer(mSerializer); - ALOGV("readAt offset %lld, size %d", offset, size); + ALOGV("readAt offset %lld, size %zu", offset, size); Mutex::Autolock autoLock(mLock); @@ -539,7 +541,7 @@ size_t NuCachedSource2::approxDataRemaining_l(status_t *finalStatus) const { ssize_t NuCachedSource2::readInternal(off64_t offset, void *data, size_t size) { CHECK_LE(size, (size_t)mHighwaterThresholdBytes); - ALOGV("readInternal offset %lld size %d", offset, size); + ALOGV("readInternal offset %lld size %zu", offset, size); Mutex::Autolock autoLock(mLock); @@ -679,7 +681,7 @@ void NuCachedSource2::updateCacheParamsFromString(const char *s) { mKeepAliveIntervalUs = kDefaultKeepAliveIntervalUs; } - ALOGV("lowwater = %d bytes, highwater = %d bytes, keepalive = %lld us", + ALOGV("lowwater = %zu bytes, highwater = %zu bytes, keepalive = %" PRId64 " us", mLowwaterThresholdBytes, mHighwaterThresholdBytes, mKeepAliveIntervalUs); diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp index 64f56e9..f24cf3a 100644 --- a/media/libstagefright/NuMediaExtractor.cpp +++ b/media/libstagefright/NuMediaExtractor.cpp @@ -389,7 +389,7 @@ ssize_t NuMediaExtractor::fetchTrackSamples( info->mFinalResult = err; if (info->mFinalResult != ERROR_END_OF_STREAM) { - ALOGW("read on track %d failed with error %d", + ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err); } diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp index f3eeb03..8c15929 100644 --- a/media/libstagefright/OggExtractor.cpp +++ b/media/libstagefright/OggExtractor.cpp @@ -338,7 +338,7 @@ status_t MyVorbisExtractor::seekToTime(int64_t timeUs) { const TOCEntry &entry = mTableOfContents.itemAt(left); - ALOGV("seeking to entry %d / %d at offset %lld", + ALOGV("seeking to entry %zu / %zu at offset %lld", left, mTableOfContents.size(), entry.mPageOffset); return seekToOffset(entry.mPageOffset); @@ -381,7 +381,7 @@ ssize_t MyVorbisExtractor::readPage(off64_t offset, Page *page) { ssize_t n; if ((n = mSource->readAt(offset, header, sizeof(header))) < (ssize_t)sizeof(header)) { - ALOGV("failed to read %zu bytes at offset 0x%016llx, got %d bytes", + ALOGV("failed to read %zu bytes at offset 0x%016llx, got %zd bytes", sizeof(header), offset, n); if (n < 0) { @@ -505,7 +505,7 @@ status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) { packetSize); if (n < (ssize_t)packetSize) { - ALOGV("failed to read %zu bytes at 0x%016llx, got %d bytes", + ALOGV("failed to read %zu bytes at 0x%016llx, got %zd bytes", packetSize, dataOffset, n); return ERROR_IO; } @@ -546,7 +546,7 @@ status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) { buffer = NULL; } - ALOGV("readPage returned %d", n); + ALOGV("readPage returned %zd", n); return n < 0 ? n : (status_t)ERROR_END_OF_STREAM; } @@ -590,7 +590,7 @@ status_t MyVorbisExtractor::init() { if ((err = readNextPacket(&packet)) != OK) { return err; } - ALOGV("read packet of size %d\n", packet->range_length()); + ALOGV("read packet of size %zu\n", packet->range_length()); err = verifyHeader(packet, 1); packet->release(); packet = NULL; @@ -601,7 +601,7 @@ status_t MyVorbisExtractor::init() { if ((err = readNextPacket(&packet)) != OK) { return err; } - ALOGV("read packet of size %d\n", packet->range_length()); + ALOGV("read packet of size %zu\n", packet->range_length()); err = verifyHeader(packet, 3); packet->release(); packet = NULL; @@ -612,7 +612,7 @@ status_t MyVorbisExtractor::init() { if ((err = readNextPacket(&packet)) != OK) { return err; } - ALOGV("read packet of size %d\n", packet->range_length()); + ALOGV("read packet of size %zu\n", packet->range_length()); err = verifyHeader(packet, 5); packet->release(); packet = NULL; @@ -903,7 +903,7 @@ static void extractAlbumArt( return; } - ALOGV("got flac of size %d", flacSize); + ALOGV("got flac of size %zu", flacSize); uint32_t picType; uint32_t typeLen; @@ -953,7 +953,7 @@ static void extractAlbumArt( goto exit; } - ALOGV("got image data, %d trailing bytes", + ALOGV("got image data, %zu trailing bytes", flacSize - 32 - typeLen - descLen - dataLen); fileMeta->setData( diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index af96225..8cc41e7 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -16,7 +16,9 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "StagefrightMetadataRetriever" + #include + #include #include "include/StagefrightMetadataRetriever.h" @@ -87,7 +89,7 @@ status_t StagefrightMetadataRetriever::setDataSource( int fd, int64_t offset, int64_t length) { fd = dup(fd); - ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); + ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length); mParsedMetaData = false; mMetaData.clear(); @@ -242,7 +244,7 @@ static VideoFrame *extractVideoFrameWithCodecFlags( const char *mime; CHECK(trackMeta->findCString(kKeyMIMEType, &mime)); - ALOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s", + ALOGV("thumbNailTime = %" PRId64 " us, timeUs = %" PRId64 " us, mime = %s", thumbNailTime, timeUs, mime); } } @@ -325,7 +327,7 @@ static VideoFrame *extractVideoFrameWithCodecFlags( VideoFrame *StagefrightMetadataRetriever::getFrameAtTime( int64_t timeUs, int option) { - ALOGV("getFrameAtTime: %lld us option: %d", timeUs, option); + ALOGV("getFrameAtTime: %" PRId64 " us option: %d", timeUs, option); if (mExtractor.get() == NULL) { ALOGV("no extractor."); diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index 62aea36..4e1c65c 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -16,6 +16,8 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "SurfaceMediaSource" +#include + #include #include #include @@ -179,7 +181,7 @@ status_t SurfaceMediaSource::start(MetaData *params) } status_t SurfaceMediaSource::setMaxAcquiredBufferCount(size_t count) { - ALOGV("setMaxAcquiredBufferCount(%d)", count); + ALOGV("setMaxAcquiredBufferCount(%zu)", count); Mutex::Autolock lock(mMutex); CHECK_GT(count, 1); @@ -209,7 +211,7 @@ status_t SurfaceMediaSource::stop() mFrameAvailableCondition.signal(); while (mNumPendingBuffers > 0) { - ALOGI("Still waiting for %d buffers to be returned.", + ALOGI("Still waiting for %zu buffers to be returned.", mNumPendingBuffers); #if DEBUG_PENDING_BUFFERS @@ -269,7 +271,7 @@ static void passMetadataBuffer(MediaBuffer **buffer, memcpy(data, &type, 4); memcpy(data + 4, &bufferHandle, sizeof(buffer_handle_t)); - ALOGV("handle = %p, , offset = %d, length = %d", + ALOGV("handle = %p, , offset = %zu, length = %zu", bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset()); } @@ -363,7 +365,7 @@ status_t SurfaceMediaSource::read( (*buffer)->setObserver(this); (*buffer)->add_ref(); (*buffer)->meta_data()->setInt64(kKeyTime, mCurrentTimestamp / 1000); - ALOGV("Frames encoded = %d, timestamp = %lld, time diff = %lld", + ALOGV("Frames encoded = %d, timestamp = %" PRId64 ", time diff = %" PRId64, mNumFramesEncoded, mCurrentTimestamp / 1000, mCurrentTimestamp / 1000 - prevTimeStamp / 1000); diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp index 3d2eb1f..da50c56 100644 --- a/media/libstagefright/TimedEventQueue.cpp +++ b/media/libstagefright/TimedEventQueue.cpp @@ -17,7 +17,11 @@ #undef __STRICT_ANSI__ #define __STDINT_LIMITS #define __STDC_LIMIT_MACROS + +#include #include +#include +#include //#define LOG_NDEBUG 0 #define LOG_TAG "TimedEventQueue" @@ -26,9 +30,6 @@ #include "include/TimedEventQueue.h" -#include -#include - #include #include #include @@ -258,7 +259,7 @@ void TimedEventQueue::threadEntry() { static int64_t kMaxTimeoutUs = 10000000ll; // 10 secs bool timeoutCapped = false; if (delay_us > kMaxTimeoutUs) { - ALOGW("delay_us exceeds max timeout: %lld us", delay_us); + ALOGW("delay_us exceeds max timeout: %" PRId64 " us", delay_us); // We'll never block for more than 10 secs, instead // we will split up the full timeout into chunks of diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 7ff31a1..d53051e 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -335,7 +335,7 @@ static size_t reassembleAVCC(const sp &csd0, const sp csd1, ch // there can't be another param here, so use all the rest i = csd0->size(); } - ALOGV("block at %d, last was %d", i, lastparamoffset); + ALOGV("block at %zu, last was %d", i, lastparamoffset); if (lastparamoffset > 0) { int size = i - lastparamoffset; avcc[avccidx++] = size >> 8; @@ -366,7 +366,7 @@ static size_t reassembleAVCC(const sp &csd0, const sp csd1, ch // there can't be another param here, so use all the rest i = csd1->size(); } - ALOGV("block at %d, last was %d", i, lastparamoffset); + ALOGV("block at %zu, last was %d", i, lastparamoffset); if (lastparamoffset > 0) { int size = i - lastparamoffset; avcc[avccidx++] = size >> 8; diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp index af858b9..e988f6d 100644 --- a/media/libstagefright/VBRISeeker.cpp +++ b/media/libstagefright/VBRISeeker.cpp @@ -16,6 +16,9 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "VBRISeeker" + +#include + #include #include "include/VBRISeeker.h" @@ -75,7 +78,7 @@ sp VBRISeeker::CreateFromSource( size_t entrySize = U16_AT(&vbriHeader[22]); size_t scale = U16_AT(&vbriHeader[20]); - ALOGV("%d entries, scale=%d, size_per_entry=%d", + ALOGV("%zu entries, scale=%zu, size_per_entry=%zu", numEntries, scale, entrySize); @@ -119,7 +122,7 @@ sp VBRISeeker::CreateFromSource( seeker->mSegments.push(numBytes); - ALOGV("entry #%d: %u offset 0x%016llx", i, numBytes, offset); + ALOGV("entry #%zu: %u offset 0x%016llx", i, numBytes, offset); offset += numBytes; } @@ -160,7 +163,7 @@ bool VBRISeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) { *pos += mSegments.itemAt(segmentIndex++); } - ALOGV("getOffsetForTime %lld us => 0x%016llx", *timeUs, *pos); + ALOGV("getOffsetForTime %" PRId64 " us => 0x%016llx", *timeUs, *pos); *timeUs = nowUs; diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp index fe9058b..7124fd3 100644 --- a/media/libstagefright/WAVExtractor.cpp +++ b/media/libstagefright/WAVExtractor.cpp @@ -414,7 +414,7 @@ status_t WAVSource::read( } else { pos = (seekTimeUs * mSampleRate) / 1000000 * mNumChannels * (mBitsPerSample >> 3); } - if (pos > mSize) { + if (pos > (off64_t)mSize) { pos = mSize; } mCurrentPos = pos + mOffset; diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp index dc38ea8..cabd6bd 100644 --- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp +++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp @@ -379,7 +379,7 @@ status_t SoftVPXEncoder::initEncoder() { } default: { - ALOGE("Wrong number of temporal layers %u", mTemporalLayers); + ALOGE("Wrong number of temporal layers %zu", mTemporalLayers); return UNKNOWN_ERROR; } } diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 16f6c58..67e6d7b 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -114,7 +114,7 @@ GraphicBufferSource::~GraphicBufferSource() { void GraphicBufferSource::omxExecuting() { Mutex::Autolock autoLock(mMutex); - ALOGV("--> executing; avail=%d, codec vec size=%zd", + ALOGV("--> executing; avail=%zu, codec vec size=%zd", mNumFramesAvailable, mCodecBuffers.size()); CHECK(!mExecuting); mExecuting = true; @@ -136,7 +136,7 @@ void GraphicBufferSource::omxExecuting() { } } - ALOGV("done loading initial frames, avail=%d", mNumFramesAvailable); + ALOGV("done loading initial frames, avail=%zu", mNumFramesAvailable); // If EOS has already been signaled, and there are no more frames to // submit, try to send EOS now as well. @@ -188,7 +188,7 @@ void GraphicBufferSource::omxLoaded(){ mLooper.clear(); } - ALOGV("--> loaded; avail=%d eos=%d eosSent=%d", + ALOGV("--> loaded; avail=%zu eos=%d eosSent=%d", mNumFramesAvailable, mEndOfStream, mEndOfStreamSent); // Codec is no longer executing. Discard all codec-related state. @@ -291,7 +291,7 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { if (mNumFramesAvailable) { // Fill this codec buffer. CHECK(!mEndOfStreamSent); - ALOGV("buffer freed, %d frames avail (eos=%d)", + ALOGV("buffer freed, %zu frames avail (eos=%d)", mNumFramesAvailable, mEndOfStream); fillCodecBuffer_l(); } else if (mEndOfStream) { @@ -320,7 +320,8 @@ void GraphicBufferSource::codecBufferFilled(OMX_BUFFERHEADERTYPE* header) { ssize_t index = mOriginalTimeUs.indexOfKey(header->nTimeStamp); if (index >= 0) { ALOGV("OUT timestamp: %lld -> %lld", - header->nTimeStamp, mOriginalTimeUs[index]); + static_cast(header->nTimeStamp), + static_cast(mOriginalTimeUs[index])); header->nTimeStamp = mOriginalTimeUs[index]; mOriginalTimeUs.removeItemsAt(index); } else { @@ -331,7 +332,7 @@ void GraphicBufferSource::codecBufferFilled(OMX_BUFFERHEADERTYPE* header) { } if (mOriginalTimeUs.size() > BufferQueue::NUM_BUFFER_SLOTS) { // something terribly wrong must have happened, giving up... - ALOGE("mOriginalTimeUs has too many entries (%d)", + ALOGE("mOriginalTimeUs has too many entries (%zu)", mOriginalTimeUs.size()); mMaxTimestampGapUs = -1ll; } @@ -388,12 +389,12 @@ bool GraphicBufferSource::fillCodecBuffer_l() { int cbi = findAvailableCodecBuffer_l(); if (cbi < 0) { // No buffers available, bail. - ALOGV("fillCodecBuffer_l: no codec buffers, avail now %d", + ALOGV("fillCodecBuffer_l: no codec buffers, avail now %zu", mNumFramesAvailable); return false; } - ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%d", + ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%zu", mNumFramesAvailable); BufferQueue::BufferItem item; status_t err = mConsumer->acquireBuffer(&item, 0); @@ -540,7 +541,7 @@ void GraphicBufferSource::setLatestSubmittedBuffer_l( status_t GraphicBufferSource::signalEndOfInputStream() { Mutex::Autolock autoLock(mMutex); - ALOGV("signalEndOfInputStream: exec=%d avail=%d eos=%d", + ALOGV("signalEndOfInputStream: exec=%d avail=%zu eos=%d", mExecuting, mNumFramesAvailable, mEndOfStream); if (mEndOfStream) { @@ -580,7 +581,7 @@ int64_t GraphicBufferSource::getTimestamp(const BufferQueue::BufferItem &item) { / mTimePerCaptureUs; if (nFrames <= 0) { // skip this frame as it's too close to previous capture - ALOGV("skipping frame, timeUs %lld", timeUs); + ALOGV("skipping frame, timeUs %lld", static_cast(timeUs)); return -1; } mPrevCaptureUs = mPrevCaptureUs + nFrames * mTimePerCaptureUs; @@ -588,7 +589,9 @@ int64_t GraphicBufferSource::getTimestamp(const BufferQueue::BufferItem &item) { } ALOGV("timeUs %lld, captureUs %lld, frameUs %lld", - timeUs, mPrevCaptureUs, mPrevFrameUs); + static_cast(timeUs), + static_cast(mPrevCaptureUs), + static_cast(mPrevFrameUs)); return mPrevFrameUs; } else if (mMaxTimestampGapUs > 0ll) { @@ -615,7 +618,9 @@ int64_t GraphicBufferSource::getTimestamp(const BufferQueue::BufferItem &item) { mPrevOriginalTimeUs = originalTimeUs; mPrevModifiedTimeUs = timeUs; mOriginalTimeUs.add(timeUs, originalTimeUs); - ALOGV("IN timestamp: %lld -> %lld", originalTimeUs, timeUs); + ALOGV("IN timestamp: %lld -> %lld", + static_cast(originalTimeUs), + static_cast(timeUs)); } return timeUs; @@ -723,7 +728,7 @@ int GraphicBufferSource::findMatchingCodecBuffer_l( void GraphicBufferSource::onFrameAvailable() { Mutex::Autolock autoLock(mMutex); - ALOGV("onFrameAvailable exec=%d avail=%d", + ALOGV("onFrameAvailable exec=%d avail=%zu", mExecuting, mNumFramesAvailable); if (mEndOfStream || mSuspended) { diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp index 6b6d0ab..ae3cb33 100644 --- a/media/libstagefright/omx/OMXMaster.cpp +++ b/media/libstagefright/omx/OMXMaster.cpp @@ -91,7 +91,7 @@ void OMXMaster::addPlugin(OMXPluginBase *plugin) { } if (err != OMX_ErrorNoMore) { - ALOGE("OMX plugin failed w/ error 0x%08x after registering %d " + ALOGE("OMX plugin failed w/ error 0x%08x after registering %zu " "components", err, mPluginByComponentName.size()); } } -- cgit v1.1 From 98f28cde0d5d682956b5e6b119823e7e8d40415b Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 18 Jun 2014 16:32:50 -0700 Subject: ndk: 64-bit compile warnings Change-Id: I214973a97547bf714e56e4596359cb2bd9cdea9c --- media/ndk/NdkMediaCodec.cpp | 10 ++++++---- media/ndk/NdkMediaExtractor.cpp | 4 ++-- media/ndk/NdkMediaFormat.cpp | 7 ++++--- 3 files changed, 12 insertions(+), 9 deletions(-) (limited to 'media') diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index c5d8858..ed00b72 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + //#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaCodec" @@ -257,7 +259,7 @@ uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_ if (mData->mCodec->getInputBuffers(&abufs) == 0) { size_t n = abufs.size(); if (idx >= n) { - ALOGE("buffer index %d out of range", idx); + ALOGE("buffer index %zu out of range", idx); return NULL; } if (out_size != NULL) { @@ -275,7 +277,7 @@ uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out if (mData->mCodec->getOutputBuffers(&abufs) == 0) { size_t n = abufs.size(); if (idx >= n) { - ALOGE("buffer index %d out of range", idx); + ALOGE("buffer index %zu out of range", idx); return NULL; } if (out_size != NULL) { @@ -345,7 +347,7 @@ media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, b EXPORT media_status_t AMediaCodec_releaseOutputBufferAtTime( AMediaCodec *mData, size_t idx, int64_t timestampNs) { - ALOGV("render @ %lld", timestampNs); + ALOGV("render @ %" PRId64, timestampNs); return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs)); } @@ -413,7 +415,7 @@ AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2; AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize); if (!ret) { - ALOGE("couldn't allocate %d bytes", cryptosize); + ALOGE("couldn't allocate %zu bytes", cryptosize); return NULL; } ret->numsubsamples = numsubsamples; diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp index 492e002..970a43c 100644 --- a/media/ndk/NdkMediaExtractor.cpp +++ b/media/ndk/NdkMediaExtractor.cpp @@ -133,13 +133,13 @@ AMediaFormat* AMediaExtractor_getTrackFormat(AMediaExtractor *mData, size_t idx) EXPORT media_status_t AMediaExtractor_selectTrack(AMediaExtractor *mData, size_t idx) { - ALOGV("selectTrack(%z)", idx); + ALOGV("selectTrack(%zu)", idx); return translate_error(mData->mImpl->selectTrack(idx)); } EXPORT media_status_t AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx) { - ALOGV("unselectTrack(%z)", idx); + ALOGV("unselectTrack(%zu)", idx); return translate_error(mData->mImpl->unselectTrack(idx)); } diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp index 67dc2c2..a354d58 100644 --- a/media/ndk/NdkMediaFormat.cpp +++ b/media/ndk/NdkMediaFormat.cpp @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaFormat" +#include #include "NdkMediaFormat.h" @@ -89,21 +90,21 @@ const char* AMediaFormat_toString(AMediaFormat *mData) { { int32_t val; f->findInt32(name, &val); - ret.appendFormat("int32(%d)", val); + ret.appendFormat("int32(%" PRId32 ")", val); break; } case AMessage::kTypeInt64: { int64_t val; f->findInt64(name, &val); - ret.appendFormat("int64(%lld)", val); + ret.appendFormat("int64(%" PRId64 ")", val); break; } case AMessage::kTypeSize: { size_t val; f->findSize(name, &val); - ret.appendFormat("size_t(%d)", val); + ret.appendFormat("size_t(%zu)", val); break; } case AMessage::kTypeFloat: -- cgit v1.1 From a5a103c579d5ecde233e04c00c90f4d15b216f29 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 26 Jun 2014 07:49:02 -0700 Subject: Fix AAC timestamps When playing an mpeg-2 transport stream with AAC audio, there will be more than one packet per input buffer, resulting in multiple output buffers for each input buffers. Additional timestamps needs to be generated in that case. b/15755476 Change-Id: I2df50b0cb3690eb36d56871daa1263de0028db06 --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 38 +++++++++++++++++-------- media/libstagefright/codecs/aacdec/SoftAAC2.h | 4 ++- 2 files changed, 29 insertions(+), 13 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 64bf2b6..ab30865 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -65,10 +65,9 @@ SoftAAC2::SoftAAC2( mInputBufferCount(0), mOutputBufferCount(0), mSignalledError(false), + mLastInHeader(NULL), + mCurrentInputTime(0), mOutputPortSettingsChange(NONE) { - for (unsigned int i = 0; i < kNumDelayBlocksMax; i++) { - mAnchorTimeUs[i] = 0; - } initPorts(); CHECK_EQ(initDecoder(), (status_t)OK); } @@ -496,14 +495,11 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { } else { mEndOfInput = false; } - if (inHeader->nOffset == 0) { // TODO: does nOffset != 0 happen? - mAnchorTimeUs[mInputBufferCount % kNumDelayBlocksMax] = - inHeader->nTimeStamp; - } if (inHeader->nFilledLen == 0) { inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; @@ -568,6 +564,18 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { INT prevSampleRate = mStreamInfo->sampleRate; INT prevNumChannels = mStreamInfo->numChannels; + if (inHeader != mLastInHeader) { + mLastInHeader = inHeader; + mCurrentInputTime = inHeader->nTimeStamp; + } else { + if (mStreamInfo->sampleRate) { + mCurrentInputTime += mStreamInfo->aacSamplesPerFrame * + 1000000ll / mStreamInfo->sampleRate; + } else { + ALOGW("no sample rate yet"); + } + } + mAnchorTimes.add(mCurrentInputTime); aacDecoder_Fill(mAACDecoder, inBuffer, inBufferLength, @@ -671,6 +679,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { inInfo->mOwnedByUs = false; mInputBufferCount++; inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; @@ -687,11 +696,12 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { inInfo->mOwnedByUs = false; mInputBufferCount++; inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; } else { - ALOGW("inHeader->nFilledLen = %d", inHeader->nFilledLen); + ALOGV("inHeader->nFilledLen = %d", inHeader->nFilledLen); } } } @@ -779,8 +789,8 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { outHeader->nFlags = 0; } - outHeader->nTimeStamp = mAnchorTimeUs[mOutputBufferCount - % kNumDelayBlocksMax]; + outHeader->nTimeStamp = mAnchorTimes.isEmpty() ? 0 : mAnchorTimes.itemAt(0); + mAnchorTimes.removeAt(0); mOutputBufferCount++; outInfo->mOwnedByUs = false; @@ -820,8 +830,8 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { outHeader->nFilledLen = 0; outHeader->nFlags = OMX_BUFFERFLAG_EOS; - outHeader->nTimeStamp = mAnchorTimeUs[mOutputBufferCount - % kNumDelayBlocksMax]; + outHeader->nTimeStamp = mAnchorTimes.itemAt(0); + mAnchorTimes.removeAt(0); mOutputBufferCount++; outInfo->mOwnedByUs = false; @@ -842,6 +852,8 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { // depend on fragments from the last one decoded. // drain all existing data drainDecoder(); + mAnchorTimes.clear(); + mLastInHeader = NULL; } else { while (outputDelayRingBufferSamplesAvailable() > 0) { int32_t ns = outputDelayRingBufferGetSamples(0, @@ -896,6 +908,8 @@ void SoftAAC2::onReset() { mOutputDelayRingBufferReadPos = 0; mEndOfInput = false; mEndOfOutput = false; + mAnchorTimes.clear(); + mLastInHeader = NULL; // To make the codec behave the same before and after a reset, we need to invalidate the // streaminfo struct. This does that: diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h index 5cde03a..865bd15 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.h +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h @@ -58,7 +58,9 @@ private: size_t mInputBufferCount; size_t mOutputBufferCount; bool mSignalledError; - int64_t mAnchorTimeUs[kNumDelayBlocksMax]; + OMX_BUFFERHEADERTYPE *mLastInHeader; + int64_t mCurrentInputTime; + Vector mAnchorTimes; CDrcPresModeWrapper mDrcWrap; -- cgit v1.1 From 632740c58119a132ce19f6d498e39c5c3773971a Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 26 Jun 2014 13:03:47 -0700 Subject: HLS: do not discard packets when queuing explicit discontinuity in case of explicit discontinuity (#EXT-X-DISCONTINUITY tag in the playlist), do not discard packets that's already queued. (when seeking, the old fetcher will be discarded so this won't affect seeking case.) Bug: 15020526 Change-Id: I5d3fc489df35e3bc44acb1ee7851571cb99cb56b --- .../nuplayer/GenericSource.cpp | 8 +++++-- .../libmediaplayerservice/nuplayer/RTSPSource.cpp | 5 +++- media/libstagefright/httplive/PlaylistFetcher.cpp | 26 ++++++++++----------- media/libstagefright/mpeg2ts/ATSParser.cpp | 2 +- .../libstagefright/mpeg2ts/AnotherPacketSource.cpp | 27 ++++++++++++---------- media/libstagefright/mpeg2ts/AnotherPacketSource.h | 4 +++- 6 files changed, 41 insertions(+), 31 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 5cf9238..388f77a 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -272,7 +272,9 @@ void NuPlayer::GenericSource::readBuffer( if (seeking) { track->mPackets->queueDiscontinuity( - ATSParser::DISCONTINUITY_SEEK, NULL); + ATSParser::DISCONTINUITY_SEEK, + NULL, + true /* discard */); } track->mPackets->queueAccessUnit(buffer); @@ -280,7 +282,9 @@ void NuPlayer::GenericSource::readBuffer( } else if (err == INFO_FORMAT_CHANGED) { #if 0 track->mPackets->queueDiscontinuity( - ATSParser::DISCONTINUITY_FORMATCHANGE, NULL); + ATSParser::DISCONTINUITY_FORMATCHANGE, + NULL, + false /* discard */); #endif } else { track->mPackets->signalEOS(err); diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index 94800ba..2338b23 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -505,7 +505,10 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp &msg) { TrackInfo *info = &mTracks.editItemAt(trackIndex); sp source = info->mSource; if (source != NULL) { - source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL); + source->queueDiscontinuity( + ATSParser::DISCONTINUITY_SEEK, + NULL, + true /* discard */); } break; diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 2af0998..10437c9 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -588,7 +588,10 @@ void PlaylistFetcher::notifyError(status_t err) { void PlaylistFetcher::queueDiscontinuity( ATSParser::DiscontinuityType type, const sp &extra) { for (size_t i = 0; i < mPacketSources.size(); ++i) { - mPacketSources.valueAt(i)->queueDiscontinuity(type, extra); + // do not discard buffer upon #EXT-X-DISCONTINUITY tag + // (seek will discard buffer by abandoning old fetchers) + mPacketSources.valueAt(i)->queueDiscontinuity( + type, extra, false /* discard */); } } @@ -723,8 +726,7 @@ void PlaylistFetcher::onDownloadNext() { firstSeqNumberInPlaylist = 0; } - bool seekDiscontinuity = false; - bool explicitDiscontinuity = false; + bool discontinuity = false; const int32_t lastSeqNumberInPlaylist = firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1; @@ -792,7 +794,7 @@ void PlaylistFetcher::onDownloadNext() { if (mSeqNumber < firstSeqNumberInPlaylist) { mSeqNumber = firstSeqNumberInPlaylist; } - explicitDiscontinuity = true; + discontinuity = true; // fall through } else { @@ -817,7 +819,7 @@ void PlaylistFetcher::onDownloadNext() { int32_t val; if (itemMeta->findInt32("discontinuity", &val) && val != 0) { - explicitDiscontinuity = true; + discontinuity = true; } int64_t range_offset, range_length; @@ -877,7 +879,7 @@ void PlaylistFetcher::onDownloadNext() { return; } - if (mStartup || seekDiscontinuity || explicitDiscontinuity) { + if (mStartup || discontinuity) { // Signal discontinuity. if (mPlaylist->isComplete() || mPlaylist->isEvent()) { @@ -887,18 +889,14 @@ void PlaylistFetcher::onDownloadNext() { mNextPTSTimeUs = getSegmentStartTimeUs(mSeqNumber); } - if (seekDiscontinuity || explicitDiscontinuity) { - ALOGI("queueing discontinuity (seek=%d, explicit=%d)", - seekDiscontinuity, explicitDiscontinuity); + if (discontinuity) { + ALOGI("queueing discontinuity (explicit=%d)", discontinuity); queueDiscontinuity( - explicitDiscontinuity - ? ATSParser::DISCONTINUITY_FORMATCHANGE - : ATSParser::DISCONTINUITY_SEEK, + ATSParser::DISCONTINUITY_FORMATCHANGE, NULL /* extra */); - seekDiscontinuity = false; - explicitDiscontinuity = false; + discontinuity = false; } } diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index 338e899..3d241e0 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -669,7 +669,7 @@ void ATSParser::Stream::signalDiscontinuity( } if (mSource != NULL) { - mSource->queueDiscontinuity(type, extra); + mSource->queueDiscontinuity(type, extra, true); } } diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index 021b640..871824a 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -217,22 +217,25 @@ void AnotherPacketSource::clear() { void AnotherPacketSource::queueDiscontinuity( ATSParser::DiscontinuityType type, - const sp &extra) { + const sp &extra, + bool discard) { Mutex::Autolock autoLock(mLock); - // Leave only discontinuities in the queue. - List >::iterator it = mBuffers.begin(); - while (it != mBuffers.end()) { - sp oldBuffer = *it; + if (discard) { + // Leave only discontinuities in the queue. + List >::iterator it = mBuffers.begin(); + while (it != mBuffers.end()) { + sp oldBuffer = *it; + + int32_t oldDiscontinuityType; + if (!oldBuffer->meta()->findInt32( + "discontinuity", &oldDiscontinuityType)) { + it = mBuffers.erase(it); + continue; + } - int32_t oldDiscontinuityType; - if (!oldBuffer->meta()->findInt32( - "discontinuity", &oldDiscontinuityType)) { - it = mBuffers.erase(it); - continue; + ++it; } - - ++it; } mEOSResult = OK; diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h index 9b193a2..06c49bd 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h @@ -54,7 +54,9 @@ struct AnotherPacketSource : public MediaSource { void queueAccessUnit(const sp &buffer); void queueDiscontinuity( - ATSParser::DiscontinuityType type, const sp &extra); + ATSParser::DiscontinuityType type, + const sp &extra, + bool discard); void signalEOS(status_t result); -- cgit v1.1 From 3a8d3eae3899f8923e3386aaa015b24ef6739489 Mon Sep 17 00:00:00 2001 From: Sungsoo Lim Date: Mon, 23 Jun 2014 11:38:04 +0900 Subject: Restore the LOOPING flag in onAudioTearDownEvent Bug: 15728572 Change-Id: Ib8d118a148a7bb74531c8c025dae479c0a86efcb --- media/libstagefright/AwesomePlayer.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'media') diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 63799e1..cd05c54 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -2949,6 +2949,7 @@ void AwesomePlayer::onAudioTearDownEvent() { sp savedHTTPService = mHTTPService; + bool wasLooping = mFlags & LOOPING; // Reset and recreate reset_l(); @@ -2967,6 +2968,9 @@ void AwesomePlayer::onAudioTearDownEvent() { // a MEDIA_ERROR to the client and abort the prepare mFlags |= PREPARE_CANCELLED; } + if (wasLooping) { + mFlags |= LOOPING; + } mAudioTearDown = true; mIsAsyncPrepare = true; -- cgit v1.1 From d9d7fa0873796ac661c44a7fcd6ad5ff697ff01f Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 24 Jun 2014 08:01:46 -0700 Subject: Support for audio attributes on audio output of media player Change-Id: Iae4995c98e64add1ab9e6c8ae6501515032755f5 --- media/libmedia/AudioTrack.cpp | 12 ++- media/libmedia/mediaplayer.cpp | 22 +++++ media/libmediaplayerservice/MediaPlayerService.cpp | 108 +++++++++++++++++++-- media/libmediaplayerservice/MediaPlayerService.h | 8 +- 4 files changed, 137 insertions(+), 13 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 898d58d..b5c9125 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -124,7 +124,8 @@ AudioTrack::AudioTrack( transfer_type transferType, const audio_offload_info_t *offloadInfo, int uid, - pid_t pid) + pid_t pid, + const audio_attributes_t* pAttributes) : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), @@ -134,7 +135,7 @@ AudioTrack::AudioTrack( mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, - offloadInfo, uid, pid, NULL /*no audio attributes*/); + offloadInfo, uid, pid, pAttributes); } AudioTrack::AudioTrack( @@ -151,7 +152,8 @@ AudioTrack::AudioTrack( transfer_type transferType, const audio_offload_info_t *offloadInfo, int uid, - pid_t pid) + pid_t pid, + const audio_attributes_t* pAttributes) : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), @@ -161,7 +163,7 @@ AudioTrack::AudioTrack( mStatus = set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags, cbf, user, notificationFrames, sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, - uid, pid, NULL /*no audio attributes*/); + uid, pid, pAttributes); } AudioTrack::~AudioTrack() @@ -205,7 +207,7 @@ status_t AudioTrack::set( const audio_offload_info_t *offloadInfo, int uid, pid_t pid, - audio_attributes_t* pAttributes) + const audio_attributes_t* pAttributes) { ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, " "flags #%x, notificationFrames %u, sessionId %d, transferType %d", diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 406f9f2..889bd7f 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -624,10 +624,32 @@ status_t MediaPlayer::attachAuxEffect(int effectId) return mPlayer->attachAuxEffect(effectId); } +// always call with lock held +status_t MediaPlayer::checkStateForKeySet_l(int key) +{ + switch(key) { + case KEY_PARAMETER_AUDIO_ATTRIBUTES: + if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | + MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) { + // Can't change the audio attributes after prepare + ALOGE("trying to set audio attributes called in state %d", mCurrentState); + return INVALID_OPERATION; + } + break; + default: + // parameter doesn't require player state check + break; + } + return OK; +} + status_t MediaPlayer::setParameter(int key, const Parcel& request) { ALOGV("MediaPlayer::setParameter(%d)", key); Mutex::Autolock _l(mLock); + if (checkStateForKeySet_l(key) != OK) { + return INVALID_OPERATION; + } if (mPlayer != NULL) { return mPlayer->setParameter(key, request); } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 76632a7..7218467 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -186,6 +186,60 @@ bool findMetadata(const Metadata::Filter& filter, const int32_t val) } // anonymous namespace +namespace { +using android::Parcel; +using android::String16; + +// marshalling tag indicating flattened utf16 tags +// keep in sync with frameworks/base/media/java/android/media/AudioAttributes.java +const int32_t kAudioAttributesMarshallTagFlattenTags = 1; + +// Audio attributes format in a parcel: +// +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | usage | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | content_type | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | flags | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | kAudioAttributesMarshallTagFlattenTags | // ignore tags if not found +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | flattened tags in UTF16 | +// | ... | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// @param p Parcel that contains audio attributes. +// @param[out] attributes On exit points to an initialized audio_attributes_t structure +// @param[out] status On exit contains the status code to be returned. +void unmarshallAudioAttributes(const Parcel& parcel, audio_attributes_t *attributes) +{ + attributes->usage = (audio_usage_t) parcel.readInt32(); + attributes->content_type = (audio_content_type_t) parcel.readInt32(); + attributes->flags = (audio_flags_mask_t) parcel.readInt32(); + const bool hasFlattenedTag = (parcel.readInt32() == kAudioAttributesMarshallTagFlattenTags); + if (hasFlattenedTag) { + // the tags are UTF16, convert to UTF8 + String16 tags = parcel.readString16(); + ssize_t realTagSize = utf16_to_utf8_length(tags.string(), tags.size()); + if (realTagSize <= 0) { + strcpy(attributes->tags, ""); + } else { + // copy the flattened string into the attributes as the destination for the conversion: + // copying array size -1, array for tags was calloc'd, no need to NULL-terminate it + size_t tagSize = realTagSize > AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 ? + AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 : realTagSize; + utf16_to_utf8(tags.string(), tagSize, attributes->tags); + } + } else { + ALOGE("unmarshallAudioAttributes() received unflattened tags, ignoring tag values"); + strcpy(attributes->tags, ""); + } +} +} // anonymous namespace + + namespace android { static bool checkPermission(const char* permissionString) { @@ -508,6 +562,7 @@ MediaPlayerService::Client::Client( mAudioSessionId = audioSessionId; mUID = uid; mRetransmitEndpointValid = false; + mAudioAttributes = NULL; #if CALLBACK_ANTAGONIZER ALOGD("create Antagonizer"); @@ -522,6 +577,9 @@ MediaPlayerService::Client::~Client() wp client(this); disconnect(); mService->removeClient(client); + if (mAudioAttributes != NULL) { + free(mAudioAttributes); + } } void MediaPlayerService::Client::disconnect() @@ -587,7 +645,7 @@ sp MediaPlayerService::Client::setDataSource_pre( if (!p->hardwareOutput()) { mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(), - mPid); + mPid, mAudioAttributes); static_cast(p.get())->setAudioSink(mAudioOutput); } @@ -968,6 +1026,22 @@ status_t MediaPlayerService::Client::setAudioStreamType(audio_stream_type_t type return NO_ERROR; } +status_t MediaPlayerService::Client::setAudioAttributes_l(const Parcel &parcel) +{ + if (mAudioAttributes != NULL) { free(mAudioAttributes); } + mAudioAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t)); + unmarshallAudioAttributes(parcel, mAudioAttributes); + + ALOGV("setAudioAttributes_l() usage=%d content=%d flags=0x%x tags=%s", + mAudioAttributes->usage, mAudioAttributes->content_type, mAudioAttributes->flags, + mAudioAttributes->tags); + + if (mAudioOutput != 0) { + mAudioOutput->setAudioAttributes(mAudioAttributes); + } + return NO_ERROR; +} + status_t MediaPlayerService::Client::setLooping(int loop) { ALOGV("[%d] setLooping(%d)", mConnId, loop); @@ -1016,9 +1090,17 @@ status_t MediaPlayerService::Client::attachAuxEffect(int effectId) status_t MediaPlayerService::Client::setParameter(int key, const Parcel &request) { ALOGV("[%d] setParameter(%d)", mConnId, key); - sp p = getPlayer(); - if (p == 0) return UNKNOWN_ERROR; - return p->setParameter(key, request); + switch (key) { + case KEY_PARAMETER_AUDIO_ATTRIBUTES: + { + Mutex::Autolock l(mLock); + return setAudioAttributes_l(request); + } + default: + sp p = getPlayer(); + if (p == 0) { return UNKNOWN_ERROR; } + return p->setParameter(key, request); + } } status_t MediaPlayerService::Client::getParameter(int key, Parcel *reply) { @@ -1300,7 +1382,8 @@ Exit: #undef LOG_TAG #define LOG_TAG "AudioSink" -MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid) +MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid, + const audio_attributes_t* attr) : mCallback(NULL), mCallbackCookie(NULL), mCallbackData(NULL), @@ -1319,6 +1402,7 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid) mAuxEffectId = 0; mSendLevel = 0.0; setMinBufferCount(); + mAttributes = attr; } MediaPlayerService::AudioOutput::~AudioOutput() @@ -1408,6 +1492,10 @@ String8 MediaPlayerService::AudioOutput::getParameters(const String8& keys) return mTrack->getParameters(keys); } +void MediaPlayerService::AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) { + mAttributes = attributes; +} + void MediaPlayerService::AudioOutput::deleteRecycledTrack() { ALOGV("deleteRecycledTrack"); @@ -1557,7 +1645,8 @@ status_t MediaPlayerService::AudioOutput::open( AudioTrack::TRANSFER_CALLBACK, offloadInfo, mUid, - mPid); + mPid, + mAttributes); } else { t = new AudioTrack( mStreamType, @@ -1573,13 +1662,18 @@ status_t MediaPlayerService::AudioOutput::open( AudioTrack::TRANSFER_DEFAULT, NULL, // offload info mUid, - mPid); + mPid, + mAttributes); } if ((t == 0) || (t->initCheck() != NO_ERROR)) { ALOGE("Unable to create audio track"); delete newcbd; return NO_INIT; + } else { + // successful AudioTrack initialization implies a legacy stream type was generated + // from the audio attributes + mStreamType = t->streamType(); } } diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 448f27a..2eca6a0 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -72,7 +72,8 @@ class MediaPlayerService : public BnMediaPlayerService class CallbackData; public: - AudioOutput(int sessionId, int uid, int pid); + AudioOutput(int sessionId, int uid, int pid, + const audio_attributes_t * attr); virtual ~AudioOutput(); virtual bool ready() const { return mTrack != 0; } @@ -104,6 +105,7 @@ class MediaPlayerService : public BnMediaPlayerService void setAudioStreamType(audio_stream_type_t streamType) { mStreamType = streamType; } virtual audio_stream_type_t getAudioStreamType() const { return mStreamType; } + void setAudioAttributes(const audio_attributes_t * attributes); void setVolume(float left, float right); virtual status_t setPlaybackRatePermille(int32_t ratePermille); @@ -133,6 +135,7 @@ class MediaPlayerService : public BnMediaPlayerService CallbackData * mCallbackData; uint64_t mBytesWritten; audio_stream_type_t mStreamType; + const audio_attributes_t *mAttributes; float mLeftVolume; float mRightVolume; int32_t mPlaybackRatePermille; @@ -410,6 +413,8 @@ private: // Disconnect from the currently connected ANativeWindow. void disconnectNativeWindow(); + status_t setAudioAttributes_l(const Parcel &request); + mutable Mutex mLock; sp mPlayer; sp mService; @@ -420,6 +425,7 @@ private: bool mLoop; int32_t mConnId; int mAudioSessionId; + audio_attributes_t * mAudioAttributes; uid_t mUID; sp mConnectedWindow; sp mConnectedWindowBinder; -- cgit v1.1 From 7df8c0b799d8f52d6386e03313286dbd7d5cdc7c Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 3 Jul 2014 12:23:29 -0700 Subject: IAudioFlinger::openRecord now suggests notificationFrames Change-Id: I08885cc381d03c522a23289e74f0e1ed46563863 --- media/libmedia/AudioRecord.cpp | 5 +++++ media/libmedia/IAudioFlinger.cpp | 8 ++++++++ 2 files changed, 13 insertions(+) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index f865d38..3ee5809 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -495,6 +495,10 @@ status_t AudioRecord::openRecord_l(size_t epoch) size_t temp = frameCount; // temp may be replaced by a revised value of frameCount, // but we will still need the original value also int originalSessionId = mSessionId; + + // The notification frame count is the period between callbacks, as suggested by the server. + size_t notificationFrames; + sp iMem; // for cblk sp bufferMem; sp record = audioFlinger->openRecord(input, @@ -504,6 +508,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) &trackFlags, tid, &mSessionId, + ¬ificationFrames, iMem, bufferMem, &status); diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 687fa76..5cf42f7 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -175,6 +175,7 @@ public: track_flags_t *flags, pid_t tid, int *sessionId, + size_t *notificationFrames, sp& cblk, sp& buffers, status_t *status) @@ -214,6 +215,10 @@ public: if (sessionId != NULL) { *sessionId = lSessionId; } + size_t lNotificationFrames = (size_t) reply.readInt64(); + if (notificationFrames != NULL) { + *notificationFrames = lNotificationFrames; + } lStatus = reply.readInt32(); record = interface_cast(reply.readStrongBinder()); cblk = interface_cast(reply.readStrongBinder()); @@ -959,16 +964,19 @@ status_t BnAudioFlinger::onTransact( track_flags_t flags = (track_flags_t) data.readInt32(); pid_t tid = (pid_t) data.readInt32(); int sessionId = data.readInt32(); + size_t notificationFrames = 0; sp cblk; sp buffers; status_t status; sp record = openRecord(input, sampleRate, format, channelMask, &frameCount, &flags, tid, &sessionId, + ¬ificationFrames, cblk, buffers, &status); LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR)); reply->writeInt64(frameCount); reply->writeInt32(flags); reply->writeInt32(sessionId); + reply->writeInt64(notificationFrames); reply->writeInt32(status); reply->writeStrongBinder(record->asBinder()); reply->writeStrongBinder(cblk->asBinder()); -- cgit v1.1 From 05ca3bfb847ff3c1980f2f0922a4d494c0e7ebab Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 7 Jul 2014 10:30:54 -0700 Subject: stagefright: create CodecBase interface (abstract class) This abstracts out the ACodec dependency in MediaCodec. Bug: 11784825 Change-Id: I0aa8b56c6414865fd4b0646e2c5bd1b62d030682 --- media/libstagefright/Android.mk | 1 + media/libstagefright/CodecBase.cpp | 38 ++++++++++++++++++++++ .../foundation/AHierarchicalStateMachine.cpp | 2 +- 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 media/libstagefright/CodecBase.cpp (limited to 'media') diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 11c5970..99c8e9f 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -15,6 +15,7 @@ LOCAL_SRC_FILES:= \ CameraSource.cpp \ CameraSourceTimeLapse.cpp \ ClockEstimator.cpp \ + CodecBase.cpp \ DataSource.cpp \ DataURISource.cpp \ DRMExtractor.cpp \ diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp new file mode 100644 index 0000000..f729d4d --- /dev/null +++ b/media/libstagefright/CodecBase.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "CodecBase" + +#include + +#include + +namespace android { + +CodecBase::CodecBase() { +} + +CodecBase::~CodecBase() { +} + +CodecBase::PortDescription::PortDescription() { +} + +CodecBase::PortDescription::~PortDescription() { +} + +} // namespace android diff --git a/media/libstagefright/foundation/AHierarchicalStateMachine.cpp b/media/libstagefright/foundation/AHierarchicalStateMachine.cpp index f7a00d8..5f7c70d 100644 --- a/media/libstagefright/foundation/AHierarchicalStateMachine.cpp +++ b/media/libstagefright/foundation/AHierarchicalStateMachine.cpp @@ -51,7 +51,7 @@ AHierarchicalStateMachine::AHierarchicalStateMachine() { AHierarchicalStateMachine::~AHierarchicalStateMachine() { } -void AHierarchicalStateMachine::onMessageReceived(const sp &msg) { +void AHierarchicalStateMachine::handleMessage(const sp &msg) { sp save = mState; sp cur = mState; -- cgit v1.1 From 92cd05b8f2e994aabcdda5d7454c96a707dc9579 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 7 Jul 2014 14:55:18 -0700 Subject: stagefright: update MediaCodec to use CodecBase instead of ACodec MediaCodec still creates an ACodec instance in init() Bug: 11784825 Change-Id: Ifba1e1582c788056c0e59afdf68cd3a504ab3679 --- media/libstagefright/MediaCodec.cpp | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 14c8028..6e3d6f8 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -67,7 +67,7 @@ sp MediaCodec::CreateByComponentName( MediaCodec::MediaCodec(const sp &looper) : mState(UNINITIALIZED), mLooper(looper), - mCodec(new ACodec), + mCodec(NULL), mReplyID(0), mFlags(0), mSoftRenderer(NULL), @@ -103,6 +103,7 @@ status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) { // quickly, violating the OpenMAX specs, until that is remedied // we need to invest in an extra looper to free the main event // queue. + mCodec = new ACodec; bool needDedicatedLooper = false; if (nameIsType && !strncasecmp(name, "video/", 6)) { needDedicatedLooper = true; @@ -541,7 +542,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->findInt32("what", &what)); switch (what) { - case ACodec::kWhatError: + case CodecBase::kWhatError: { int32_t omxError, internalError; CHECK(msg->findInt32("omx-error", &omxError)); @@ -638,7 +639,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } - case ACodec::kWhatComponentAllocated: + case CodecBase::kWhatComponentAllocated: { CHECK_EQ(mState, INITIALIZING); setState(INITIALIZED); @@ -661,7 +662,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } - case ACodec::kWhatComponentConfigured: + case CodecBase::kWhatComponentConfigured: { CHECK_EQ(mState, CONFIGURING); setState(CONFIGURED); @@ -676,9 +677,9 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } - case ACodec::kWhatInputSurfaceCreated: + case CodecBase::kWhatInputSurfaceCreated: { - // response to ACodec::kWhatCreateInputSurface + // response to initiateCreateInputSurface() status_t err = NO_ERROR; sp response = new AMessage(); if (!msg->findInt32("err", &err)) { @@ -694,9 +695,9 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } - case ACodec::kWhatSignaledInputEOS: + case CodecBase::kWhatSignaledInputEOS: { - // response to ACodec::kWhatSignalEndOfInputStream + // response to signalEndOfInputStream() sp response = new AMessage(); status_t err; if (msg->findInt32("err", &err)) { @@ -707,7 +708,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { } - case ACodec::kWhatBuffersAllocated: + case CodecBase::kWhatBuffersAllocated: { int32_t portIndex; CHECK(msg->findInt32("portIndex", &portIndex)); @@ -725,8 +726,8 @@ void MediaCodec::onMessageReceived(const sp &msg) { sp obj; CHECK(msg->findObject("portDesc", &obj)); - sp portDesc = - static_cast(obj.get()); + sp portDesc = + static_cast(obj.get()); size_t numBuffers = portDesc->countBuffers(); @@ -759,7 +760,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } - case ACodec::kWhatOutputFormatChanged: + case CodecBase::kWhatOutputFormatChanged: { ALOGV("codec output format changed"); @@ -810,7 +811,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } - case ACodec::kWhatFillThisBuffer: + case CodecBase::kWhatFillThisBuffer: { /* size_t index = */updateBuffers(kPortIndexInput, msg); @@ -857,7 +858,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } - case ACodec::kWhatDrainThisBuffer: + case CodecBase::kWhatDrainThisBuffer: { /* size_t index = */updateBuffers(kPortIndexOutput, msg); @@ -908,14 +909,14 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } - case ACodec::kWhatEOS: + case CodecBase::kWhatEOS: { // We already notify the client of this by using the // corresponding flag in "onOutputBufferReady". break; } - case ACodec::kWhatShutdownCompleted: + case CodecBase::kWhatShutdownCompleted: { if (mState == STOPPING) { setState(INITIALIZED); @@ -928,7 +929,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } - case ACodec::kWhatFlushCompleted: + case CodecBase::kWhatFlushCompleted: { CHECK_EQ(mState, FLUSHING); setState(STARTED); -- cgit v1.1 From d8cbe4a024ef54adf043b6ea31fa22271b8b2c51 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 7 Jul 2014 15:08:24 -0700 Subject: stagefright: update ACodec to use CodecBase enumerations directly Bug: 11784825 Change-Id: I9f322b78b52bfcc5040fda951486df4354cdba4f --- media/libstagefright/ACodec.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 2a583d0..9c64d72 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -547,7 +547,7 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { } sp notify = mNotify->dup(); - notify->setInt32("what", ACodec::kWhatBuffersAllocated); + notify->setInt32("what", CodecBase::kWhatBuffersAllocated); notify->setInt32("portIndex", portIndex); @@ -3005,7 +3005,7 @@ void ACodec::sendFormatChange(const sp &reply) { void ACodec::signalError(OMX_ERRORTYPE error, status_t internalError) { sp notify = mNotify->dup(); - notify->setInt32("what", ACodec::kWhatError); + notify->setInt32("what", CodecBase::kWhatError); notify->setInt32("omx-error", error); notify->setInt32("err", internalError); notify->post(); @@ -3398,7 +3398,7 @@ void ACodec::BaseState::postFillThisBuffer(BufferInfo *info) { CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US); sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatFillThisBuffer); + notify->setInt32("what", CodecBase::kWhatFillThisBuffer); notify->setInt32("buffer-id", info->mBufferID); info->mData->meta()->clear(); @@ -3693,7 +3693,7 @@ bool ACodec::BaseState::onOMXFillBufferDone( info->mData->meta()->setInt64("timeUs", timeUs); sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatDrainThisBuffer); + notify->setInt32("what", CodecBase::kWhatDrainThisBuffer); notify->setInt32("buffer-id", info->mBufferID); notify->setBuffer("buffer", info->mData); notify->setInt32("flags", flags); @@ -3710,7 +3710,7 @@ bool ACodec::BaseState::onOMXFillBufferDone( ALOGV("[%s] saw output EOS", mCodec->mComponentName.c_str()); sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatEOS); + notify->setInt32("what", CodecBase::kWhatEOS); notify->setInt32("err", mCodec->mInputEOSResult); notify->post(); @@ -3891,7 +3891,7 @@ bool ACodec::UninitializedState::onMessageReceived(const sp &msg) { "cannot keep component allocated on shutdown in Uninitialized state"); sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatShutdownCompleted); + notify->setInt32("what", CodecBase::kWhatShutdownCompleted); notify->post(); handled = true; @@ -3901,7 +3901,7 @@ bool ACodec::UninitializedState::onMessageReceived(const sp &msg) { case ACodec::kWhatFlush: { sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatFlushCompleted); + notify->setInt32("what", CodecBase::kWhatFlushCompleted); notify->post(); handled = true; @@ -4023,7 +4023,7 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp &msg) { { sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatComponentAllocated); + notify->setInt32("what", CodecBase::kWhatComponentAllocated); notify->setString("componentName", mCodec->mComponentName.c_str()); notify->post(); } @@ -4073,7 +4073,7 @@ void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) { if (mCodec->mExplicitShutdown) { sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatShutdownCompleted); + notify->setInt32("what", CodecBase::kWhatShutdownCompleted); notify->post(); mCodec->mExplicitShutdown = false; } @@ -4120,7 +4120,7 @@ bool ACodec::LoadedState::onMessageReceived(const sp &msg) { case ACodec::kWhatFlush: { sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatFlushCompleted); + notify->setInt32("what", CodecBase::kWhatFlushCompleted); notify->post(); handled = true; @@ -4169,7 +4169,7 @@ bool ACodec::LoadedState::onConfigureComponent( { sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatComponentConfigured); + notify->setInt32("what", CodecBase::kWhatComponentConfigured); notify->setMessage("input-format", mCodec->mInputFormat); notify->setMessage("output-format", mCodec->mOutputFormat); notify->post(); @@ -4183,7 +4183,7 @@ void ACodec::LoadedState::onCreateInputSurface( ALOGV("onCreateInputSurface"); sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatInputSurfaceCreated); + notify->setInt32("what", CodecBase::kWhatInputSurfaceCreated); sp bufferProducer; status_t err; @@ -4337,7 +4337,7 @@ bool ACodec::LoadedToIdleState::onMessageReceived(const sp &msg) { { // We haven't even started yet, so we're flushed alright... sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatFlushCompleted); + notify->setInt32("what", CodecBase::kWhatFlushCompleted); notify->post(); return true; } @@ -4398,7 +4398,7 @@ bool ACodec::IdleToExecutingState::onMessageReceived(const sp &msg) { { // We haven't even started yet, so we're flushed alright... sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatFlushCompleted); + notify->setInt32("what", CodecBase::kWhatFlushCompleted); notify->post(); return true; @@ -4701,7 +4701,7 @@ status_t ACodec::setParameters(const sp ¶ms) { void ACodec::onSignalEndOfInputStream() { sp notify = mNotify->dup(); - notify->setInt32("what", ACodec::kWhatSignaledInputEOS); + notify->setInt32("what", CodecBase::kWhatSignaledInputEOS); status_t err = mOMX->signalEndOfInputStream(mNode); if (err != OK) { @@ -5131,7 +5131,7 @@ void ACodec::FlushingState::changeStateIfWeOwnAllBuffers() { mCodec->waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs(); sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatFlushCompleted); + notify->setInt32("what", CodecBase::kWhatFlushCompleted); notify->post(); mCodec->mPortEOS[kPortIndexInput] = -- cgit v1.1 From 862f8455eaacc1ffb5d8911f0bc7ecc3cf7ec46c Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 26 Jun 2014 19:55:23 -0700 Subject: handle emulation_prevention_three_bytes for AVC bug: 15917805 Change-Id: I824fe7eea807f8faba6b149c31890b7a5df87825 --- .../nuplayer/NuPlayerDecoder.cpp | 4 +- media/libstagefright/foundation/ABitReader.cpp | 68 ++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 5abfb71..dd73cc4 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -674,9 +674,9 @@ bool NuPlayer::CCDecoder::extractFromSEI(const sp &accessUnit) { bool hasCC = false; - ABitReader br(sei->data() + 1, sei->size() - 1); + NALBitReader br(sei->data() + 1, sei->size() - 1); // sei_message() - while (br.numBitsLeft() >= 16) { // at least 16-bit for sei_message() + while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message() uint32_t payload_type = 0; size_t payload_size = 0; uint8_t last_byte; diff --git a/media/libstagefright/foundation/ABitReader.cpp b/media/libstagefright/foundation/ABitReader.cpp index 5499c32..beb5cc0 100644 --- a/media/libstagefright/foundation/ABitReader.cpp +++ b/media/libstagefright/foundation/ABitReader.cpp @@ -27,6 +27,9 @@ ABitReader::ABitReader(const uint8_t *data, size_t size) mNumBitsLeft(0) { } +ABitReader::~ABitReader() { +} + void ABitReader::fillReservoir() { CHECK_GT(mSize, 0u); @@ -99,4 +102,69 @@ const uint8_t *ABitReader::data() const { return mData - (mNumBitsLeft + 7) / 8; } +NALBitReader::NALBitReader(const uint8_t *data, size_t size) + : ABitReader(data, size), + mNumZeros(0) { +} + +bool NALBitReader::atLeastNumBitsLeft(size_t n) const { + // check against raw size and reservoir bits first + size_t numBits = numBitsLeft(); + if (n > numBits) { + return false; + } + + ssize_t numBitsRemaining = n - mNumBitsLeft; + + size_t size = mSize; + const uint8_t *data = mData; + int32_t numZeros = mNumZeros; + while (size > 0 && numBitsRemaining > 0) { + bool isEmulationPreventionByte = (numZeros >= 2 && *data == 3); + + if (*data == 0) { + ++numZeros; + } else { + numZeros = 0; + } + + if (!isEmulationPreventionByte) { + numBitsRemaining -= 8; + } + + ++data; + --size; + } + + return (numBitsRemaining <= 0); +} + +void NALBitReader::fillReservoir() { + CHECK_GT(mSize, 0u); + + mReservoir = 0; + size_t i = 0; + while (mSize > 0 && i < 4) { + bool isEmulationPreventionByte = (mNumZeros >= 2 && *mData == 3); + + if (*mData == 0) { + ++mNumZeros; + } else { + mNumZeros = 0; + } + + // skip emulation_prevention_three_byte + if (!isEmulationPreventionByte) { + mReservoir = (mReservoir << 8) | *mData; + ++i; + } + + ++mData; + --mSize; + } + + mNumBitsLeft = 8 * i; + mReservoir <<= 32 - mNumBitsLeft; +} + } // namespace android -- cgit v1.1 From 7618c5cb2fd60e944307e46afa051987d1e016c6 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 8 Jul 2014 14:17:29 -0700 Subject: Cleanup unused parameters or variable in EffectBundle No unused parameter warning in EffectBundle. Remove unused variable declaration in Virtualizer_getParameter Change-Id: Ibe1c051bc21ac53a6c770b4aa28e31ac5d559d9b --- media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index 695767d..38ee82b 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -163,7 +163,7 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled); extern "C" int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, - int32_t ioId, + int32_t ioId __unused, effect_handle_t *pHandle){ int ret = 0; int sessionNo; @@ -1360,7 +1360,7 @@ int32_t EqualizerGetCentreFrequency(EffectContext *pContext, int32_t band){ // pLow: lower band range // pLow: upper band range //---------------------------------------------------------------------------- -int32_t EqualizerGetBandFreqRange(EffectContext *pContext, int32_t band, uint32_t *pLow, +int32_t EqualizerGetBandFreqRange(EffectContext *pContext __unused, int32_t band, uint32_t *pLow, uint32_t *pHi){ *pLow = bandFreqRange[band][0]; *pHi = bandFreqRange[band][1]; @@ -1384,7 +1384,7 @@ int32_t EqualizerGetBandFreqRange(EffectContext *pContext, int32_t band, uint32_ // pLow: lower band range // pLow: upper band range //---------------------------------------------------------------------------- -int32_t EqualizerGetBand(EffectContext *pContext, uint32_t targetFreq){ +int32_t EqualizerGetBand(EffectContext *pContext __unused, uint32_t targetFreq){ int band = 0; if(targetFreq < bandFreqRange[0][0]){ @@ -1884,7 +1884,6 @@ int Virtualizer_getParameter(EffectContext *pContext, int status = 0; int32_t *pParamTemp = (int32_t *)pParam; int32_t param = *pParamTemp++; - int32_t param2; char *name; //ALOGV("\tVirtualizer_getParameter start"); -- cgit v1.1 From aae3f86c7c9a3bce5aab0d283343455d58b133b8 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 9 Jul 2014 10:01:38 -0700 Subject: DO NOT MERGE: Fix build for libstagefright Bug: 15987446 Change-Id: I6a13e1f73b067b733e2592e12ee21210d4c4d476 --- media/libstagefright/ACodec.cpp | 12 +++--------- media/libstagefright/OMXCodec.cpp | 12 +++--------- 2 files changed, 6 insertions(+), 18 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index f2d960a..8945d58 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -652,15 +652,9 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( err = mOMX->setParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - if (err == OK) { - *minUndequeuedBuffers += extraBuffers; - break; - } - - ALOGW("[%s] setting nBufferCountActual to %u failed: %d", - mComponentName.c_str(), newBufferCount, err); - /* exit condition */ - if (extraBuffers == 0) { + if (err != OK) { + ALOGE("[%s] setting nBufferCountActual to %u failed: %d", + mComponentName.c_str(), newBufferCount, err); return err; } } diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 97bf514..cefa248 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1806,15 +1806,9 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { err = mOMX->setParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - if (err == OK) { - minUndequeuedBufs += extraBuffers; - break; - } - - CODEC_LOGW("setting nBufferCountActual to %u failed: %d", - newBufferCount, err); - /* exit condition */ - if (extraBuffers == 0) { + if (err != OK) { + ALOGE("setting nBufferCountActual to %u failed: %d", + newBufferCount, err); return err; } } -- cgit v1.1 From bc2fb720bbd0acd122bacc67e844e982d068f6f9 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Tue, 8 Jul 2014 16:37:57 -0700 Subject: Add support of audio offloading for NuPlayer. Change-Id: Ic83973339fb46a83b48382e6097925f45d200867 --- media/libmediaplayerservice/nuplayer/Android.mk | 1 + media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 128 +++++++++-- media/libmediaplayerservice/nuplayer/NuPlayer.h | 2 + .../nuplayer/NuPlayerDecoder.h | 12 +- .../nuplayer/NuPlayerDecoderPassThrough.cpp | 237 +++++++++++++++++++++ .../nuplayer/NuPlayerDecoderPassThrough.h | 77 +++++++ .../nuplayer/NuPlayerRenderer.cpp | 185 ++++++++++++++-- .../nuplayer/NuPlayerRenderer.h | 37 +++- .../nuplayer/NuPlayerSource.h | 3 +- media/libstagefright/Utils.cpp | 5 + 10 files changed, 641 insertions(+), 46 deletions(-) create mode 100644 media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp create mode 100644 media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk index f97ba57..25002e3 100644 --- a/media/libmediaplayerservice/nuplayer/Android.mk +++ b/media/libmediaplayerservice/nuplayer/Android.mk @@ -6,6 +6,7 @@ LOCAL_SRC_FILES:= \ HTTPLiveSource.cpp \ NuPlayer.cpp \ NuPlayerDecoder.cpp \ + NuPlayerDecoderPassThrough.cpp \ NuPlayerDriver.cpp \ NuPlayerRenderer.cpp \ NuPlayerStreamListener.cpp \ diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index b333043..88c59bf 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -22,6 +22,7 @@ #include "HTTPLiveSource.h" #include "NuPlayerDecoder.h" +#include "NuPlayerDecoderPassThrough.h" #include "NuPlayerDriver.h" #include "NuPlayerRenderer.h" #include "NuPlayerSource.h" @@ -143,6 +144,7 @@ NuPlayer::NuPlayer() : mUIDValid(false), mSourceFlags(0), mVideoIsAVC(false), + mOffloadAudio(false), mAudioEOS(false), mVideoEOS(false), mScanSourcesPending(false), @@ -500,6 +502,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { ALOGV("kWhatStart"); mVideoIsAVC = false; + mOffloadAudio = false; mAudioEOS = false; mVideoEOS = false; mSkipRenderingAudioUntilMediaTimeUs = -1; @@ -517,6 +520,21 @@ void NuPlayer::onMessageReceived(const sp &msg) { flags |= Renderer::FLAG_REAL_TIME; } + sp audioMeta = mSource->getFormatMeta(true /* audio */); + audio_stream_type_t streamType = AUDIO_STREAM_MUSIC; + if (mAudioSink != NULL) { + streamType = mAudioSink->getAudioStreamType(); + } + + sp videoFormat = mSource->getFormat(false /* audio */); + + mOffloadAudio = + canOffloadStream(audioMeta, (videoFormat != NULL), + true /* is_streaming */, streamType); + if (mOffloadAudio) { + flags |= Renderer::FLAG_OFFLOAD_AUDIO; + } + mRenderer = new Renderer( mAudioSink, new AMessage(kWhatRendererNotify, id()), @@ -661,7 +679,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { mAudioSink->close(); - audio_output_flags_t flags; + uint32_t flags; int64_t durationUs; // FIXME: we should handle the case where the video decoder // is created after we receive the format change indication. @@ -682,17 +700,92 @@ void NuPlayer::onMessageReceived(const sp &msg) { channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; } - CHECK_EQ(mAudioSink->open( - sampleRate, - numChannels, - (audio_channel_mask_t)channelMask, - AUDIO_FORMAT_PCM_16_BIT, - 8 /* bufferCount */, - NULL, - NULL, - flags), - (status_t)OK); - mAudioSink->start(); + if (mOffloadAudio) { + audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT; + audio_offload_info_t offloadInfo = + AUDIO_INFO_INITIALIZER; + + AString mime; + CHECK(format->findString("mime", &mime)); + + status_t err = + mapMimeToAudioFormat(audioFormat, mime.c_str()); + if (err != OK) { + ALOGE("Couldn't map mime \"%s\" to a valid " + "audio_format", mime.c_str()); + mOffloadAudio = false; + } else { + ALOGV("Mime \"%s\" mapped to audio_format 0x%x", + mime.c_str(), audioFormat); + + flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; + + offloadInfo.duration_us = -1; + format->findInt64( + "durationUs", &offloadInfo.duration_us); + + int avgBitRate = -1; + format->findInt32("bit-rate", &avgBitRate); + + offloadInfo.sample_rate = sampleRate; + offloadInfo.channel_mask = channelMask; + offloadInfo.format = audioFormat; + offloadInfo.stream_type = AUDIO_STREAM_MUSIC; + offloadInfo.bit_rate = avgBitRate; + offloadInfo.has_video = (mVideoDecoder != NULL); + offloadInfo.is_streaming = true; + + err = mAudioSink->open( + sampleRate, + numChannels, + (audio_channel_mask_t)channelMask, + audioFormat, + 8 /* bufferCount */, + &NuPlayer::Renderer::AudioSinkCallback, + mRenderer.get(), + (audio_output_flags_t)flags, + &offloadInfo); + + if (err == OK) { + // If the playback is offloaded to h/w, we pass + // the HAL some metadata information. + // We don't want to do this for PCM because it + // will be going through the AudioFlinger mixer + // before reaching the hardware. + sp audioMeta = + mSource->getFormatMeta(true /* audio */); + sendMetaDataToHal(mAudioSink, audioMeta); + + err = mAudioSink->start(); + } + } + + if (err != OK) { + // Clean up, fall back to non offload mode. + mAudioSink->close(); + mAudioDecoder.clear(); + mRenderer->signalDisableOffloadAudio(); + mOffloadAudio = false; + + instantiateDecoder( + true /* audio */, &mAudioDecoder); + } + } + + if (!mOffloadAudio) { + flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; + CHECK_EQ(mAudioSink->open( + sampleRate, + numChannels, + (audio_channel_mask_t)channelMask, + AUDIO_FORMAT_PCM_16_BIT, + 8 /* bufferCount */, + NULL, + NULL, + (audio_output_flags_t)flags), + (status_t)OK); + mAudioSink->start(); + } mRenderer->signalAudioSinkChanged(); } else { @@ -968,8 +1061,15 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp *decoder) { new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify, id()); - *decoder = audio ? new Decoder(notify) : - new Decoder(notify, mNativeWindow); + if (audio) { + if (mOffloadAudio) { + *decoder = new DecoderPassThrough(notify); + } else { + *decoder = new Decoder(notify); + } + } else { + *decoder = new Decoder(notify, mNativeWindow); + } (*decoder)->init(); (*decoder)->configure(format); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 5be71fb..d7c00aa 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -76,6 +76,7 @@ public: private: struct Decoder; + struct DecoderPassThrough; struct CCDecoder; struct GenericSource; struct HTTPLiveSource; @@ -120,6 +121,7 @@ private: sp mAudioSink; sp mVideoDecoder; bool mVideoIsAVC; + bool mOffloadAudio; sp mAudioDecoder; sp mCCDecoder; sp mRenderer; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index 1a4f4ab..4fa0dbd 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -31,14 +31,14 @@ struct NuPlayer::Decoder : public AHandler { Decoder(const sp ¬ify, const sp &nativeWindow = NULL); - void configure(const sp &format); - void init(); + virtual void configure(const sp &format); + virtual void init(); - void signalFlush(); - void signalResume(); - void initiateShutdown(); + virtual void signalFlush(); + virtual void signalResume(); + virtual void initiateShutdown(); - bool supportsSeamlessFormatChange(const sp &to) const; + virtual bool supportsSeamlessFormatChange(const sp &to) const; enum { kWhatFillThisBuffer = 'flTB', diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp new file mode 100644 index 0000000..eec6960 --- /dev/null +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "NuPlayerDecoderPassThrough" +#include +#include + +#include "NuPlayerDecoderPassThrough.h" + +#include +#include +#include +#include +#include +#include + +namespace android { + +static const int kMaxPendingBuffers = 10; + +NuPlayer::DecoderPassThrough::DecoderPassThrough( + const sp ¬ify) + : Decoder(notify), + mNotify(notify), + mBufferGeneration(0), + mReachedEOS(true), + mPendingBuffers(0), + mComponentName("pass through decoder") { + mDecoderLooper = new ALooper; + mDecoderLooper->setName("NuPlayerDecoderPassThrough"); + mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO); +} + +NuPlayer::DecoderPassThrough::~DecoderPassThrough() { +} + +void NuPlayer::DecoderPassThrough::configure(const sp &format) { + sp msg = new AMessage(kWhatConfigure, id()); + msg->setMessage("format", format); + msg->post(); +} + +void NuPlayer::DecoderPassThrough::init() { + mDecoderLooper->registerHandler(this); +} + +void NuPlayer::DecoderPassThrough::signalFlush() { + (new AMessage(kWhatFlush, id()))->post(); +} + +void NuPlayer::DecoderPassThrough::signalResume() { + (new AMessage(kWhatResume, id()))->post(); +} + +void NuPlayer::DecoderPassThrough::initiateShutdown() { + (new AMessage(kWhatShutdown, id()))->post(); +} + +bool NuPlayer::DecoderPassThrough::supportsSeamlessFormatChange( + const sp & /* targetFormat */) const { + return true; +} + +void NuPlayer::DecoderPassThrough::onConfigure(const sp &format) { + ALOGV("[%s] onConfigure", mComponentName.c_str()); + mPendingBuffers = 0; + mReachedEOS = false; + ++mBufferGeneration; + + requestABuffer(); + + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatOutputFormatChanged); + notify->setMessage("format", format); + notify->post(); +} + +bool NuPlayer::DecoderPassThrough::isStaleReply(const sp &msg) { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + return generation != mBufferGeneration; +} + +void NuPlayer::DecoderPassThrough::requestABuffer() { + if (mPendingBuffers >= kMaxPendingBuffers || mReachedEOS) { + ALOGV("[%s] mReachedEOS=%d, max pending buffers(%d:%d)", + mComponentName.c_str(), (mReachedEOS ? 1 : 0), + mPendingBuffers, kMaxPendingBuffers); + return; + } + + sp reply = new AMessage(kWhatInputBufferFilled, id()); + reply->setInt32("generation", mBufferGeneration); + + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatFillThisBuffer); + notify->setMessage("reply", reply); + notify->post(); + mPendingBuffers++; + + sp message = new AMessage(kWhatRequestABuffer, id()); + message->setInt32("generation", mBufferGeneration); + message->post(); + return; +} + +void android::NuPlayer::DecoderPassThrough::onInputBufferFilled( + const sp &msg) { + if (mReachedEOS) { + return; + } + + sp buffer; + msg->findBuffer("buffer", &buffer); + if (buffer == NULL) { + mReachedEOS = true; + + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatEOS); + notify->setInt32("err", ERROR_END_OF_STREAM); + notify->post(); + return; + } + + sp reply = new AMessage(kWhatBufferConsumed, id()); + reply->setInt32("generation", mBufferGeneration); + + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatDrainThisBuffer); + notify->setBuffer("buffer", buffer); + notify->setMessage("reply", reply); + notify->post(); +} + +void NuPlayer::DecoderPassThrough::onBufferConsumed() { + mPendingBuffers--; + sp message = new AMessage(kWhatRequestABuffer, id()); + message->setInt32("generation", mBufferGeneration); + message->post(); +} + +void NuPlayer::DecoderPassThrough::onFlush() { + ++mBufferGeneration; + + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatFlushCompleted); + notify->post(); + mPendingBuffers = 0; + mReachedEOS = false; +} + +void NuPlayer::DecoderPassThrough::onShutdown() { + ++mBufferGeneration; + + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatShutdownCompleted); + notify->post(); + mReachedEOS = true; +} + +void NuPlayer::DecoderPassThrough::onMessageReceived(const sp &msg) { + ALOGV("[%s] onMessage: %s", mComponentName.c_str(), + msg->debugString().c_str()); + + switch (msg->what()) { + case kWhatConfigure: + { + sp format; + CHECK(msg->findMessage("format", &format)); + onConfigure(format); + break; + } + + case kWhatRequestABuffer: + { + if (!isStaleReply(msg)) { + requestABuffer(); + } + + break; + } + + case kWhatInputBufferFilled: + { + if (!isStaleReply(msg)) { + onInputBufferFilled(msg); + } + break; + } + + case kWhatBufferConsumed: + { + if (!isStaleReply(msg)) { + onBufferConsumed(); + } + break; + } + + case kWhatFlush: + { + onFlush(); + break; + } + + case kWhatResume: + { + requestABuffer(); + break; + } + + case kWhatShutdown: + { + onShutdown(); + break; + } + + default: + TRESPASS(); + break; + } +} + +} // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h new file mode 100644 index 0000000..e9e5658 --- /dev/null +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014 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 NUPLAYER_DECODER_PASS_THROUGH_H_ + +#define NUPLAYER_DECODER_PASS_THROUGH_H_ + +#include "NuPlayer.h" + +#include "NuPlayerDecoder.h" + +namespace android { + +struct NuPlayer::DecoderPassThrough : public Decoder { + DecoderPassThrough(const sp ¬ify); + + virtual void configure(const sp &format); + virtual void init(); + + virtual void signalFlush(); + virtual void signalResume(); + virtual void initiateShutdown(); + + bool supportsSeamlessFormatChange(const sp &to) const; + +protected: + + virtual ~DecoderPassThrough(); + + virtual void onMessageReceived(const sp &msg); + +private: + enum { + kWhatRequestABuffer = 'reqB', + kWhatConfigure = 'conf', + kWhatInputBufferFilled = 'inpF', + kWhatBufferConsumed = 'bufC', + kWhatFlush = 'flus', + kWhatShutdown = 'shuD', + }; + + sp mNotify; + sp mDecoderLooper; + + void requestABuffer(); + bool isStaleReply(const sp &msg); + + void onConfigure(const sp &format); + void onFlush(); + void onInputBufferFilled(const sp &msg); + void onBufferConsumed(); + void onShutdown(); + + int32_t mBufferGeneration; + bool mReachedEOS; + int32_t mPendingBuffers; + AString mComponentName; + + DISALLOW_EVIL_CONSTRUCTORS(DecoderPassThrough); +}; + +} // namespace android + +#endif // NUPLAYER_DECODER_PASS_THROUGH_H_ diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index a070c1a..f520ff7 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include namespace android { @@ -41,6 +43,7 @@ NuPlayer::Renderer::Renderer( mDrainVideoQueuePending(false), mAudioQueueGeneration(0), mVideoQueueGeneration(0), + mFirstAudioTimeUs(-1), mAnchorTimeMediaUs(-1), mAnchorTimeRealUs(-1), mFlushingAudio(false), @@ -57,6 +60,11 @@ NuPlayer::Renderer::Renderer( } NuPlayer::Renderer::~Renderer() { + if (offloadingAudio()) { + mAudioSink->stop(); + mAudioSink->flush(); + mAudioSink->close(); + } } void NuPlayer::Renderer::queueBuffer( @@ -97,6 +105,7 @@ void NuPlayer::Renderer::flush(bool audio) { } void NuPlayer::Renderer::signalTimeDiscontinuity() { + Mutex::Autolock autoLock(mLock); // CHECK(mAudioQueue.empty()); // CHECK(mVideoQueue.empty()); mAnchorTimeMediaUs = -1; @@ -114,6 +123,12 @@ void NuPlayer::Renderer::resume() { void NuPlayer::Renderer::onMessageReceived(const sp &msg) { switch (msg->what()) { + case kWhatStopAudioSink: + { + mAudioSink->stop(); + break; + } + case kWhatDrainAudioQueue: { int32_t generation; @@ -140,7 +155,10 @@ void NuPlayer::Renderer::onMessageReceived(const sp &msg) { // Let's give it more data after about half that time // has elapsed. - postDrainAudioQueue(delayUs / 2); + // kWhatDrainAudioQueue is used for non-offloading mode, + // and mLock is used only for offloading mode. Therefore, + // no need to acquire mLock here. + postDrainAudioQueue_l(delayUs / 2); } break; } @@ -185,6 +203,12 @@ void NuPlayer::Renderer::onMessageReceived(const sp &msg) { break; } + case kWhatDisableOffloadAudio: + { + onDisableOffloadAudio(); + break; + } + case kWhatPause: { onPause(); @@ -203,8 +227,9 @@ void NuPlayer::Renderer::onMessageReceived(const sp &msg) { } } -void NuPlayer::Renderer::postDrainAudioQueue(int64_t delayUs) { - if (mDrainAudioQueuePending || mSyncQueues || mPaused) { +void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) { + if (mDrainAudioQueuePending || mSyncQueues || mPaused + || offloadingAudio()) { return; } @@ -222,6 +247,10 @@ void NuPlayer::Renderer::signalAudioSinkChanged() { (new AMessage(kWhatAudioSinkChanged, id()))->post(); } +void NuPlayer::Renderer::signalDisableOffloadAudio() { + (new AMessage(kWhatDisableOffloadAudio, id()))->post(); +} + void NuPlayer::Renderer::prepareForMediaRenderingStart() { mAudioRenderingStartGeneration = mAudioQueueGeneration; mVideoRenderingStartGeneration = mVideoQueueGeneration; @@ -239,6 +268,109 @@ void NuPlayer::Renderer::notifyIfMediaRenderingStarted() { } } +// static +size_t NuPlayer::Renderer::AudioSinkCallback( + MediaPlayerBase::AudioSink * /* audioSink */, + void *buffer, + size_t size, + void *cookie, + MediaPlayerBase::AudioSink::cb_event_t event) { + NuPlayer::Renderer *me = (NuPlayer::Renderer *)cookie; + + switch (event) { + case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER: + { + return me->fillAudioBuffer(buffer, size); + break; + } + + case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END: + { + me->notifyEOS(true /* audio */, ERROR_END_OF_STREAM); + break; + } + + case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN: + { + // TODO: send this to player. + break; + } + } + + return 0; +} + +size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { + Mutex::Autolock autoLock(mLock); + + if (!offloadingAudio()) { + return 0; + } + + bool hasEOS = false; + + size_t sizeCopied = 0; + while (sizeCopied < size && !mAudioQueue.empty()) { + QueueEntry *entry = &*mAudioQueue.begin(); + + if (entry->mBuffer == NULL) { // EOS + hasEOS = true; + mAudioQueue.erase(mAudioQueue.begin()); + entry = NULL; + break; + } + + if (entry->mOffset == 0) { + int64_t mediaTimeUs; + CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); + ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); + if (mFirstAudioTimeUs == -1) { + mFirstAudioTimeUs = mediaTimeUs; + } + mAnchorTimeMediaUs = mediaTimeUs; + + uint32_t numFramesPlayed; + CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); + + // TODO: figure out how to calculate initial latency. + // Otherwise, the initial time is not correct till the first sample + // is played. + mAnchorTimeMediaUs = mFirstAudioTimeUs + + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll; + mAnchorTimeRealUs = ALooper::GetNowUs(); + } + + size_t copy = entry->mBuffer->size() - entry->mOffset; + size_t sizeRemaining = size - sizeCopied; + if (copy > sizeRemaining) { + copy = sizeRemaining; + } + + memcpy((char *)buffer + sizeCopied, + entry->mBuffer->data() + entry->mOffset, + copy); + + entry->mOffset += copy; + if (entry->mOffset == entry->mBuffer->size()) { + entry->mNotifyConsumed->post(); + mAudioQueue.erase(mAudioQueue.begin()); + entry = NULL; + } + sizeCopied += copy; + notifyIfMediaRenderingStarted(); + } + + if (sizeCopied != 0) { + notifyPosition(); + } + + if (hasEOS) { + (new AMessage(kWhatStopAudioSink, id()))->post(); + } + + return sizeCopied; +} + bool NuPlayer::Renderer::onDrainAudioQueue() { uint32_t numFramesPlayed; if (mAudioSink->getPosition(&numFramesPlayed) != OK) { @@ -474,13 +606,15 @@ void NuPlayer::Renderer::onQueueBuffer(const sp &msg) { entry.mFinalResult = OK; if (audio) { + Mutex::Autolock autoLock(mLock); mAudioQueue.push_back(entry); - postDrainAudioQueue(); + postDrainAudioQueue_l(); } else { mVideoQueue.push_back(entry); postDrainVideoQueue(); } + Mutex::Autolock autoLock(mLock); if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) { return; } @@ -490,7 +624,7 @@ void NuPlayer::Renderer::onQueueBuffer(const sp &msg) { if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) { // EOS signalled on either queue. - syncQueuesDone(); + syncQueuesDone_l(); return; } @@ -514,10 +648,10 @@ void NuPlayer::Renderer::onQueueBuffer(const sp &msg) { return; } - syncQueuesDone(); + syncQueuesDone_l(); } -void NuPlayer::Renderer::syncQueuesDone() { +void NuPlayer::Renderer::syncQueuesDone_l() { if (!mSyncQueues) { return; } @@ -525,7 +659,7 @@ void NuPlayer::Renderer::syncQueuesDone() { mSyncQueues = false; if (!mAudioQueue.empty()) { - postDrainAudioQueue(); + postDrainAudioQueue_l(); } if (!mVideoQueue.empty()) { @@ -549,14 +683,16 @@ void NuPlayer::Renderer::onQueueEOS(const sp &msg) { entry.mFinalResult = finalResult; if (audio) { + Mutex::Autolock autoLock(mLock); if (mAudioQueue.empty() && mSyncQueues) { - syncQueuesDone(); + syncQueuesDone_l(); } mAudioQueue.push_back(entry); - postDrainAudioQueue(); + postDrainAudioQueue_l(); } else { if (mVideoQueue.empty() && mSyncQueues) { - syncQueuesDone(); + Mutex::Autolock autoLock(mLock); + syncQueuesDone_l(); } mVideoQueue.push_back(entry); postDrainVideoQueue(); @@ -575,11 +711,17 @@ void NuPlayer::Renderer::onFlush(const sp &msg) { // corresponding discontinuity on the other queue. // Therefore we'll stop syncing the queues if at least one of them // is flushed. - syncQueuesDone(); + { + Mutex::Autolock autoLock(mLock); + syncQueuesDone_l(); + } ALOGV("flushing %s", audio ? "audio" : "video"); if (audio) { - flushQueue(&mAudioQueue); + { + Mutex::Autolock autoLock(mLock); + flushQueue(&mAudioQueue); + } Mutex::Autolock autoLock(mFlushLock); mFlushingAudio = false; @@ -588,6 +730,12 @@ void NuPlayer::Renderer::onFlush(const sp &msg) { ++mAudioQueueGeneration; prepareForMediaRenderingStart(); + if (offloadingAudio()) { + mFirstAudioTimeUs = -1; + mAudioSink->pause(); + mAudioSink->flush(); + mAudioSink->start(); + } } else { flushQueue(&mVideoQueue); @@ -649,6 +797,9 @@ bool NuPlayer::Renderer::dropBufferWhileFlushing( } void NuPlayer::Renderer::onAudioSinkChanged() { + if (offloadingAudio()) { + return; + } CHECK(!mDrainAudioQueuePending); mNumFramesWritten = 0; uint32_t written; @@ -657,6 +808,11 @@ void NuPlayer::Renderer::onAudioSinkChanged() { } } +void NuPlayer::Renderer::onDisableOffloadAudio() { + Mutex::Autolock autoLock(mLock); + mFlags &= ~FLAG_OFFLOAD_AUDIO; +} + void NuPlayer::Renderer::notifyPosition() { if (mAnchorTimeRealUs < 0 || mAnchorTimeMediaUs < 0) { return; @@ -711,8 +867,9 @@ void NuPlayer::Renderer::onResume() { mPaused = false; + Mutex::Autolock autoLock(mLock); if (!mAudioQueue.empty()) { - postDrainAudioQueue(); + postDrainAudioQueue_l(); } if (!mVideoQueue.empty()) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 94a05ea..6e86a8f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -27,11 +27,17 @@ struct ABuffer; struct NuPlayer::Renderer : public AHandler { enum Flags { FLAG_REAL_TIME = 1, + FLAG_OFFLOAD_AUDIO = 2, }; Renderer(const sp &sink, const sp ¬ify, uint32_t flags = 0); + static size_t AudioSinkCallback( + MediaPlayerBase::AudioSink *audioSink, + void *data, size_t size, void *me, + MediaPlayerBase::AudioSink::cb_event_t event); + void queueBuffer( bool audio, const sp &buffer, @@ -45,6 +51,8 @@ struct NuPlayer::Renderer : public AHandler { void signalAudioSinkChanged(); + void signalDisableOffloadAudio(); + void pause(); void resume(); @@ -63,14 +71,16 @@ protected: private: enum { - kWhatDrainAudioQueue = 'draA', - kWhatDrainVideoQueue = 'draV', - kWhatQueueBuffer = 'queB', - kWhatQueueEOS = 'qEOS', - kWhatFlush = 'flus', - kWhatAudioSinkChanged = 'auSC', - kWhatPause = 'paus', - kWhatResume = 'resm', + kWhatDrainAudioQueue = 'draA', + kWhatDrainVideoQueue = 'draV', + kWhatQueueBuffer = 'queB', + kWhatQueueEOS = 'qEOS', + kWhatFlush = 'flus', + kWhatAudioSinkChanged = 'auSC', + kWhatPause = 'paus', + kWhatResume = 'resm', + kWhatStopAudioSink = 'stpA', + kWhatDisableOffloadAudio = 'noOA', }; struct QueueEntry { @@ -84,6 +94,7 @@ private: sp mAudioSink; sp mNotify; + Mutex mLock; uint32_t mFlags; List mAudioQueue; List mVideoQueue; @@ -94,6 +105,7 @@ private: int32_t mAudioQueueGeneration; int32_t mVideoQueueGeneration; + int64_t mFirstAudioTimeUs; int64_t mAnchorTimeMediaUs; int64_t mAnchorTimeRealUs; @@ -113,8 +125,10 @@ private: int64_t mLastPositionUpdateUs; int64_t mVideoLateByUs; + size_t fillAudioBuffer(void *buffer, size_t size); + bool onDrainAudioQueue(); - void postDrainAudioQueue(int64_t delayUs = 0); + void postDrainAudioQueue_l(int64_t delayUs = 0); void onDrainVideoQueue(); void postDrainVideoQueue(); @@ -126,6 +140,7 @@ private: void onQueueEOS(const sp &msg); void onFlush(const sp &msg); void onAudioSinkChanged(); + void onDisableOffloadAudio(); void onPause(); void onResume(); @@ -137,7 +152,9 @@ private: void flushQueue(List *queue); bool dropBufferWhileFlushing(bool audio, const sp &msg); - void syncQueuesDone(); + void syncQueuesDone_l(); + + bool offloadingAudio() const { return (mFlags & FLAG_OFFLOAD_AUDIO) != 0; } DISALLOW_EVIL_CONSTRUCTORS(Renderer); }; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index f5a1d6d..632c4a6 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -64,6 +64,7 @@ struct NuPlayer::Source : public AHandler { virtual status_t feedMoreTSData() = 0; virtual sp getFormat(bool audio); + virtual sp getFormatMeta(bool /* audio */) { return NULL; } virtual status_t dequeueAccessUnit( bool audio, sp *accessUnit) = 0; @@ -97,8 +98,6 @@ protected: virtual void onMessageReceived(const sp &msg); - virtual sp getFormatMeta(bool /* audio */) { return NULL; } - sp dupNotify() const { return mNotify->dup(); } void notifyFlagsChanged(uint32_t flags); diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index d53051e..5771c6c 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -84,6 +84,11 @@ status_t convertMetaDataToMessage( msg->setInt64("durationUs", durationUs); } + int avgBitRate; + if (meta->findInt32(kKeyBitRate, &avgBitRate)) { + msg->setInt32("bit-rate", avgBitRate); + } + int32_t isSync; if (meta->findInt32(kKeyIsSyncFrame, &isSync) && isSync != 0) { msg->setInt32("is-sync-frame", 1); -- cgit v1.1 From 4510de26e5361f3a9f07057ec6f26483c888c1fa Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Wed, 28 May 2014 18:42:37 -0700 Subject: DNG: Update TiffWriter to handle thumbnails and SubIfds. - Fix SubIfd handling. - Add StripSources, convenience functions for writing image strips. - Update Input classes to use with JNI. - Add skip method. - Add tag definitions for GPS tags. - Add name string to tag definitions. Bug: 15112503 Change-Id: I9535b21261027f6c06a041c1621de8f865a0ad32 --- media/img_utils/include/img_utils/FileInput.h | 6 +- media/img_utils/include/img_utils/Input.h | 14 +- media/img_utils/include/img_utils/StripSource.h | 53 +++++ media/img_utils/include/img_utils/TagDefinitions.h | 229 +++++++++++++++++++-- media/img_utils/include/img_utils/TiffEntry.h | 13 +- media/img_utils/include/img_utils/TiffEntryImpl.h | 56 +++-- media/img_utils/include/img_utils/TiffHelpers.h | 2 +- media/img_utils/include/img_utils/TiffIfd.h | 46 ++++- media/img_utils/include/img_utils/TiffWriter.h | 145 +++++++++---- media/img_utils/src/Android.mk | 1 + media/img_utils/src/FileInput.cpp | 13 +- media/img_utils/src/Input.cpp | 28 +++ media/img_utils/src/StripSource.cpp | 25 +++ media/img_utils/src/TiffEntry.cpp | 10 - media/img_utils/src/TiffEntryImpl.cpp | 19 -- media/img_utils/src/TiffIfd.cpp | 208 ++++++++++++++++++- media/img_utils/src/TiffWriter.cpp | 219 +++++++++++++++++--- 17 files changed, 938 insertions(+), 149 deletions(-) create mode 100644 media/img_utils/include/img_utils/StripSource.h create mode 100644 media/img_utils/src/StripSource.cpp (limited to 'media') diff --git a/media/img_utils/include/img_utils/FileInput.h b/media/img_utils/include/img_utils/FileInput.h index d3c5ec1..4d4f22b 100644 --- a/media/img_utils/include/img_utils/FileInput.h +++ b/media/img_utils/include/img_utils/FileInput.h @@ -52,10 +52,10 @@ class ANDROID_API FileInput : public Input { * of bytes given in the count argument will be read. Bytes will be written * into the given buffer starting at the index given in the offset argument. * - * Returns the number of bytes read. If an error has occurred, the value pointed - * to by the given status_t pointer will be set to a negative error code. + * Returns the number of bytes read, or NOT_ENOUGH_DATA if at the end of the file. If an + * error has occurred, this will return a negative error code other than NOT_ENOUGH_DATA. */ - virtual size_t read(uint8_t* buf, size_t offset, size_t count, status_t* err); + virtual ssize_t read(uint8_t* buf, size_t offset, size_t count); /** * Close the file descriptor to the path given in the constructor. diff --git a/media/img_utils/include/img_utils/Input.h b/media/img_utils/include/img_utils/Input.h index 2166601..6a03647 100644 --- a/media/img_utils/include/img_utils/Input.h +++ b/media/img_utils/include/img_utils/Input.h @@ -43,10 +43,18 @@ class ANDROID_API Input { * count argument will be read. Bytes will be written into the given buffer starting * at the index given in the offset argument. * - * Returns the number of bytes read. If an error has occurred, the value pointed - * to by the given status_t pointer will be set to a negative error code. + * Returns the number of bytes read, or NOT_ENOUGH_DATA if at the end of the file. If an + * error has occurred, this will return a negative error code other than NOT_ENOUGH_DATA. */ - virtual size_t read(uint8_t* buf, size_t offset, size_t count, status_t* err) = 0; + virtual ssize_t read(uint8_t* buf, size_t offset, size_t count) = 0; + + /** + * Skips bytes in the input. + * + * Returns the number of bytes skipped, or NOT_ENOUGH_DATA if at the end of the file. If an + * error has occurred, this will return a negative error code other than NOT_ENOUGH_DATA. + */ + virtual ssize_t skip(size_t count); /** * Close the Input. It is not valid to call open on a previously closed Input. diff --git a/media/img_utils/include/img_utils/StripSource.h b/media/img_utils/include/img_utils/StripSource.h new file mode 100644 index 0000000..b5c6b60 --- /dev/null +++ b/media/img_utils/include/img_utils/StripSource.h @@ -0,0 +1,53 @@ +/* + * Copyright 2014 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 IMG_UTILS_STRIP_SOURCE_H +#define IMG_UTILS_STRIP_SOURCE_H + +#include + +#include +#include + +#include + +namespace android { +namespace img_utils { + +/** + * This class acts as a data source for strips set in a TiffIfd. + */ +class ANDROID_API StripSource { + public: + virtual ~StripSource(); + + /** + * Write count bytes to the stream. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t writeToStream(Output& stream, uint32_t count) = 0; + + /** + * Return the source IFD. + */ + virtual uint32_t getIfd() const = 0; +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_STRIP_SOURCE_H*/ diff --git a/media/img_utils/include/img_utils/TagDefinitions.h b/media/img_utils/include/img_utils/TagDefinitions.h index 6cc42b2..e9a7480 100644 --- a/media/img_utils/include/img_utils/TagDefinitions.h +++ b/media/img_utils/include/img_utils/TagDefinitions.h @@ -29,16 +29,18 @@ namespace img_utils { * Tag definitions contain information about standard TIFF compatible tags. */ typedef struct TagDefinition { + // The tag name. + const char* tagName; // The specified tag ID. - uint16_t tagId; + const uint16_t tagId; // The default type for this tag. This must be a valid TIFF type. - TagType defaultType; + const TagType defaultType; // The default Image File Directory (IFD) for this tag. - uint32_t defaultIfd; + const uint32_t defaultIfd; // The valid count for this tag, or 0 if the count is not fixed. - uint32_t fixedCount; + const uint32_t fixedCount; // The endianness of the tag value, or UNDEFINED_ENDIAN if there is no fixed endian - Endianness fixedEndian; + const Endianness fixedEndian; } TagDefinition_t; /** @@ -180,6 +182,14 @@ enum { TAG_ISOSPEEDRATINGS = 0x8827u, TAG_FOCALLENGTH = 0x920Au, TAG_FNUMBER = 0x829Du, + TAG_GPSINFO = 0x8825u, + TAG_GPSVERSIONID = 0x0u, + TAG_GPSLATITUDEREF = 0x1u, + TAG_GPSLATITUDE = 0x2u, + TAG_GPSLONGITUDEREF = 0x3u, + TAG_GPSLONGITUDE = 0x4u, + TAG_GPSTIMESTAMP = 0x7u, + TAG_GPSDATESTAMP = 0x001Du, }; /** @@ -187,6 +197,7 @@ enum { */ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { { // PhotometricInterpretation + "PhotometricInterpretation", 0x0106u, SHORT, IFD_0, @@ -194,6 +205,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // SubIfds + "SubIfds", 0x014Au, LONG, IFD_0, @@ -201,6 +213,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CFAPattern + "CFAPattern", 0x828Eu, BYTE, IFD_0, @@ -208,6 +221,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CFARepeatPatternDim + "CFARepeatPatternDim", 0x828Du, SHORT, IFD_0, @@ -215,6 +229,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DateTimeOriginal + "DateTimeOriginal", 0x9003u, ASCII, IFD_0, @@ -222,6 +237,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Tiff/EPStandardID + "Tiff", 0x9216u, BYTE, IFD_0, @@ -229,6 +245,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ExposureTime + "ExposureTime", 0x829Au, RATIONAL, IFD_0, @@ -236,6 +253,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ISOSpeedRatings + "ISOSpeedRatings", 0x8827u, SHORT, IFD_0, @@ -243,6 +261,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // FocalLength + "FocalLength", 0x920Au, RATIONAL, IFD_0, @@ -250,12 +269,69 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // FNumber + "FNumber", 0x829Du, RATIONAL, IFD_0, 0, UNDEFINED_ENDIAN }, + { // GPSInfo + "GPSInfo", + 0x8825u, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // GPSVersionID + "GPSVersionID", + 0x0u, + BYTE, + IFD_0, + 4, + UNDEFINED_ENDIAN + }, + { // GPSLatitudeRef + "GPSLatitudeRef", + 0x1u, + ASCII, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + { // GPSLatitude + "GPSLatitude", + 0x2u, + RATIONAL, + IFD_0, + 3, + UNDEFINED_ENDIAN + }, + { // GPSLongitudeRef + "GPSLongitudeRef", + 0x3u, + ASCII, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + { // GPSLongitude + "GPSLongitude", + 0x4u, + RATIONAL, + IFD_0, + 3, + UNDEFINED_ENDIAN + }, + { // GPSTimeStamp + "GPSTimeStamp", + 0x7u, + RATIONAL, + IFD_0, + 3, + UNDEFINED_ENDIAN + }, /*TODO: Remaining TIFF EP tags*/ }; @@ -264,12 +340,21 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { */ const TagDefinition_t EXIF_2_3_TAG_DEFINITIONS[] = { { // ExifVersion + "ExifVersion", 0x9000u, UNDEFINED, IFD_0, 4, UNDEFINED_ENDIAN }, + { // GPSDateStamp + "GPSDateStamp", + 0x001Du, + ASCII, + IFD_0, + 11, + UNDEFINED_ENDIAN + }, /*TODO: Remaining EXIF 2.3 tags*/ }; @@ -278,6 +363,7 @@ const TagDefinition_t EXIF_2_3_TAG_DEFINITIONS[] = { */ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { { // SubFileType + "SubFileType", 0x00FFu, SHORT, IFD_0, @@ -285,6 +371,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Artist + "Artist", 0x013Bu, ASCII, IFD_0, @@ -292,6 +379,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BitsPerSample + "BitsPerSample", 0x0102u, SHORT, IFD_0, @@ -299,6 +387,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CellLength + "CellLength", 0x0109u, SHORT, IFD_0, @@ -306,6 +395,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CellWidth + "CellWidth", 0x0108u, SHORT, IFD_0, @@ -313,6 +403,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ColorMap + "ColorMap", 0x0140u, SHORT, IFD_0, @@ -320,6 +411,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Compression + "Compression", 0x0103u, SHORT, IFD_0, @@ -327,6 +419,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Copyright + "Copyright", 0x8298u, ASCII, IFD_0, @@ -334,6 +427,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DateTime + "DateTime", 0x0132u, ASCII, IFD_0, @@ -341,6 +435,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ExtraSamples + "ExtraSamples", 0x0152u, SHORT, IFD_0, @@ -348,6 +443,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // FillOrder + "FillOrder", 0x010Au, SHORT, IFD_0, @@ -355,6 +451,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // FreeByteCounts + "FreeByteCounts", 0x0121u, LONG, IFD_0, @@ -362,6 +459,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // FreeOffsets + "FreeOffsets", 0x0120u, LONG, IFD_0, @@ -369,6 +467,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // GrayResponseCurve + "GrayResponseCurve", 0x0123u, SHORT, IFD_0, @@ -376,6 +475,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // GrayResponseUnit + "GrayResponseUnit", 0x0122u, SHORT, IFD_0, @@ -383,6 +483,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // HostComputer + "HostComputer", 0x013Cu, ASCII, IFD_0, @@ -390,6 +491,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ImageDescription + "ImageDescription", 0x010Eu, ASCII, IFD_0, @@ -397,6 +499,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ImageLength + "ImageLength", 0x0101u, LONG, IFD_0, @@ -404,6 +507,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ImageWidth + "ImageWidth", 0x0100u, LONG, IFD_0, @@ -411,6 +515,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Make + "Make", 0x010Fu, ASCII, IFD_0, @@ -418,6 +523,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // MaxSampleValue + "MaxSampleValue", 0x0119u, SHORT, IFD_0, @@ -425,6 +531,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // MinSampleValue + "MinSampleValue", 0x0118u, SHORT, IFD_0, @@ -432,6 +539,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Model + "Model", 0x0110u, ASCII, IFD_0, @@ -439,6 +547,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // NewSubfileType + "NewSubfileType", 0x00FEu, LONG, IFD_0, @@ -446,6 +555,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Orientation + "Orientation", 0x0112u, SHORT, IFD_0, @@ -453,6 +563,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PhotoMetricInterpretation + "PhotoMetricInterpretation", 0x0106u, SHORT, IFD_0, @@ -460,6 +571,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PlanarConfiguration + "PlanarConfiguration", 0x011Cu, SHORT, IFD_0, @@ -467,6 +579,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ResolutionUnit + "ResolutionUnit", 0x0128u, SHORT, IFD_0, @@ -474,6 +587,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // RowsPerStrip + "RowsPerStrip", 0x0116u, LONG, IFD_0, @@ -481,6 +595,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // SamplesPerPixel + "SamplesPerPixel", 0x0115u, SHORT, IFD_0, @@ -488,6 +603,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Software + "Software", 0x0131u, ASCII, IFD_0, @@ -495,6 +611,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // StripByteCounts + "StripByteCounts", 0x0117u, LONG, IFD_0, @@ -502,6 +619,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // StripOffsets + "StripOffsets", 0x0111u, LONG, IFD_0, @@ -509,6 +627,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // SubfileType + "SubfileType", 0x00FFu, SHORT, IFD_0, @@ -516,6 +635,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Threshholding + "Threshholding", 0x0107u, SHORT, IFD_0, @@ -523,6 +643,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // XResolution + "XResolution", 0x011Au, RATIONAL, IFD_0, @@ -530,19 +651,13 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // YResolution + "YResolution", 0x011Bu, RATIONAL, IFD_0, 1, UNDEFINED_ENDIAN }, - { // YResolution - 0x011Bu, - RATIONAL, - IFD_0, - 1, - UNDEFINED_ENDIAN - } }; /** @@ -550,6 +665,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { */ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { { // DNGVersion + "DNGVersion", 0xC612u, BYTE, IFD_0, @@ -557,6 +673,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DNGBackwardVersion + "DNGBackwardVersion", 0xC613u, BYTE, IFD_0, @@ -564,6 +681,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // UniqueCameraModel + "UniqueCameraModel", 0xC614u, ASCII, IFD_0, @@ -571,6 +689,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // LocalizedCameraModel + "LocalizedCameraModel", 0xC615u, ASCII, IFD_0, @@ -578,6 +697,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CFAPlaneColor + "CFAPlaneColor", 0xC616u, BYTE, RAW_IFD, @@ -585,6 +705,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CFALayout + "CFALayout", 0xC617u, SHORT, RAW_IFD, @@ -592,6 +713,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // LinearizationTable + "LinearizationTable", 0xC618u, SHORT, RAW_IFD, @@ -599,6 +721,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BlackLevelRepeatDim + "BlackLevelRepeatDim", 0xC619u, SHORT, RAW_IFD, @@ -606,6 +729,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BlackLevel + "BlackLevel", 0xC61Au, LONG, RAW_IFD, @@ -613,6 +737,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BlackLevelDeltaH + "BlackLevelDeltaH", 0xC61Bu, SRATIONAL, RAW_IFD, @@ -620,6 +745,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BlackLevelDeltaV + "BlackLevelDeltaV", 0xC61Cu, SRATIONAL, RAW_IFD, @@ -627,6 +753,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // WhiteLevel + "WhiteLevel", 0xC61Du, LONG, RAW_IFD, @@ -634,6 +761,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DefaultScale + "DefaultScale", 0xC61Eu, RATIONAL, RAW_IFD, @@ -641,6 +769,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BestQualityScale + "BestQualityScale", 0xC65Cu, RATIONAL, RAW_IFD, @@ -648,6 +777,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DefaultCropOrigin + "DefaultCropOrigin", 0xC61Fu, LONG, RAW_IFD, @@ -655,6 +785,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DefaultCropSize + "DefaultCropSize", 0xC620u, LONG, RAW_IFD, @@ -662,6 +793,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CalibrationIlluminant1 + "CalibrationIlluminant1", 0xC65Au, SHORT, PROFILE_IFD, @@ -669,6 +801,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CalibrationIlluminant2 + "CalibrationIlluminant2", 0xC65Bu, SHORT, PROFILE_IFD, @@ -676,6 +809,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ColorMatrix1 + "ColorMatrix1", 0xC621u, SRATIONAL, PROFILE_IFD, @@ -683,6 +817,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ColorMatrix2 + "ColorMatrix2", 0xC622u, SRATIONAL, PROFILE_IFD, @@ -690,6 +825,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CameraCalibration1 + "CameraCalibration1", 0xC623u, SRATIONAL, IFD_0, @@ -697,6 +833,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CameraCalibration2 + "CameraCalibration2", 0xC624u, SRATIONAL, IFD_0, @@ -704,6 +841,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ReductionMatrix1 + "ReductionMatrix1", 0xC625u, SRATIONAL, PROFILE_IFD, @@ -711,6 +849,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ReductionMatrix2 + "ReductionMatrix2", 0xC626u, SRATIONAL, PROFILE_IFD, @@ -718,6 +857,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AnalogBalance + "AnalogBalance", 0xC627u, RATIONAL, IFD_0, @@ -725,6 +865,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AsShotNeutral + "AsShotNeutral", 0xC628u, RATIONAL, IFD_0, @@ -732,6 +873,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AsShotWhiteXY + "AsShotWhiteXY", 0xC629u, RATIONAL, IFD_0, @@ -739,6 +881,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BaselineExposure + "BaselineExposure", 0xC62Au, SRATIONAL, IFD_0, @@ -746,6 +889,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BaselineNoise + "BaselineNoise", 0xC62Bu, RATIONAL, IFD_0, @@ -753,6 +897,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BaselineSharpness + "BaselineSharpness", 0xC62Cu, RATIONAL, IFD_0, @@ -760,6 +905,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BayerGreenSplit + "BayerGreenSplit", 0xC62Du, LONG, RAW_IFD, @@ -767,6 +913,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // LinearResponseLimit + "LinearResponseLimit", 0xC62Eu, RATIONAL, IFD_0, @@ -774,6 +921,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CameraSerialNumber + "CameraSerialNumber", 0xC62Fu, ASCII, IFD_0, @@ -781,6 +929,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // LensInfo + "LensInfo", 0xC630u, RATIONAL, IFD_0, @@ -788,6 +937,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ChromaBlurRadius + "ChromaBlurRadius", 0xC631u, RATIONAL, RAW_IFD, @@ -795,6 +945,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AntiAliasStrength + "AntiAliasStrength", 0xC632u, RATIONAL, RAW_IFD, @@ -802,6 +953,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ShadowScale + "ShadowScale", 0xC633u, RATIONAL, IFD_0, @@ -809,6 +961,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DNGPrivateData + "DNGPrivateData", 0xC634u, BYTE, IFD_0, @@ -816,6 +969,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // MakerNoteSafety + "MakerNoteSafety", 0xC635u, SHORT, IFD_0, @@ -823,6 +977,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // RawDataUniqueID + "RawDataUniqueID", 0xC65Du, BYTE, IFD_0, @@ -830,6 +985,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OriginalRawFileName + "OriginalRawFileName", 0xC68Bu, ASCII, IFD_0, @@ -837,6 +993,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OriginalRawFileData + "OriginalRawFileData", 0xC68Cu, UNDEFINED, IFD_0, @@ -844,6 +1001,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { BIG }, { // ActiveArea + "ActiveArea", 0xC68Du, LONG, RAW_IFD, @@ -851,6 +1009,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // MaskedAreas + "MaskedAreas", 0xC68Eu, LONG, RAW_IFD, @@ -858,6 +1017,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AsShotICCProfile + "AsShotICCProfile", 0xC68Fu, UNDEFINED, IFD_0, @@ -865,6 +1025,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AsShotPreProfileMatrix + "AsShotPreProfileMatrix", 0xC690u, SRATIONAL, IFD_0, @@ -872,6 +1033,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CurrentICCProfile + "CurrentICCProfile", 0xC691u, UNDEFINED, IFD_0, @@ -879,6 +1041,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CurrentICCProfile + "CurrentICCProfile", 0xC691u, UNDEFINED, IFD_0, @@ -886,6 +1049,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CurrentPreProfileMatrix + "CurrentPreProfileMatrix", 0xC692u, SRATIONAL, IFD_0, @@ -893,6 +1057,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ColorimetricReference + "ColorimetricReference", 0xC6BFu, SHORT, IFD_0, @@ -900,6 +1065,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CameraCalibrationSignature + "CameraCalibrationSignature", 0xC6F3u, ASCII, IFD_0, @@ -907,6 +1073,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileCalibrationSignature + "ProfileCalibrationSignature", 0xC6F4u, ASCII, PROFILE_IFD, @@ -914,6 +1081,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ExtraCameraProfiles + "ExtraCameraProfiles", 0xC6F5u, LONG, IFD_0, @@ -921,6 +1089,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AsShotProfileName + "AsShotProfileName", 0xC6F6u, ASCII, IFD_0, @@ -928,6 +1097,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // NoiseReductionApplied + "NoiseReductionApplied", 0xC6F7u, RATIONAL, RAW_IFD, @@ -935,6 +1105,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileName + "ProfileName", 0xC6F8u, ASCII, PROFILE_IFD, @@ -942,6 +1113,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileHueSatMapDims + "ProfileHueSatMapDims", 0xC6F9u, LONG, PROFILE_IFD, @@ -949,6 +1121,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileHueSatMapData1 + "ProfileHueSatMapData1", 0xC6FAu, FLOAT, PROFILE_IFD, @@ -956,6 +1129,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileHueSatMapData2 + "ProfileHueSatMapData2", 0xC6FBu, FLOAT, PROFILE_IFD, @@ -963,6 +1137,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileToneCurve + "ProfileToneCurve", 0xC6FCu, FLOAT, PROFILE_IFD, @@ -970,6 +1145,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileEmbedPolicy + "ProfileEmbedPolicy", 0xC6FDu, LONG, PROFILE_IFD, @@ -977,6 +1153,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileCopyright + "ProfileCopyright", 0xC6FEu, ASCII, PROFILE_IFD, @@ -984,6 +1161,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ForwardMatrix1 + "ForwardMatrix1", 0xC714u, SRATIONAL, PROFILE_IFD, @@ -991,6 +1169,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ForwardMatrix2 + "ForwardMatrix2", 0xC715u, SRATIONAL, PROFILE_IFD, @@ -998,6 +1177,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PreviewApplicationName + "PreviewApplicationName", 0xC716u, ASCII, PREVIEW_IFD, @@ -1005,6 +1185,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PreviewApplicationVersion + "PreviewApplicationVersion", 0xC717u, ASCII, PREVIEW_IFD, @@ -1012,6 +1193,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PreviewSettingsName + "PreviewSettingsName", 0xC718u, ASCII, PREVIEW_IFD, @@ -1019,6 +1201,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PreviewSettingsDigest + "PreviewSettingsDigest", 0xC719u, BYTE, PREVIEW_IFD, @@ -1026,6 +1209,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PreviewColorSpace + "PreviewColorSpace", 0xC71Au, LONG, PREVIEW_IFD, @@ -1033,6 +1217,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PreviewDateTime + "PreviewDateTime", 0xC71Bu, ASCII, PREVIEW_IFD, @@ -1040,6 +1225,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // RawImageDigest + "RawImageDigest", 0xC71Cu, BYTE, IFD_0, @@ -1047,6 +1233,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OriginalRawFileDigest + "OriginalRawFileDigest", 0xC71Du, BYTE, IFD_0, @@ -1054,6 +1241,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // SubTileBlockSize + "SubTileBlockSize", 0xC71Eu, LONG, RAW_IFD, @@ -1061,6 +1249,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // RowInterleaveFactor + "RowInterleaveFactor", 0xC71Fu, LONG, RAW_IFD, @@ -1068,6 +1257,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileLookTableDims + "ProfileLookTableDims", 0xC725u, LONG, PROFILE_IFD, @@ -1075,6 +1265,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileLookTableData + "ProfileLookTableData", 0xC726u, FLOAT, PROFILE_IFD, @@ -1082,6 +1273,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OpcodeList1 + "OpcodeList1", 0xC740u, UNDEFINED, RAW_IFD, @@ -1089,6 +1281,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { BIG }, { // OpcodeList2 + "OpcodeList2", 0xC741u, UNDEFINED, RAW_IFD, @@ -1096,6 +1289,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { BIG }, { // OpcodeList3 + "OpcodeList3", 0xC74Eu, UNDEFINED, RAW_IFD, @@ -1103,6 +1297,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { BIG }, { // NoiseProfile + "NoiseProfile", 0xC761u, DOUBLE, RAW_IFD, @@ -1110,6 +1305,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DefaultUserCrop + "DefaultUserCrop", 0xC7B5u, RATIONAL, RAW_IFD, @@ -1117,6 +1313,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DefaultBlackRender + "DefaultBlackRender", 0xC7A6u, LONG, PROFILE_IFD, @@ -1124,6 +1321,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BaselineExposureOffset + "BaselineExposureOffset", 0xC7A5u, RATIONAL, PROFILE_IFD, @@ -1131,6 +1329,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileLookTableEncoding + "ProfileLookTableEncoding", 0xC7A4u, LONG, PROFILE_IFD, @@ -1138,6 +1337,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileHueSatMapEncoding + "ProfileHueSatMapEncoding", 0xC7A3u, LONG, PROFILE_IFD, @@ -1145,6 +1345,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OriginalDefaultFinalSize + "OriginalDefaultFinalSize", 0xC791u, LONG, IFD_0, @@ -1152,6 +1353,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OriginalBestQualityFinalSize + "OriginalBestQualityFinalSize", 0xC792u, LONG, IFD_0, @@ -1159,6 +1361,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OriginalDefaultCropSize + "OriginalDefaultCropSize", 0xC793u, LONG, IFD_0, @@ -1166,6 +1369,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // NewRawImageDigest + "NewRawImageDigest", 0xC7A7u, BYTE, IFD_0, @@ -1173,6 +1377,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // RawToPreviewGain + "RawToPreviewGain", 0xC7A8u, DOUBLE, PREVIEW_IFD, diff --git a/media/img_utils/include/img_utils/TiffEntry.h b/media/img_utils/include/img_utils/TiffEntry.h index cd01640..4d672b2 100644 --- a/media/img_utils/include/img_utils/TiffEntry.h +++ b/media/img_utils/include/img_utils/TiffEntry.h @@ -34,10 +34,11 @@ inline bool operator op (const TiffEntry& entry) const; /** * This class holds a single TIFF IFD entry. + * + * Subclasses are expected to support assignment and copying operations. */ class ANDROID_API TiffEntry : public TiffWritable { public: - // TODO: Copy constructor/equals here. virtual ~TiffEntry(); /** @@ -83,7 +84,7 @@ class ANDROID_API TiffEntry : public TiffWritable { template const T* getData() const; - String8 toString() const; + virtual String8 toString() const; /** * Force the type used here to be a valid TIFF type. @@ -99,10 +100,10 @@ class ANDROID_API TiffEntry : public TiffWritable { COMPARE_DEF(>) COMPARE_DEF(<) - protected: - enum { - MAX_PRINT_STRING_LENGTH = 256 - }; + protected: + enum { + MAX_PRINT_STRING_LENGTH = 256 + }; }; #define COMPARE(op) \ diff --git a/media/img_utils/include/img_utils/TiffEntryImpl.h b/media/img_utils/include/img_utils/TiffEntryImpl.h index cbe0e9a..f5ccb5e 100644 --- a/media/img_utils/include/img_utils/TiffEntryImpl.h +++ b/media/img_utils/include/img_utils/TiffEntryImpl.h @@ -17,6 +17,7 @@ #ifndef IMG_UTILS_TIFF_ENTRY_IMPL #define IMG_UTILS_TIFF_ENTRY_IMPL +#include #include #include #include @@ -24,6 +25,8 @@ #include #include +#include +#include #include namespace android { @@ -32,7 +35,6 @@ namespace img_utils { template class TiffEntryImpl : public TiffEntry { public: - // TODO: Copy constructor/equals here. TiffEntryImpl(uint16_t tag, TagType type, uint32_t count, Endianness end, const T* data); virtual ~TiffEntryImpl(); @@ -54,7 +56,7 @@ class TiffEntryImpl : public TiffEntry { uint16_t mType; uint32_t mCount; Endianness mEnd; - T* mData; + Vector mData; }; @@ -63,18 +65,12 @@ TiffEntryImpl::TiffEntryImpl(uint16_t tag, TagType type, uint32_t count, Endi const T* data) : mTag(tag), mType(static_cast(type)), mCount(count), mEnd(end) { count = (type == RATIONAL || type == SRATIONAL) ? count * 2 : count; - mData = new T[count](); - for (uint32_t i = 0; i < count; ++i) { - mData[i] = data[i]; - } + ssize_t index = mData.appendArray(data, count); + LOG_ALWAYS_FATAL_IF(index < 0, "%s: Could not allocate vector for data.", __FUNCTION__); } template -TiffEntryImpl::~TiffEntryImpl() { - if (mData) { - delete[] mData; - } -} +TiffEntryImpl::~TiffEntryImpl() {} template uint32_t TiffEntryImpl::getCount() const { @@ -93,7 +89,7 @@ TagType TiffEntryImpl::getType() const { template const void* TiffEntryImpl::getDataHelper() const { - return reinterpret_cast(mData); + return reinterpret_cast(mData.array()); } template @@ -144,7 +140,7 @@ status_t TiffEntryImpl::writeTagInfo(uint32_t offset, /*out*/EndianOutput* ou */ count <<= 1; } - BAIL_ON_FAIL(out->write(mData, 0, count), ret); + BAIL_ON_FAIL(out->write(mData.array(), 0, count), ret); ZERO_TILL_WORD(out, dataSize, ret); } return ret; @@ -171,7 +167,7 @@ status_t TiffEntryImpl::writeData(uint32_t offset, EndianOutput* out) const { count <<= 1; } - BAIL_ON_FAIL(out->write(mData, 0, count), ret); + BAIL_ON_FAIL(out->write(mData.array(), 0, count), ret); if (mEnd != UNDEFINED_ENDIAN) { out->setEndianness(tmp); @@ -182,6 +178,38 @@ status_t TiffEntryImpl::writeData(uint32_t offset, EndianOutput* out) const { return ret; } +template<> +inline status_t TiffEntryImpl >::writeTagInfo(uint32_t offset, + /*out*/EndianOutput* out) const { + assert((offset % TIFF_WORD_SIZE) == 0); + status_t ret = OK; + BAIL_ON_FAIL(out->write(&mTag, 0, 1), ret); + BAIL_ON_FAIL(out->write(&mType, 0, 1), ret); + BAIL_ON_FAIL(out->write(&mCount, 0, 1), ret); + + BAIL_ON_FAIL(out->write(&offset, 0, 1), ret); + return ret; +} + +template<> +inline uint32_t TiffEntryImpl >::getActualSize() const { + uint32_t total = 0; + for (size_t i = 0; i < mData.size(); ++i) { + total += mData[i]->getSize(); + } + return total; +} + +template<> +inline status_t TiffEntryImpl >::writeData(uint32_t offset, EndianOutput* out) const { + status_t ret = OK; + for (uint32_t i = 0; i < mCount; ++i) { + BAIL_ON_FAIL(mData[i]->writeData(offset, out), ret); + offset += mData[i]->getSize(); + } + return ret; +} + } /*namespace img_utils*/ } /*namespace android*/ diff --git a/media/img_utils/include/img_utils/TiffHelpers.h b/media/img_utils/include/img_utils/TiffHelpers.h index fd0ea7a..0969e4d 100644 --- a/media/img_utils/include/img_utils/TiffHelpers.h +++ b/media/img_utils/include/img_utils/TiffHelpers.h @@ -37,7 +37,7 @@ const uint8_t ZERO_WORD[] = {0, 0, 0, 0}; { \ size_t remaining = BYTES_TILL_WORD(index); \ if (remaining > 0) { \ - BAIL_ON_FAIL(output->write(ZERO_WORD, 0, remaining), ret); \ + BAIL_ON_FAIL((output)->write(ZERO_WORD, 0, remaining), ret); \ } \ } diff --git a/media/img_utils/include/img_utils/TiffIfd.h b/media/img_utils/include/img_utils/TiffIfd.h index 9400456..51b5c9a 100644 --- a/media/img_utils/include/img_utils/TiffIfd.h +++ b/media/img_utils/include/img_utils/TiffIfd.h @@ -42,7 +42,6 @@ namespace img_utils { */ class ANDROID_API TiffIfd : public TiffWritable { public: - // TODO: Copy constructor/equals here - needed for SubIfds. TiffIfd(uint32_t ifdId); virtual ~TiffIfd(); @@ -98,9 +97,50 @@ class ANDROID_API TiffIfd : public TiffWritable { virtual sp getEntry(uint16_t tag) const; /** + * Remove the entry with the given tag ID if it exists. + */ + virtual void removeEntry(uint16_t tag); + + /** + * Convenience method to validate and set strip-related image tags. + * + * This sets all strip related tags, but leaves offset values unitialized. + * setStripOffsets must be called with the desired offset before writing. + * The strip tag values are calculated from the existing tags for image + * dimensions and pixel type set in the IFD. + * + * Does not handle planar image configurations (PlanarConfiguration != 1). + * + * Returns OK on success, or a negative error code. + */ + virtual status_t validateAndSetStripTags(); + + /** + * Returns true if validateAndSetStripTags has been called, but not setStripOffsets. + */ + virtual bool uninitializedOffsets() const; + + /** + * Convenience method to set beginning offset for strips. + * + * Call this to update the strip offsets before calling writeData. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t setStripOffset(uint32_t offset); + + /** + * Get the total size of the strips in bytes. + * + * This sums the byte count at each strip offset, and returns + * the total count of bytes stored in strips for this IFD. + */ + virtual uint32_t getStripSize() const; + + /** * Get a formatted string representing this IFD. */ - String8 toString() const; + virtual String8 toString() const; /** * Print a formatted string representing this IFD to logcat. @@ -111,11 +151,13 @@ class ANDROID_API TiffIfd : public TiffWritable { * Get value used to determine sort order. */ virtual uint32_t getComparableValue() const; + protected: virtual uint32_t checkAndGetOffset(uint32_t offset) const; SortedEntryVector mEntries; sp mNextIfd; uint32_t mIfdId; + bool mStripOffsetsInitialized; }; } /*namespace img_utils*/ diff --git a/media/img_utils/include/img_utils/TiffWriter.h b/media/img_utils/include/img_utils/TiffWriter.h index ec27fc3..b7af239 100644 --- a/media/img_utils/include/img_utils/TiffWriter.h +++ b/media/img_utils/include/img_utils/TiffWriter.h @@ -18,8 +18,10 @@ #define IMG_UTILS_TIFF_WRITER_H #include +#include #include #include +#include #include #include @@ -48,6 +50,10 @@ class Output; */ class ANDROID_API TiffWriter : public LightRefBase { public: + enum SubIfdType { + SUBIFD = 0, + GPSINFO + }; /** * Constructs a TiffWriter with the default tag mappings. This enables @@ -77,6 +83,25 @@ class ANDROID_API TiffWriter : public LightRefBase { * Write a TIFF header containing each IFD set. This will recursively * write all SubIFDs and tags. * + * Any StripSources passed in will be written to the output as image strips + * at the appropriate offests. The StripByteCounts, RowsPerStrip, and + * StripOffsets tags must be set to use this. To set these tags in a + * given IFD, use the addStrip method. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t write(Output* out, StripSource** sources, size_t sourcesCount, + Endianness end = LITTLE); + + /** + * Write a TIFF header containing each IFD set. This will recursively + * write all SubIFDs and tags. + * + * Image data for strips or tiles must be written separately at the + * appropriate offsets. These offsets must not fall within the file + * header written this way. The size of the header written is given + * by the getTotalSize() method. + * * Returns OK on success, or a negative error code on failure. */ virtual status_t write(Output* out, Endianness end = LITTLE); @@ -88,16 +113,7 @@ class ANDROID_API TiffWriter : public LightRefBase { virtual uint32_t getTotalSize() const; /** - * Add the given entry to its default IFD. If that IFD does not - * exist, it will be created. - */ - virtual status_t addEntry(const sp& entry); - - /** - * Build an entry for a known tag. This tag must be one of the tags - * defined in one of the definition vectors this TIFF writer was constructed - * with. The count and type are validated. If this succeeds, the resulting - * entry will be placed in the outEntry pointer. + * Add an entry to the IFD with the given ID. * * Returns OK on success, or a negative error code on failure. Valid * error codes for this method are: @@ -106,16 +122,14 @@ class ANDROID_API TiffWriter : public LightRefBase { * this tag. * - BAD_TYPE - The type of the given data isn't compatible with the * type required for this tag. + * - NAME_NOT_FOUND - No ifd exists with the given ID. */ - template - status_t buildEntry(uint16_t tag, uint32_t count, const T* data, - /*out*/sp* outEntry) const; + virtual status_t addEntry(const sp& entry, uint32_t ifd); - /** + /** * Build an entry for a known tag and add it to the IFD with the given ID. * This tag must be defined in one of the definition vectors this TIFF writer - * was constructed with. The count and type are validated. If this succeeds, - * the resulting entry will be placed in the outEntry pointer. + * was constructed with. The count and type are validated. * * Returns OK on success, or a negative error code on failure. Valid * error codes for this method are: @@ -130,18 +144,47 @@ class ANDROID_API TiffWriter : public LightRefBase { status_t addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd); /** + * Build an entry for a known tag. This tag must be one of the tags + * defined in one of the definition vectors this TIFF writer was constructed + * with. The count and type are validated. If this succeeds, the resulting + * entry will be placed in the outEntry pointer. + * + * Returns OK on success, or a negative error code on failure. Valid + * error codes for this method are: + * - BAD_INDEX - The given tag doesn't exist. + * - BAD_VALUE - The given count doesn't match the required count for + * this tag. + * - BAD_TYPE - The type of the given data isn't compatible with the + * type required for this tag. + */ + template + status_t buildEntry(uint16_t tag, uint32_t count, const T* data, + /*out*/sp* outEntry) const; + + /** + * Convenience function to set the strip related tags for a given IFD. + * + * Call this before using a StripSource as an input to write. + * The following tags must be set before calling this method: + * - ImageWidth + * - ImageLength + * - SamplesPerPixel + * - BitsPerSample + * + * Returns OK on success, or a negative error code. + */ + virtual status_t addStrip(uint32_t ifd); + + /** * Return the TIFF entry with the given tag ID in the IFD with the given ID, * or an empty pointer if none exists. */ virtual sp getEntry(uint16_t tag, uint32_t ifd) const; /** - * Add the given IFD to the end of the top-level IFD chain. No - * validation is done. - * - * Returns OK on success, or a negative error code on failure. + * Remove the TIFF entry with the given tag ID in the given IFD if it exists. */ - virtual status_t uncheckedAddIfd(const sp& ifd); + virtual void removeEntry(uint16_t tag, uint32_t ifd); /** * Create an empty IFD with the given ID and add it to the end of the @@ -150,24 +193,10 @@ class ANDROID_API TiffWriter : public LightRefBase { virtual status_t addIfd(uint32_t ifd); /** - * Build an entry. No validation is done. - * - * WARNING: Using this method can result in creating poorly formatted - * TIFF files. - * - * Returns a TiffEntry with the given tag, type, count, endianness, - * and data. + * Create an empty IFD with the given ID and add it as a SubIfd of the + * parent IFD. */ - template - static sp uncheckedBuildEntry(uint16_t tag, TagType type, - uint32_t count, Endianness end, const T* data); - - /** - * Utility function to build atag-to-definition mapping from a given - * array of tag definitions. - */ - static KeyedVector buildTagMap( - const TagDefinition_t* definitions, size_t length); + virtual status_t addSubIfd(uint32_t parentIfd, uint32_t ifd, SubIfdType type = SUBIFD); /** * Returns the default type for the given tag ID. @@ -181,15 +210,46 @@ class ANDROID_API TiffWriter : public LightRefBase { virtual uint32_t getDefaultCount(uint16_t tag) const; /** + * Returns true if an IFD with the given ID exists. + */ + virtual bool hasIfd(uint32_t ifd) const; + + /** * Returns true if a definition exist for the given tag ID. */ virtual bool checkIfDefined(uint16_t tag) const; /** + * Returns the name of the tag if a definition exists for the given tag + * ID, or null if no definition exists. + */ + virtual const char* getTagName(uint16_t tag) const; + + /** * Print the currently configured IFDs and entries to logcat. */ virtual void log() const; + /** + * Build an entry. No validation is done. + * + * WARNING: Using this method can result in creating poorly formatted + * TIFF files. + * + * Returns a TiffEntry with the given tag, type, count, endianness, + * and data. + */ + template + static sp uncheckedBuildEntry(uint16_t tag, TagType type, + uint32_t count, Endianness end, const T* data); + + /** + * Utility function to build atag-to-definition mapping from a given + * array of tag definitions. + */ + static KeyedVector buildTagMap( + const TagDefinition_t* definitions, size_t length); + protected: enum { DEFAULT_NUM_TAG_MAPS = 4, @@ -240,17 +300,14 @@ status_t TiffWriter::buildEntry(uint16_t tag, uint32_t count, const T* data, template status_t TiffWriter::addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd) { sp outEntry; + status_t ret = buildEntry(tag, count, data, &outEntry); if (ret != OK) { ALOGE("%s: Could not build entry for tag %x.", __FUNCTION__, tag); return ret; } - ssize_t index = mNamedIfds.indexOfKey(ifd); - if (index < 0) { - ALOGE("%s: No IFD %d set for this writer.", __FUNCTION__, ifd); - return NAME_NOT_FOUND; - } - return mNamedIfds[index]->addEntry(outEntry); + + return addEntry(outEntry, ifd); } template diff --git a/media/img_utils/src/Android.mk b/media/img_utils/src/Android.mk index 80893be..4074849 100644 --- a/media/img_utils/src/Android.mk +++ b/media/img_utils/src/Android.mk @@ -31,6 +31,7 @@ LOCAL_SRC_FILES := \ TiffEntryImpl.cpp \ ByteArrayOutput.cpp \ DngUtils.cpp \ + StripSource.cpp \ LOCAL_SHARED_LIBRARIES := \ libexpat \ diff --git a/media/img_utils/src/FileInput.cpp b/media/img_utils/src/FileInput.cpp index e43fd53..498e715 100644 --- a/media/img_utils/src/FileInput.cpp +++ b/media/img_utils/src/FileInput.cpp @@ -45,19 +45,24 @@ status_t FileInput::open() { return OK; } -size_t FileInput::read(uint8_t* buf, size_t offset, size_t count, status_t* err) { +ssize_t FileInput::read(uint8_t* buf, size_t offset, size_t count) { if (!mOpen) { ALOGE("%s: Could not read file %s, file not open.", __FUNCTION__, mPath.string()); - if (err != NULL) *err = BAD_VALUE; - return 0; + return BAD_VALUE; } size_t bytesRead = ::fread(buf + offset, sizeof(uint8_t), count, mFp); int error = ::ferror(mFp); if (error != 0) { ALOGE("%s: Error %d occurred while reading file %s.", __FUNCTION__, error, mPath.string()); - if (err != NULL) *err = BAD_VALUE; + return BAD_VALUE; } + + // End of file reached + if (::feof(mFp) != 0 && bytesRead == 0) { + return NOT_ENOUGH_DATA; + } + return bytesRead; } diff --git a/media/img_utils/src/Input.cpp b/media/img_utils/src/Input.cpp index 1e51e10..3782014 100644 --- a/media/img_utils/src/Input.cpp +++ b/media/img_utils/src/Input.cpp @@ -20,9 +20,37 @@ namespace android { namespace img_utils { Input::~Input() {} + status_t Input::open() { return OK; } + status_t Input::close() { return OK; } +ssize_t Input::skip(size_t count) { + const size_t SKIP_BUF_SIZE = 1024; + uint8_t skipBuf[SKIP_BUF_SIZE]; + + size_t remaining = count; + while (remaining > 0) { + size_t amt = (SKIP_BUF_SIZE > remaining) ? remaining : SKIP_BUF_SIZE; + ssize_t ret = read(skipBuf, 0, amt); + if (ret < 0) { + if(ret == NOT_ENOUGH_DATA) { + // End of file encountered + if (remaining == count) { + // Read no bytes, return EOF + return NOT_ENOUGH_DATA; + } else { + // Return num bytes read + return count - remaining; + } + } + // Return error code. + return ret; + } + remaining -= ret; + } + return count; +} } /*namespace img_utils*/ } /*namespace android*/ diff --git a/media/img_utils/src/StripSource.cpp b/media/img_utils/src/StripSource.cpp new file mode 100644 index 0000000..57b6082 --- /dev/null +++ b/media/img_utils/src/StripSource.cpp @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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 + +namespace android { +namespace img_utils { + +StripSource::~StripSource() {} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/TiffEntry.cpp b/media/img_utils/src/TiffEntry.cpp index e028827..9cea721 100644 --- a/media/img_utils/src/TiffEntry.cpp +++ b/media/img_utils/src/TiffEntry.cpp @@ -32,16 +32,6 @@ TiffEntry::~TiffEntry() {} * * Values with types other than the ones given here should not compile. */ -template<> -const Vector >* TiffEntry::forceValidType > >(TagType type, - const Vector >* value) { - if (type == LONG) { - return value; - } - ALOGE("%s: Value of type 'ifd vector' is not valid for tag with TIFF type %d.", - __FUNCTION__, type); - return NULL; -} template<> const sp* TiffEntry::forceValidType >(TagType type, const sp* value) { diff --git a/media/img_utils/src/TiffEntryImpl.cpp b/media/img_utils/src/TiffEntryImpl.cpp index 6efa458..257c266 100644 --- a/media/img_utils/src/TiffEntryImpl.cpp +++ b/media/img_utils/src/TiffEntryImpl.cpp @@ -15,30 +15,11 @@ */ #include -#include #include namespace android { namespace img_utils { -template<> -size_t TiffEntryImpl::getSize() const { - uint32_t total = 0; - for (uint32_t i = 0; i < mCount; ++i) { - total += mData[i].getSize(); - } - return total; -} - -template<> -status_t TiffEntryImpl::writeData(uint32_t offset, EndianOutput* out) const { - status_t ret = OK; - for (uint32_t i = 0; i < mCount; ++i) { - BAIL_ON_FAIL(mData[i].writeData(offset, out), ret); - } - return ret; -} - } /*namespace img_utils*/ } /*namespace android*/ diff --git a/media/img_utils/src/TiffIfd.cpp b/media/img_utils/src/TiffIfd.cpp index 1b3b40d..3fb00cc 100644 --- a/media/img_utils/src/TiffIfd.cpp +++ b/media/img_utils/src/TiffIfd.cpp @@ -14,8 +14,12 @@ * limitations under the License. */ -#include +#define LOG_TAG "TiffIfd" + +#include #include +#include +#include #include @@ -23,7 +27,7 @@ namespace android { namespace img_utils { TiffIfd::TiffIfd(uint32_t ifdId) - : mNextIfd(), mIfdId(ifdId) {} + : mNextIfd(), mIfdId(ifdId), mStripOffsetsInitialized(false) {} TiffIfd::~TiffIfd() {} @@ -52,6 +56,14 @@ sp TiffIfd::getEntry(uint16_t tag) const { return mEntries[index]; } +void TiffIfd::removeEntry(uint16_t tag) { + ssize_t index = mEntries.indexOfTag(tag); + if (index >= 0) { + mEntries.removeAt(index); + } +} + + void TiffIfd::setNextIfd(const sp& ifd) { mNextIfd = ifd; } @@ -156,6 +168,198 @@ uint32_t TiffIfd::getComparableValue() const { return mIfdId; } +status_t TiffIfd::validateAndSetStripTags() { + sp widthEntry = getEntry(TAG_IMAGEWIDTH); + if (widthEntry == NULL) { + ALOGE("%s: IFD %u doesn't have a ImageWidth tag set", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + sp heightEntry = getEntry(TAG_IMAGELENGTH); + if (heightEntry == NULL) { + ALOGE("%s: IFD %u doesn't have a ImageLength tag set", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + sp samplesEntry = getEntry(TAG_SAMPLESPERPIXEL); + if (samplesEntry == NULL) { + ALOGE("%s: IFD %u doesn't have a SamplesPerPixel tag set", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + sp bitsEntry = getEntry(TAG_BITSPERSAMPLE); + if (bitsEntry == NULL) { + ALOGE("%s: IFD %u doesn't have a BitsPerSample tag set", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + uint32_t width = *(widthEntry->getData()); + uint32_t height = *(heightEntry->getData()); + uint16_t bitsPerSample = *(bitsEntry->getData()); + uint16_t samplesPerPixel = *(samplesEntry->getData()); + + if ((bitsPerSample % 8) != 0) { + ALOGE("%s: BitsPerSample %d in IFD %u is not byte-aligned.", __FUNCTION__, + bitsPerSample, mIfdId); + return BAD_VALUE; + } + + uint32_t bytesPerSample = bitsPerSample / 8; + + // Choose strip size as close to 8kb as possible without splitting rows. + // If the row length is >8kb, each strip will only contain a single row. + const uint32_t rowLengthBytes = bytesPerSample * samplesPerPixel * width; + const uint32_t idealChunkSize = (1 << 13); // 8kb + uint32_t rowsPerChunk = idealChunkSize / rowLengthBytes; + rowsPerChunk = (rowsPerChunk == 0) ? 1 : rowsPerChunk; + const uint32_t actualChunkSize = rowLengthBytes * rowsPerChunk; + + const uint32_t lastChunkRows = height % rowsPerChunk; + const uint32_t lastChunkSize = lastChunkRows * rowLengthBytes; + + if (actualChunkSize > /*max strip size for TIFF/EP*/65536) { + ALOGE("%s: Strip length too long.", __FUNCTION__); + return BAD_VALUE; + } + + size_t numStrips = height / rowsPerChunk; + + // Add another strip for the incomplete chunk. + if (lastChunkRows > 0) { + numStrips += 1; + } + + // Put each row in it's own strip + uint32_t rowsPerStripVal = rowsPerChunk; + sp rowsPerStrip = TiffWriter::uncheckedBuildEntry(TAG_ROWSPERSTRIP, LONG, 1, + UNDEFINED_ENDIAN, &rowsPerStripVal); + + if (rowsPerStrip == NULL) { + ALOGE("%s: Could not build entry for RowsPerStrip tag.", __FUNCTION__); + return BAD_VALUE; + } + + Vector byteCounts; + + for (size_t i = 0; i < numStrips; ++i) { + if (lastChunkRows > 0 && i == (numStrips - 1)) { + byteCounts.add(lastChunkSize); + } else { + byteCounts.add(actualChunkSize); + } + } + + // Set byte counts for each strip + sp stripByteCounts = TiffWriter::uncheckedBuildEntry(TAG_STRIPBYTECOUNTS, LONG, + static_cast(numStrips), UNDEFINED_ENDIAN, byteCounts.array()); + + if (stripByteCounts == NULL) { + ALOGE("%s: Could not build entry for StripByteCounts tag.", __FUNCTION__); + return BAD_VALUE; + } + + Vector stripOffsetsVector; + stripOffsetsVector.resize(numStrips); + + // Set uninitialized offsets + sp stripOffsets = TiffWriter::uncheckedBuildEntry(TAG_STRIPOFFSETS, LONG, + static_cast(numStrips), UNDEFINED_ENDIAN, stripOffsetsVector.array()); + + if (stripOffsets == NULL) { + ALOGE("%s: Could not build entry for StripOffsets tag.", __FUNCTION__); + return BAD_VALUE; + } + + if(addEntry(stripByteCounts) != OK) { + ALOGE("%s: Could not add entry for StripByteCounts to IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + if(addEntry(rowsPerStrip) != OK) { + ALOGE("%s: Could not add entry for StripByteCounts to IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + if(addEntry(stripOffsets) != OK) { + ALOGE("%s: Could not add entry for StripByteCounts to IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + mStripOffsetsInitialized = true; + return OK; +} + +bool TiffIfd::uninitializedOffsets() const { + return mStripOffsetsInitialized; +} + +status_t TiffIfd::setStripOffset(uint32_t offset) { + + // Get old offsets and bytecounts + sp oldOffsets = getEntry(TAG_STRIPOFFSETS); + if (oldOffsets == NULL) { + ALOGE("%s: IFD %u does not contain StripOffsets entry.", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + sp stripByteCounts = getEntry(TAG_STRIPBYTECOUNTS); + if (stripByteCounts == NULL) { + ALOGE("%s: IFD %u does not contain StripByteCounts entry.", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + uint32_t offsetsCount = oldOffsets->getCount(); + uint32_t byteCount = stripByteCounts->getCount(); + if (offsetsCount != byteCount) { + ALOGE("%s: StripOffsets count (%u) doesn't match StripByteCounts count (%u) in IFD %u", + __FUNCTION__, offsetsCount, byteCount, mIfdId); + return BAD_VALUE; + } + + const uint32_t* stripByteCountsArray = stripByteCounts->getData(); + + size_t numStrips = offsetsCount; + + Vector stripOffsets; + + // Calculate updated byte offsets + for (size_t i = 0; i < numStrips; ++i) { + stripOffsets.add(offset); + offset += stripByteCountsArray[i]; + } + + sp newOffsets = TiffWriter::uncheckedBuildEntry(TAG_STRIPOFFSETS, LONG, + static_cast(numStrips), UNDEFINED_ENDIAN, stripOffsets.array()); + + if (newOffsets == NULL) { + ALOGE("%s: Coult not build updated offsets entry in IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + if (addEntry(newOffsets) != OK) { + ALOGE("%s: Failed to add updated offsets entry in IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + return OK; +} + +uint32_t TiffIfd::getStripSize() const { + sp stripByteCounts = getEntry(TAG_STRIPBYTECOUNTS); + if (stripByteCounts == NULL) { + ALOGE("%s: IFD %u does not contain StripByteCounts entry.", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + uint32_t count = stripByteCounts->getCount(); + const uint32_t* byteCounts = stripByteCounts->getData(); + + uint32_t total = 0; + for (size_t i = 0; i < static_cast(count); ++i) { + total += byteCounts[i]; + } + return total; +} + String8 TiffIfd::toString() const { size_t s = mEntries.size(); String8 output; diff --git a/media/img_utils/src/TiffWriter.cpp b/media/img_utils/src/TiffWriter.cpp index 2439033..d85289e 100644 --- a/media/img_utils/src/TiffWriter.cpp +++ b/media/img_utils/src/TiffWriter.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ -#include +#define LOG_TAG "TiffWriter" + #include #include #include @@ -55,6 +56,82 @@ TiffWriter::TiffWriter(KeyedVector* enabledDef TiffWriter::~TiffWriter() {} +status_t TiffWriter::write(Output* out, StripSource** sources, size_t sourcesCount, + Endianness end) { + status_t ret = OK; + EndianOutput endOut(out, end); + + if (mIfd == NULL) { + ALOGE("%s: Tiff header is empty.", __FUNCTION__); + return BAD_VALUE; + } + + if (LOG_NDEBUG == 0) { + log(); + } + + uint32_t totalSize = getTotalSize(); + + KeyedVector offsetVector; + + for (size_t i = 0; i < mNamedIfds.size(); ++i) { + if (mNamedIfds[i]->uninitializedOffsets()) { + uint32_t stripSize = mNamedIfds[i]->getStripSize(); + if (mNamedIfds[i]->setStripOffset(totalSize) != OK) { + ALOGE("%s: Could not set strip offsets.", __FUNCTION__); + return BAD_VALUE; + } + totalSize += stripSize; + WORD_ALIGN(totalSize); + offsetVector.add(mNamedIfds.keyAt(i), totalSize); + } + } + + size_t offVecSize = offsetVector.size(); + if (offVecSize != sourcesCount) { + ALOGE("%s: Mismatch between number of IFDs with uninitialized strips (%zu) and" + " sources (%zu).", __FUNCTION__, offVecSize, sourcesCount); + return BAD_VALUE; + } + + BAIL_ON_FAIL(writeFileHeader(endOut), ret); + + uint32_t offset = FILE_HEADER_SIZE; + sp ifd = mIfd; + while(ifd != NULL) { + BAIL_ON_FAIL(ifd->writeData(offset, &endOut), ret); + offset += ifd->getSize(); + ifd = ifd->getNextIfd(); + } + + log(); + + for (size_t i = 0; i < offVecSize; ++i) { + uint32_t ifdKey = offsetVector.keyAt(i); + uint32_t nextOffset = offsetVector[i]; + uint32_t sizeToWrite = mNamedIfds[ifdKey]->getStripSize(); + bool found = false; + for (size_t j = 0; j < sourcesCount; ++j) { + if (sources[j]->getIfd() == ifdKey) { + if ((ret = sources[i]->writeToStream(endOut, sizeToWrite)) != OK) { + ALOGE("%s: Could not write to stream, received %d.", __FUNCTION__, ret); + return ret; + } + ZERO_TILL_WORD(&endOut, sizeToWrite, ret); + found = true; + break; + } + } + if (!found) { + ALOGE("%s: No stream for byte strips for IFD %u", __FUNCTION__, ifdKey); + return BAD_VALUE; + } + assert(nextOffset == endOut.getCurrentOffset()); + } + + return ret; +} + status_t TiffWriter::write(Output* out, Endianness end) { status_t ret = OK; EndianOutput endOut(out, end); @@ -101,48 +178,43 @@ sp TiffWriter::getEntry(uint16_t tag, uint32_t ifd) const { return mNamedIfds[index]->getEntry(tag); } +void TiffWriter::removeEntry(uint16_t tag, uint32_t ifd) { + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index >= 0) { + mNamedIfds[index]->removeEntry(tag); + } +} -// TODO: Fix this to handle IFD position in chain/sub-IFD tree -status_t TiffWriter::addEntry(const sp& entry) { +status_t TiffWriter::addEntry(const sp& entry, uint32_t ifd) { uint16_t tag = entry->getTag(); const TagDefinition_t* definition = lookupDefinition(tag); if (definition == NULL) { + ALOGE("%s: No definition exists for tag 0x%x.", __FUNCTION__, tag); return BAD_INDEX; } - uint32_t ifdId = 0; // TODO: all in IFD0 for now. - ssize_t index = mNamedIfds.indexOfKey(ifdId); + ssize_t index = mNamedIfds.indexOfKey(ifd); // Add a new IFD if necessary if (index < 0) { - sp ifdEntry = new TiffIfd(ifdId); - if (mIfd == NULL) { - mIfd = ifdEntry; - } - index = mNamedIfds.add(ifdId, ifdEntry); - assert(index >= 0); + ALOGE("%s: No IFD %u exists.", __FUNCTION__, ifd); + return NAME_NOT_FOUND; } sp selectedIfd = mNamedIfds[index]; return selectedIfd->addEntry(entry); } -status_t TiffWriter::uncheckedAddIfd(const sp& ifd) { - mNamedIfds.add(ifd->getId(), ifd); - sp last = findLastIfd(); - if (last == NULL) { - mIfd = ifd; - } else { - last->setNextIfd(ifd); - } - last = ifd->getNextIfd(); - while (last != NULL) { - mNamedIfds.add(last->getId(), last); - last = last->getNextIfd(); +status_t TiffWriter::addStrip(uint32_t ifd) { + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index < 0) { + ALOGE("%s: Ifd %u doesn't exist, cannot add strip entries.", __FUNCTION__, ifd); + return BAD_VALUE; } - return OK; + sp selected = mNamedIfds[index]; + return selected->validateAndSetStripTags(); } status_t TiffWriter::addIfd(uint32_t ifd) { @@ -151,6 +223,7 @@ status_t TiffWriter::addIfd(uint32_t ifd) { ALOGE("%s: Ifd with ID 0x%x already exists.", __FUNCTION__, ifd); return BAD_VALUE; } + sp newIfd = new TiffIfd(ifd); if (mIfd == NULL) { mIfd = newIfd; @@ -158,7 +231,83 @@ status_t TiffWriter::addIfd(uint32_t ifd) { sp last = findLastIfd(); last->setNextIfd(newIfd); } - mNamedIfds.add(ifd, newIfd); + + if(mNamedIfds.add(ifd, newIfd) < 0) { + ALOGE("%s: Failed to add new IFD 0x%x.", __FUNCTION__, ifd); + return BAD_VALUE; + } + + return OK; +} + +status_t TiffWriter::addSubIfd(uint32_t parentIfd, uint32_t ifd, SubIfdType type) { + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index >= 0) { + ALOGE("%s: Ifd with ID 0x%x already exists.", __FUNCTION__, ifd); + return BAD_VALUE; + } + + ssize_t parentIndex = mNamedIfds.indexOfKey(parentIfd); + if (parentIndex < 0) { + ALOGE("%s: Parent IFD with ID 0x%x does not exist.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + + sp parent = mNamedIfds[parentIndex]; + sp newIfd = new TiffIfd(ifd); + + uint16_t subIfdTag; + if (type == SUBIFD) { + subIfdTag = TAG_SUBIFDS; + } else if (type == GPSINFO) { + subIfdTag = TAG_GPSINFO; + } else { + ALOGE("%s: Unknown SubIFD type %d.", __FUNCTION__, type); + return BAD_VALUE; + } + + sp subIfds = parent->getEntry(subIfdTag); + if (subIfds == NULL) { + if (buildEntry(subIfdTag, 1, &newIfd, &subIfds) < 0) { + ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + } else { + if (type == GPSINFO) { + ALOGE("%s: Cannot add GPSInfo SubIFD to IFD %u, one already exists.", __FUNCTION__, + ifd); + return BAD_VALUE; + } + + Vector > subIfdList; + const sp* oldIfdArray = subIfds->getData >(); + if (subIfdList.appendArray(oldIfdArray, subIfds->getCount()) < 0) { + ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + + if (subIfdList.add(newIfd) < 0) { + ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + + uint32_t count = subIfdList.size(); + if (buildEntry(subIfdTag, count, subIfdList.array(), &subIfds) < 0) { + ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + } + + if (parent->addEntry(subIfds) < 0) { + ALOGE("%s: Failed to add SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + + if(mNamedIfds.add(ifd, newIfd) < 0) { + ALOGE("%s: Failed to add new IFD 0x%x.", __FUNCTION__, ifd); + return BAD_VALUE; + } + return OK; } @@ -180,10 +329,23 @@ uint32_t TiffWriter::getDefaultCount(uint16_t tag) const { return definition->fixedCount; } +bool TiffWriter::hasIfd(uint32_t ifd) const { + ssize_t index = mNamedIfds.indexOfKey(ifd); + return index >= 0; +} + bool TiffWriter::checkIfDefined(uint16_t tag) const { return lookupDefinition(tag) != NULL; } +const char* TiffWriter::getTagName(uint16_t tag) const { + const TagDefinition_t* definition = lookupDefinition(tag); + if (definition == NULL) { + return NULL; + } + return definition->tagName; +} + sp TiffWriter::findLastIfd() { sp ifd = mIfd; while(ifd != NULL) { @@ -221,10 +383,9 @@ uint32_t TiffWriter::getTotalSize() const { void TiffWriter::log() const { ALOGI("%s: TiffWriter:", __FUNCTION__); - sp ifd = mIfd; - while(ifd != NULL) { - ifd->log(); - ifd = ifd->getNextIfd(); + size_t length = mNamedIfds.size(); + for (size_t i = 0; i < length; ++i) { + mNamedIfds[i]->log(); } } -- cgit v1.1 From cd249c40c51584e89e065bf7d51999b04db2eb57 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Thu, 10 Jul 2014 17:49:27 -0700 Subject: Check meta before dereferencing it. Change-Id: Ic8153b33413a34d75a3053dbfb9530a639e0ec12 --- media/libstagefright/Utils.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'media') diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 5771c6c..8c5deb3 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -613,6 +613,9 @@ bool canOffloadStream(const sp& meta, bool hasVideo, bool isStreaming, audio_stream_type_t streamType) { const char *mime; + if (meta == NULL) { + return false; + } CHECK(meta->findCString(kKeyMIMEType, &mime)); audio_offload_info_t info = AUDIO_INFO_INITIALIZER; -- cgit v1.1 From 2829edccd7d2bb8244246f316face82b650b8949 Mon Sep 17 00:00:00 2001 From: aarti jadhav-gaikwad Date: Wed, 18 Jun 2014 15:25:26 +0530 Subject: stagefright: Pass audio aac sub formats in offloadinfo Pass audio aac sub formats in offloadinfo according to aac profile. Audio HAL can take decision about offload using DSP capabilities Change-Id: If269a3654b5d2b09c183212b0646ef03e06f2d8f --- media/libstagefright/AudioPlayer.cpp | 7 ++++++ media/libstagefright/Utils.cpp | 44 ++++++++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index fdac8fc..04fc88b 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -141,6 +142,12 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) { } else { ALOGV("Mime type \"%s\" mapped to audio_format 0x%x", mime, audioFormat); } + + int32_t aacaot = -1; + if ((audioFormat == AUDIO_FORMAT_AAC) && format->findInt32(kKeyAACAOT, &aacaot)) { + // Redefine AAC format corrosponding to aac profile + mapAACProfileToAudioFormat(audioFormat,(OMX_AUDIO_AACPROFILETYPE) aacaot); + } } int avgBitRate = -1; diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 8c5deb3..750bff0 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -609,6 +610,39 @@ const struct mime_conv_t* p = &mimeLookup[0]; return BAD_VALUE; } +struct aac_format_conv_t { + OMX_AUDIO_AACPROFILETYPE eAacProfileType; + audio_format_t format; +}; + +static const struct aac_format_conv_t profileLookup[] = { + { OMX_AUDIO_AACObjectMain, AUDIO_FORMAT_AAC_MAIN}, + { OMX_AUDIO_AACObjectLC, AUDIO_FORMAT_AAC_LC}, + { OMX_AUDIO_AACObjectSSR, AUDIO_FORMAT_AAC_SSR}, + { OMX_AUDIO_AACObjectLTP, AUDIO_FORMAT_AAC_LTP}, + { OMX_AUDIO_AACObjectHE, AUDIO_FORMAT_AAC_HE_V1}, + { OMX_AUDIO_AACObjectScalable, AUDIO_FORMAT_AAC_SCALABLE}, + { OMX_AUDIO_AACObjectERLC, AUDIO_FORMAT_AAC_ERLC}, + { OMX_AUDIO_AACObjectLD, AUDIO_FORMAT_AAC_LD}, + { OMX_AUDIO_AACObjectHE_PS, AUDIO_FORMAT_AAC_HE_V2}, + { OMX_AUDIO_AACObjectELD, AUDIO_FORMAT_AAC_ELD}, + { OMX_AUDIO_AACObjectNull, AUDIO_FORMAT_AAC}, +}; + +void mapAACProfileToAudioFormat( audio_format_t& format, uint64_t eAacProfile) +{ +const struct aac_format_conv_t* p = &profileLookup[0]; + while (p->eAacProfileType != OMX_AUDIO_AACObjectNull) { + if (eAacProfile == p->eAacProfileType) { + format = p->format; + return; + } + ++p; + } + format = AUDIO_FORMAT_AAC; + return; +} + bool canOffloadStream(const sp& meta, bool hasVideo, bool isStreaming, audio_stream_type_t streamType) { @@ -634,15 +668,11 @@ bool canOffloadStream(const sp& meta, bool hasVideo, return false; } - // check whether it is ELD/LD content -> no offloading - // FIXME: this should depend on audio DSP capabilities. mapMimeToAudioFormat() should use the - // metadata to refine the AAC format and the audio HAL should only list supported profiles. + // Redefine aac format according to its profile + // Offloading depends on audio DSP capabilities. int32_t aacaot = -1; if (meta->findInt32(kKeyAACAOT, &aacaot)) { - if (aacaot == 23 || aacaot == 39 ) { - ALOGV("track of type '%s' is ELD/LD content", mime); - return false; - } + mapAACProfileToAudioFormat(info.format,(OMX_AUDIO_AACPROFILETYPE) aacaot); } int32_t srate = -1; -- cgit v1.1 From e125bba94afe74df330c661ab0a64b1e9e2ac5b7 Mon Sep 17 00:00:00 2001 From: aarti jadhav-gaikwad Date: Thu, 19 Jun 2014 17:43:01 +0530 Subject: stagefright: Return correct play position after EOS In case of offload getOutputPlayPositionUs_l returns zero on reaching EOS. Return duration as position. Bug: 15770459 Change-Id: I7aeafdc315a86ccd197d555d604e1069eead3153 --- media/libstagefright/AudioPlayer.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'media') diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index 04fc88b..e24824b 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -766,6 +766,11 @@ int64_t AudioPlayer::getMediaTimeUs() { if (mSeeking) { return mSeekTimeUs; } + if (mReachedEOS) { + int64_t durationUs; + mSource->getFormat()->findInt64(kKeyDuration, &durationUs); + return durationUs; + } mPositionTimeRealUs = getOutputPlayPositionUs_l(); ALOGV("getMediaTimeUs getOutputPlayPositionUs_l() mPositionTimeRealUs %" PRId64, mPositionTimeRealUs); -- cgit v1.1 From 7bad72237b49ac47e77ffe2a89fd26f3d171324c Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Tue, 8 Jul 2014 21:26:53 -0700 Subject: stagefright: add indexed buffer and format getters to MediaCodec These are designed to be called from the same thread as the one calling dequeue?Buffer, and use a mutex to avoid switching context. All other calls of MediaCodec are designed to be blocking and synchronous. Bug: 14297827 Change-Id: If341c6e4407ca6f10f5e0d47008dddc0e20b0a50 --- media/libstagefright/MediaCodec.cpp | 65 ++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 6e3d6f8..1e6ac45 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -410,6 +410,46 @@ status_t MediaCodec::getOutputBuffers(Vector > *buffers) const { return PostAndAwaitResponse(msg, &response); } +status_t MediaCodec::getOutputBuffer(size_t index, sp *buffer) { + sp format; + return getBufferAndFormat(kPortIndexOutput, index, buffer, &format); +} + +status_t MediaCodec::getOutputFormat(size_t index, sp *format) { + sp buffer; + return getBufferAndFormat(kPortIndexOutput, index, &buffer, format); +} + +status_t MediaCodec::getInputBuffer(size_t index, sp *buffer) { + sp format; + return getBufferAndFormat(kPortIndexInput, index, buffer, &format); +} + +status_t MediaCodec::getBufferAndFormat( + size_t portIndex, size_t index, + sp *buffer, sp *format) { + // use mutex instead of a context switch + + buffer->clear(); + format->clear(); + if (mState != STARTED) { + return INVALID_OPERATION; + } + + // we do not want mPortBuffers to change during this section + // we also don't want mOwnedByClient to change during this + Mutex::Autolock al(mBufferLock); + Vector *buffers = &mPortBuffers[portIndex]; + if (index < buffers->size()) { + const BufferInfo &info = buffers->itemAt(index); + if (info.mOwnedByClient) { + *buffer = info.mData; + *format = info.mFormat; + } + } + return OK; +} + status_t MediaCodec::flush() { sp msg = new AMessage(kWhatFlush, id()); @@ -710,6 +750,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { case CodecBase::kWhatBuffersAllocated: { + Mutex::Autolock al(mBufferLock); int32_t portIndex; CHECK(msg->findInt32("portIndex", &portIndex)); @@ -1463,8 +1504,8 @@ void MediaCodec::extractCSD(const sp &format) { status_t MediaCodec::queueCSDInputBuffer(size_t bufferIndex) { CHECK(!mCSD.empty()); - BufferInfo *info = - &mPortBuffers[kPortIndexInput].editItemAt(bufferIndex); + const BufferInfo *info = + &mPortBuffers[kPortIndexInput].itemAt(bufferIndex); sp csd = *mCSD.begin(); mCSD.erase(mCSD.begin()); @@ -1530,6 +1571,7 @@ void MediaCodec::returnBuffersToCodec() { void MediaCodec::returnBuffersToCodecOnPort(int32_t portIndex) { CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput); + Mutex::Autolock al(mBufferLock); Vector *buffers = &mPortBuffers[portIndex]; @@ -1684,11 +1726,15 @@ status_t MediaCodec::onQueueInputBuffer(const sp &msg) { info->mData->setRange(0, result); } + // synchronization boundary for getBufferAndFormat + { + Mutex::Autolock al(mBufferLock); + info->mOwnedByClient = false; + } reply->setBuffer("buffer", info->mData); reply->post(); info->mNotify = NULL; - info->mOwnedByClient = false; return OK; } @@ -1716,6 +1762,12 @@ status_t MediaCodec::onReleaseOutputBuffer(const sp &msg) { return -EACCES; } + // synchronization boundary for getBufferAndFormat + { + Mutex::Autolock al(mBufferLock); + info->mOwnedByClient = false; + } + if (render && info->mData != NULL && info->mData->size() != 0) { info->mNotify->setInt32("render", true); @@ -1743,7 +1795,6 @@ status_t MediaCodec::onReleaseOutputBuffer(const sp &msg) { info->mNotify->post(); info->mNotify = NULL; - info->mOwnedByClient = false; return OK; } @@ -1762,7 +1813,11 @@ ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) { BufferInfo *info = &mPortBuffers[portIndex].editItemAt(index); CHECK(!info->mOwnedByClient); - info->mOwnedByClient = true; + { + Mutex::Autolock al(mBufferLock); + info->mFormat = portIndex == kPortIndexInput ? mInputFormat : mOutputFormat; + info->mOwnedByClient = true; + } return index; } -- cgit v1.1 From c5619c7a6dcc1137fde7520351ad5284e3e958ab Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 8 Jul 2014 18:50:05 -0700 Subject: MediaCodec async callbacks Bug: 11990118 Change-Id: I6fe4b407d9c85cddec8d958620d5d356735273cf --- media/libstagefright/MediaCodec.cpp | 264 +++++++++++++++++++++++------------- 1 file changed, 173 insertions(+), 91 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 1e6ac45..f286659 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -98,6 +98,13 @@ status_t MediaCodec::PostAndAwaitResponse( return err; } +// static +void MediaCodec::PostReplyWithError(int32_t replyID, int32_t err) { + sp response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); +} + status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) { // Current video decoders do not return from OMX_FillThisBuffer // quickly, violating the OpenMAX specs, until that is remedied @@ -155,6 +162,14 @@ status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) { return PostAndAwaitResponse(msg, &response); } +status_t MediaCodec::setCallback(const sp &callback) { + sp msg = new AMessage(kWhatSetCallback, id()); + msg->setMessage("callback", callback); + + sp response; + return PostAndAwaitResponse(msg, &response); +} + status_t MediaCodec::configure( const sp &format, const sp &nativeWindow, @@ -473,9 +488,7 @@ void MediaCodec::requestActivityNotification(const sp ¬ify) { void MediaCodec::cancelPendingDequeueOperations() { if (mFlags & kFlagDequeueInputPending) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - response->postReply(mDequeueInputReplyID); + PostReplyWithError(mDequeueInputReplyID, INVALID_OPERATION); ++mDequeueInputTimeoutGeneration; mDequeueInputReplyID = 0; @@ -483,9 +496,7 @@ void MediaCodec::cancelPendingDequeueOperations() { } if (mFlags & kFlagDequeueOutputPending) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - response->postReply(mDequeueOutputReplyID); + PostReplyWithError(mDequeueOutputReplyID, INVALID_OPERATION); ++mDequeueOutputTimeoutGeneration; mDequeueOutputReplyID = 0; @@ -497,11 +508,7 @@ bool MediaCodec::handleDequeueInputBuffer(uint32_t replyID, bool newRequest) { if (mState != STARTED || (mFlags & kFlagStickyError) || (newRequest && (mFlags & kFlagDequeueInputPending))) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - - response->postReply(replyID); - + PostReplyWithError(replyID, INVALID_OPERATION); return true; } @@ -655,6 +662,10 @@ void MediaCodec::onMessageReceived(const sp &msg) { postActivityNotificationIfPossible(); cancelPendingDequeueOperations(); + + if (mFlags & kFlagIsAsync) { + onError(0, omxError); + } setState(UNINITIALIZED); break; } @@ -665,16 +676,17 @@ void MediaCodec::onMessageReceived(const sp &msg) { mFlags |= kFlagStickyError; postActivityNotificationIfPossible(); + + if (mFlags & kFlagIsAsync) { + onError(0, omxError); + } setState(UNINITIALIZED); break; } } if (sendErrorReponse) { - sp response = new AMessage; - response->setInt32("err", UNKNOWN_ERROR); - - response->postReply(mReplyID); + PostReplyWithError(mReplyID, UNKNOWN_ERROR); } break; } @@ -845,6 +857,8 @@ void MediaCodec::onMessageReceived(const sp &msg) { // collect codec specific data and amend the output // format as necessary. mFlags |= kFlagGatherCodecSpecificData; + } else if (mFlags & kFlagIsAsync) { + onOutputFormatChanged(); } else { mFlags |= kFlagOutputFormatChanged; postActivityNotificationIfPossible(); @@ -887,7 +901,9 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } - if (mFlags & kFlagDequeueInputPending) { + if (mFlags & kFlagIsAsync) { + onInputBufferAvailable(); + } else if (mFlags & kFlagDequeueInputPending) { CHECK(handleDequeueInputBuffer(mDequeueInputReplyID)); ++mDequeueInputTimeoutGeneration; @@ -934,10 +950,16 @@ void MediaCodec::onMessageReceived(const sp &msg) { } mFlags &= ~kFlagGatherCodecSpecificData; - mFlags |= kFlagOutputFormatChanged; + if (mFlags & kFlagIsAsync) { + onOutputFormatChanged(); + } else { + mFlags |= kFlagOutputFormatChanged; + } } - if (mFlags & kFlagDequeueOutputPending) { + if (mFlags & kFlagIsAsync) { + onOutputBufferAvailable(); + } else if (mFlags & kFlagDequeueOutputPending) { CHECK(handleDequeueOutputBuffer(mDequeueOutputReplyID)); ++mDequeueOutputTimeoutGeneration; @@ -993,10 +1015,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->senderAwaitsResponse(&replyID)); if (mState != UNINITIALIZED) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - - response->postReply(replyID); + PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1026,16 +1045,45 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } + case kWhatSetCallback: + { + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + if (mState == UNINITIALIZED + || mState == INITIALIZING + || mState == STARTED) { + // callback can't be set after codec is started, + // or before it's initialized (as the callback + // will be cleared when it goes to INITIALIZED) + PostReplyWithError(replyID, INVALID_OPERATION); + break; + } + + sp callback; + CHECK(msg->findMessage("callback", &callback)); + + mCallback = callback; + + if (mCallback != NULL) { + ALOGI("MediaCodec will operate in async mode"); + mFlags |= kFlagIsAsync; + } else { + mFlags &= ~kFlagIsAsync; + } + + sp response = new AMessage; + response->postReply(replyID); + break; + } + case kWhatConfigure: { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (mState != INITIALIZED) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - - response->postReply(replyID); + PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1055,10 +1103,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { ->getSurfaceTextureClient()); if (err != OK) { - sp response = new AMessage; - response->setInt32("err", err); - - response->postReply(replyID); + PostReplyWithError(replyID, err); break; } } else { @@ -1096,10 +1141,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { // Must be configured, but can't have been started yet. if (mState != CONFIGURED) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - - response->postReply(replyID); + PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1114,10 +1156,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->senderAwaitsResponse(&replyID)); if (mState != CONFIGURED) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - - response->postReply(replyID); + PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1178,11 +1217,15 @@ void MediaCodec::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); + if (mFlags & kFlagIsAsync) { + ALOGE("dequeueOutputBuffer can't be used in async mode"); + PostReplyWithError(replyID, INVALID_OPERATION); + break; + } + if (mHaveInputSurface) { ALOGE("dequeueInputBuffer can't be used with input surface"); - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - response->postReply(replyID); + PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1194,9 +1237,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->findInt64("timeoutUs", &timeoutUs)); if (timeoutUs == 0ll) { - sp response = new AMessage; - response->setInt32("err", -EAGAIN); - response->postReply(replyID); + PostReplyWithError(replyID, -EAGAIN); break; } @@ -1225,9 +1266,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(mFlags & kFlagDequeueInputPending); - sp response = new AMessage; - response->setInt32("err", -EAGAIN); - response->postReply(mDequeueInputReplyID); + PostReplyWithError(mDequeueInputReplyID, -EAGAIN); mFlags &= ~kFlagDequeueInputPending; mDequeueInputReplyID = 0; @@ -1240,18 +1279,13 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->senderAwaitsResponse(&replyID)); if (mState != STARTED || (mFlags & kFlagStickyError)) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - - response->postReply(replyID); + PostReplyWithError(replyID, INVALID_OPERATION); break; } status_t err = onQueueInputBuffer(msg); - sp response = new AMessage; - response->setInt32("err", err); - response->postReply(replyID); + PostReplyWithError(replyID, err); break; } @@ -1260,6 +1294,12 @@ void MediaCodec::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); + if (mFlags & kFlagIsAsync) { + ALOGE("dequeueOutputBuffer can't be used in async mode"); + PostReplyWithError(replyID, INVALID_OPERATION); + break; + } + if (handleDequeueOutputBuffer(replyID, true /* new request */)) { break; } @@ -1268,9 +1308,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->findInt64("timeoutUs", &timeoutUs)); if (timeoutUs == 0ll) { - sp response = new AMessage; - response->setInt32("err", -EAGAIN); - response->postReply(replyID); + PostReplyWithError(replyID, -EAGAIN); break; } @@ -1299,9 +1337,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(mFlags & kFlagDequeueOutputPending); - sp response = new AMessage; - response->setInt32("err", -EAGAIN); - response->postReply(mDequeueOutputReplyID); + PostReplyWithError(mDequeueOutputReplyID, -EAGAIN); mFlags &= ~kFlagDequeueOutputPending; mDequeueOutputReplyID = 0; @@ -1314,18 +1350,13 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->senderAwaitsResponse(&replyID)); if (mState != STARTED || (mFlags & kFlagStickyError)) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - - response->postReply(replyID); + PostReplyWithError(replyID, INVALID_OPERATION); break; } status_t err = onReleaseOutputBuffer(msg); - sp response = new AMessage; - response->setInt32("err", err); - response->postReply(replyID); + PostReplyWithError(replyID, err); break; } @@ -1335,10 +1366,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->senderAwaitsResponse(&replyID)); if (mState != STARTED || (mFlags & kFlagStickyError)) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - - response->postReply(replyID); + PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1353,10 +1381,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->senderAwaitsResponse(&replyID)); if (mState != STARTED || (mFlags & kFlagStickyError)) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - - response->postReply(replyID); + PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1387,10 +1412,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->senderAwaitsResponse(&replyID)); if (mState != STARTED || (mFlags & kFlagStickyError)) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - - response->postReply(replyID); + PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1415,10 +1437,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { mState != STARTED && mState != FLUSHING) || (mFlags & kFlagStickyError) || format == NULL) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - - response->postReply(replyID); + PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1449,10 +1468,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->senderAwaitsResponse(&replyID)); if (mComponentName.empty()) { - sp response = new AMessage; - response->setInt32("err", INVALID_OPERATION); - - response->postReply(replyID); + PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1472,10 +1488,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { status_t err = onSetParameters(params); - sp response = new AMessage; - response->setInt32("err", err); - - response->postReply(replyID); + PostReplyWithError(replyID, err); break; } @@ -1546,8 +1559,10 @@ void MediaCodec::setState(State newState) { mFlags &= ~kFlagStickyError; mFlags &= ~kFlagIsEncoder; mFlags &= ~kFlagGatherCodecSpecificData; + mFlags &= ~kFlagIsAsync; mActivityNotify.clear(); + mCallback.clear(); } if (newState == UNINITIALIZED) { @@ -1855,6 +1870,73 @@ status_t MediaCodec::setNativeWindow( return OK; } +void MediaCodec::onInputBufferAvailable() { + int32_t index; + while ((index = dequeuePortBuffer(kPortIndexInput)) >= 0) { + sp msg = mCallback->dup(); + msg->setInt32("callbackID", CB_INPUT_AVAILABLE); + msg->setInt32("index", index); + msg->post(); + } +} + +void MediaCodec::onOutputBufferAvailable() { + int32_t index; + while ((index = dequeuePortBuffer(kPortIndexOutput)) >= 0) { + const sp &buffer = + mPortBuffers[kPortIndexOutput].itemAt(index).mData; + sp msg = mCallback->dup(); + msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE); + msg->setInt32("index", index); + msg->setSize("offset", buffer->offset()); + msg->setSize("size", buffer->size()); + + int64_t timeUs; + CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); + + msg->setInt64("timeUs", timeUs); + + int32_t omxFlags; + CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags)); + + uint32_t flags = 0; + if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) { + flags |= BUFFER_FLAG_SYNCFRAME; + } + if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) { + flags |= BUFFER_FLAG_CODECCONFIG; + } + if (omxFlags & OMX_BUFFERFLAG_EOS) { + flags |= BUFFER_FLAG_EOS; + } + + msg->setInt32("flags", flags); + + msg->post(); + } +} + +void MediaCodec::onError(int32_t actionCode, status_t err) { + if (mCallback != NULL) { + sp msg = mCallback->dup(); + msg->setInt32("callbackID", CB_ERROR); + msg->setInt32("actionCode", actionCode); + msg->setInt32("err", err); + + msg->post(); + } +} + +void MediaCodec::onOutputFormatChanged() { + if (mCallback != NULL) { + sp msg = mCallback->dup(); + msg->setInt32("callbackID", CB_OUTPUT_FORMAT_CHANGED); + msg->setMessage("format", mOutputFormat); + msg->post(); + } +} + + void MediaCodec::postActivityNotificationIfPossible() { if (mActivityNotify == NULL) { return; -- cgit v1.1 From 8e6912423c3be3fc2f4bab8ac815f0dce075ded8 Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Fri, 11 Jul 2014 17:37:32 -0700 Subject: Use a better and more direct API to mark a socket as if it were a user's. Change-Id: If525ee259b74314191d1913f7c2a3e828e05c38f --- media/libstagefright/Android.mk | 4 ++-- media/libstagefright/HTTPBase.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 99c8e9f..be9af5e 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -65,16 +65,15 @@ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/av/include/media/stagefright/timedtext \ $(TOP)/frameworks/native/include/media/hardware \ $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/native/services/connectivitymanager \ $(TOP)/external/flac/include \ $(TOP)/external/tremolo \ $(TOP)/external/openssl/include \ $(TOP)/external/libvpx/libwebm \ + $(TOP)/system/netd/include \ LOCAL_SHARED_LIBRARIES := \ libbinder \ libcamera_client \ - libconnectivitymanager \ libcutils \ libdl \ libdrmframework \ @@ -84,6 +83,7 @@ LOCAL_SHARED_LIBRARIES := \ libicuuc \ liblog \ libmedia \ + libnetd_client \ libopus \ libsonivox \ libssl \ diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp index ca68c3d..32291c8 100644 --- a/media/libstagefright/HTTPBase.cpp +++ b/media/libstagefright/HTTPBase.cpp @@ -26,7 +26,7 @@ #include #include -#include +#include namespace android { @@ -122,7 +122,7 @@ void HTTPBase::UnRegisterSocketUserTag(int sockfd) { // static void HTTPBase::RegisterSocketUserMark(int sockfd, uid_t uid) { - ConnectivityManager::markSocketAsUser(sockfd, uid); + setNetworkForUser(uid, sockfd); } // static -- cgit v1.1 From 749dafad09d85f2aaf6902a7ff16b4087e3bc4c7 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Fri, 11 Jul 2014 16:17:14 -0700 Subject: MediaCodec: change onError cb to return CodecException Bug: 11990118 Change-Id: I3278aecb20df88c42fa2709a66e6166eb3cbe56f --- media/libstagefright/MediaCodec.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index f286659..24fd7ad 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -664,7 +664,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { cancelPendingDequeueOperations(); if (mFlags & kFlagIsAsync) { - onError(0, omxError); + onError(omxError, 0); } setState(UNINITIALIZED); break; @@ -678,7 +678,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { postActivityNotificationIfPossible(); if (mFlags & kFlagIsAsync) { - onError(0, omxError); + onError(omxError, 0); } setState(UNINITIALIZED); break; @@ -1916,12 +1916,16 @@ void MediaCodec::onOutputBufferAvailable() { } } -void MediaCodec::onError(int32_t actionCode, status_t err) { +void MediaCodec::onError(status_t err, int32_t actionCode, const char *detail) { if (mCallback != NULL) { sp msg = mCallback->dup(); msg->setInt32("callbackID", CB_ERROR); - msg->setInt32("actionCode", actionCode); msg->setInt32("err", err); + msg->setInt32("actionCode", actionCode); + + if (detail != NULL) { + msg->setString("detail", detail); + } msg->post(); } -- cgit v1.1 From f6ef963fecde3b63696028fadce4bcfb5b998db0 Mon Sep 17 00:00:00 2001 From: Naveen Kumar Ponnusamy Date: Tue, 1 Jul 2014 15:10:40 -0700 Subject: Resolution reinitialization changes Decoder initialized to 320x240. When higher resolution comes, the decoder reinitialized to the resolution. Bug: 14571712 Change-Id: I6b6ad17dd87f0112ce7ccf4f6c17bb4c65b5d8af --- media/libstagefright/codecs/hevcdec/SoftHEVC.cpp | 220 ++++++++++++----------- media/libstagefright/codecs/hevcdec/SoftHEVC.h | 12 +- 2 files changed, 125 insertions(+), 107 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp index 0aae5ed..b0d0827 100644 --- a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp +++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp @@ -66,7 +66,7 @@ SoftHEVC::SoftHEVC( OMX_COMPONENTTYPE **component) : SoftVideoDecoderOMXComponent(name, componentName, codingType, kProfileLevels, ARRAY_SIZE(kProfileLevels), - CODEC_MAX_WIDTH /* width */, CODEC_MAX_HEIGHT /* height */, callbacks, + 320 /* width */, 240 /* height */, callbacks, appData, component) { initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE); @@ -104,7 +104,7 @@ static size_t GetCPUCoreCount() { return (size_t)cpuCoreCount; } -status_t SoftHEVC::getVersion() { +void SoftHEVC::logVersion() { ivd_ctl_getversioninfo_ip_t s_ctl_ip; ivd_ctl_getversioninfo_op_t s_ctl_op; UWORD8 au1_buf[512]; @@ -127,18 +127,18 @@ status_t SoftHEVC::getVersion() { ALOGD("Ittiam decoder version number: %s", (char *)s_ctl_ip.pv_version_buffer); } - return OK; + return; } -status_t SoftHEVC::setParams(WORD32 stride, IVD_VIDEO_DECODE_MODE_T decMode) { +status_t SoftHEVC::setParams(size_t stride) { ivd_ctl_set_config_ip_t s_ctl_ip; ivd_ctl_set_config_op_t s_ctl_op; IV_API_CALL_STATUS_T status; - s_ctl_ip.u4_disp_wd = stride; + s_ctl_ip.u4_disp_wd = (UWORD32)stride; s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE; s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT; - s_ctl_ip.e_vid_dec_mode = decMode; + s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME; s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS; s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); @@ -188,7 +188,7 @@ status_t SoftHEVC::resetDecoder() { } /* Set the run-time (dynamic) parameters */ - setParams(0, IVD_DECODE_FRAME); + setParams(0); /* Set number of cores/threads to be used by the codec */ setNumCores(); @@ -250,6 +250,8 @@ status_t SoftHEVC::initDecoder() { WORD32 i4_level; mNumCores = GetCPUCoreCount(); + mMemRecords = NULL; + mFlushOutBuffer = NULL; /* Initialize number of ref and reorder modes (for HEVC) */ u4_num_reorder_frames = 16; @@ -259,11 +261,16 @@ status_t SoftHEVC::initDecoder() { if ((mWidth * mHeight) > (1920 * 1088)) { i4_level = 50; } else if ((mWidth * mHeight) > (1280 * 720)) { - i4_level = 41; - } else { + i4_level = 40; + } else if ((mWidth * mHeight) > (960 * 540)) { i4_level = 31; + } else if ((mWidth * mHeight) > (640 * 360)) { + i4_level = 30; + } else if ((mWidth * mHeight) > (352 * 288)) { + i4_level = 21; + } else { + i4_level = 20; } - { iv_num_mem_rec_ip_t s_num_mem_rec_ip; iv_num_mem_rec_op_t s_num_mem_rec_op; @@ -291,6 +298,8 @@ status_t SoftHEVC::initDecoder() { return NO_MEMORY; } + memset(mMemRecords, 0, mNumMemRecords * sizeof(iv_mem_rec_t)); + { size_t i; ivdext_fill_mem_rec_ip_t s_fill_mem_ip; @@ -386,13 +395,13 @@ status_t SoftHEVC::initDecoder() { resetPlugin(); /* Set the run time (dynamic) parameters */ - setParams(0, IVD_DECODE_FRAME); + setParams(0); /* Set number of cores/threads to be used by the codec */ setNumCores(); /* Get codec version */ - getVersion(); + logVersion(); /* Allocate internal picture buffer */ mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, mStride * mHeight * 3 / 2); @@ -406,19 +415,40 @@ status_t SoftHEVC::initDecoder() { status_t SoftHEVC::deInitDecoder() { size_t i; - iv_mem_rec_t *ps_mem_rec; - ps_mem_rec = mMemRecords; - ALOGD("Freeing codec memory"); - for (i = 0; i < mNumMemRecords; i++) { - ivd_aligned_free(ps_mem_rec->pv_base); - ps_mem_rec++; + + if (mMemRecords) { + iv_mem_rec_t *ps_mem_rec; + + ps_mem_rec = mMemRecords; + ALOGD("Freeing codec memory"); + for (i = 0; i < mNumMemRecords; i++) { + if(ps_mem_rec->pv_base) { + ivd_aligned_free(ps_mem_rec->pv_base); + } + ps_mem_rec++; + } + ivd_aligned_free(mMemRecords); } - ivd_aligned_free(mMemRecords); - ivd_aligned_free(mFlushOutBuffer); + if(mFlushOutBuffer) { + ivd_aligned_free(mFlushOutBuffer); + } return OK; } +status_t SoftHEVC::reInitDecoder() { + status_t ret; + + deInitDecoder(); + + ret = initDecoder(); + if (OK != ret) { + ALOGE("Create failure"); + deInitDecoder(); + return NO_MEMORY; + } + return OK; +} void SoftHEVC::onReset() { ALOGD("onReset called"); SoftVideoDecoderOMXComponent::onReset(); @@ -427,6 +457,50 @@ void SoftHEVC::onReset() { resetPlugin(); } +void SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip, + ivd_video_decode_op_t *ps_dec_op, + OMX_BUFFERHEADERTYPE *inHeader, + OMX_BUFFERHEADERTYPE *outHeader, + size_t sizeY, + size_t timeStampIx) { + size_t sizeUV; + uint8_t *pBuf; + + ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t); + ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t); + + ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE; + + /* When in flush and after EOS with zero byte input, + * inHeader is set to zero. Hence check for non-null */ + if (inHeader) { + ps_dec_ip->u4_ts = timeStampIx; + ps_dec_ip->pv_stream_buffer = inHeader->pBuffer + + inHeader->nOffset; + ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen; + } else { + ps_dec_ip->u4_ts = 0; + ps_dec_ip->pv_stream_buffer = NULL; + ps_dec_ip->u4_num_Bytes = 0; + } + + if (outHeader) { + pBuf = outHeader->pBuffer; + } else { + pBuf = mFlushOutBuffer; + } + + sizeUV = sizeY / 4; + ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY; + ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV; + ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV; + + ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf; + ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY; + ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV; + ps_dec_ip->s_out_buffer.u4_num_bufs = 3; + return; +} void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { ALOGD("onPortFlushCompleted on port %d", portIndex); @@ -434,37 +508,13 @@ void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { if (kOutputPortIndex == portIndex) { setFlushMode(); - /* Reset the time stamp arrays */ - memset(mTimeStamps, 0, sizeof(mTimeStamps)); - memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); - while (true) { ivd_video_decode_ip_t s_dec_ip; ivd_video_decode_op_t s_dec_op; IV_API_CALL_STATUS_T status; size_t sizeY, sizeUV; - s_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE; - - s_dec_ip.u4_ts = 0; - s_dec_ip.pv_stream_buffer = NULL; - s_dec_ip.u4_num_Bytes = 0; - - s_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t); - s_dec_op.u4_size = sizeof(ivd_video_decode_op_t); - - sizeY = mStride * mHeight; - sizeUV = sizeY / 4; - s_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = sizeY; - s_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = sizeUV; - s_dec_ip.s_out_buffer.u4_min_out_buf_size[2] = sizeUV; - - s_dec_ip.s_out_buffer.pu1_bufs[0] = mFlushOutBuffer; - s_dec_ip.s_out_buffer.pu1_bufs[1] = - s_dec_ip.s_out_buffer.pu1_bufs[0] + sizeY; - s_dec_ip.s_out_buffer.pu1_bufs[2] = - s_dec_ip.s_out_buffer.pu1_bufs[1] + sizeUV; - s_dec_ip.s_out_buffer.u4_num_bufs = 3; + setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, mStride * mHeight, 0); status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); @@ -558,36 +608,8 @@ void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { WORD32 timeDelay, timeTaken; size_t sizeY, sizeUV; - s_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE; - - /* When in flush and after EOS with zero byte input, - * inHeader is set to zero. Hence check for non-null */ - if (inHeader != NULL) { - s_dec_ip.u4_ts = timeStampIx; - s_dec_ip.pv_stream_buffer = inHeader->pBuffer - + inHeader->nOffset; - s_dec_ip.u4_num_Bytes = inHeader->nFilledLen; - } else { - s_dec_ip.u4_ts = 0; - s_dec_ip.pv_stream_buffer = NULL; - s_dec_ip.u4_num_Bytes = 0; - } - - s_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t); - s_dec_op.u4_size = sizeof(ivd_video_decode_op_t); - - sizeY = mStride * mHeight; - sizeUV = sizeY / 4; - s_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = sizeY; - s_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = sizeUV; - s_dec_ip.s_out_buffer.u4_min_out_buf_size[2] = sizeUV; - - s_dec_ip.s_out_buffer.pu1_bufs[0] = outHeader->pBuffer; - s_dec_ip.s_out_buffer.pu1_bufs[1] = - s_dec_ip.s_out_buffer.pu1_bufs[0] + sizeY; - s_dec_ip.s_out_buffer.pu1_bufs[2] = - s_dec_ip.s_out_buffer.pu1_bufs[1] + sizeUV; - s_dec_ip.s_out_buffer.u4_num_bufs = 3; + setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, + mStride * mHeight, timeStampIx); GETTIME(&mTimeStart, NULL); /* Compute time elapsed between end of previous decode() @@ -604,6 +626,23 @@ void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { ALOGD("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, s_dec_op.u4_num_bytes_consumed); + /* If width and height are greater than the + * the dimensions used during codec create, then + * delete the current instance and recreate an instance with + * new dimensions */ + + if(IHEVCD_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code) { + mInitWidth = s_dec_op.u4_pic_wd; + mInitHeight = s_dec_op.u4_pic_ht; + mStride = mInitWidth; + CHECK_EQ(reInitDecoder(), (status_t)OK); + + setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, + mStride * mHeight, timeStampIx); + + status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, + (void *)&s_dec_op); + } if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { /* If the input did not contain picture data, then ignore * the associated timestamp */ @@ -616,40 +655,11 @@ void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { uint32_t width = s_dec_op.u4_pic_wd; uint32_t height = s_dec_op.u4_pic_ht; - if ((width != mWidth || height != mHeight)) { + if ((width != mWidth) || (height != mHeight)) { mWidth = width; mHeight = height; mStride = mWidth; - /* If width and height are greater than the - * the dimensions used during codec create, then - * delete the current instance and recreate an instance with - * new dimensions */ - /* TODO: The following does not work currently, since the decoder - * currently returns 0 x 0 as width height when it is not supported - * Once the decoder is updated to return actual width and height, - * then this can be validated*/ - - if ((mWidth * mHeight) > (mInitWidth * mInitHeight)) { - status_t ret; - ALOGD("Trying reInit"); - ret = deInitDecoder(); - if (OK != ret) { - // TODO: Handle graceful exit - ALOGE("Create failure"); - return; - } - - mInitWidth = mWidth; - mInitHeight = mHeight; - - ret = initDecoder(); - if (OK != ret) { - // TODO: Handle graceful exit - ALOGE("Create failure"); - return; - } - } updatePortDefinitions(); notify(OMX_EventPortSettingsChanged, 1, 0, NULL); diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.h b/media/libstagefright/codecs/hevcdec/SoftHEVC.h index 20db0e1..233db0c 100644 --- a/media/libstagefright/codecs/hevcdec/SoftHEVC.h +++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.h @@ -103,11 +103,19 @@ private: status_t initDecoder(); status_t deInitDecoder(); status_t setFlushMode(); - status_t setParams(WORD32 stride, IVD_VIDEO_DECODE_MODE_T decMode); - status_t getVersion(); + status_t setParams(size_t stride); + void logVersion(); status_t setNumCores(); status_t resetDecoder(); status_t resetPlugin(); + status_t reInitDecoder(); + + void setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip, + ivd_video_decode_op_t *ps_dec_op, + OMX_BUFFERHEADERTYPE *inHeader, + OMX_BUFFERHEADERTYPE *outHeader, + size_t sizeY, + size_t timeStampIx); DISALLOW_EVIL_CONSTRUCTORS (SoftHEVC); }; -- cgit v1.1 From e580006cd0067109189975c56395d29309d49883 Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Mon, 7 Jul 2014 19:26:31 -0700 Subject: Encoder input buffers don't need HW_TEXTURE usage Change-Id: Ibb1be86ae99439ccbce3fc2b38d92115083ef7ff --- media/libstagefright/omx/GraphicBufferSource.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 67e6d7b..fad6c33 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -75,8 +75,7 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, BufferQueue::createBufferQueue(&mProducer, &mConsumer); mConsumer->setConsumerName(name); mConsumer->setDefaultBufferSize(bufferWidth, bufferHeight); - mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER | - GRALLOC_USAGE_HW_TEXTURE); + mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER); mInitCheck = mConsumer->setMaxAcquiredBufferCount(bufferCount); if (mInitCheck != NO_ERROR) { -- cgit v1.1 From 333f66d4642ddd36b42668da2767551ba25f0248 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 8 Jul 2014 16:31:40 -0700 Subject: DO NOT MERGE LVM virtualizer: add support for virtualizer capability query Change-Id: I88106ba25f9b3f8fd7616307ab6b7fbe7afb6e91 (cherry picked from commit bfd3b9764841971be2d2f04a3fdbd41a2144beea) --- .../libeffects/lvm/wrapper/Bundle/EffectBundle.cpp | 291 ++++++++++++++++++--- media/libeffects/lvm/wrapper/Bundle/EffectBundle.h | 2 + 2 files changed, 257 insertions(+), 36 deletions(-) (limited to 'media') diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index 38ee82b..6c2cbe3 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -223,6 +223,8 @@ extern "C" int EffectCreate(const effect_uuid_t *uuid, pContext->pBundledContext->bBassTempDisabled = LVM_FALSE; pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE; pContext->pBundledContext->bVirtualizerTempDisabled = LVM_FALSE; + pContext->pBundledContext->nOutputDevice = AUDIO_DEVICE_NONE; + pContext->pBundledContext->nVirtualizerForcedDevice = AUDIO_DEVICE_NONE; pContext->pBundledContext->NumberEffectsEnabled = 0; pContext->pBundledContext->NumberEffectsCalled = 0; pContext->pBundledContext->firstVolume = LVM_TRUE; @@ -1166,6 +1168,177 @@ void VirtualizerSetStrength(EffectContext *pContext, uint32_t strength){ //ALOGV("\tVirtualizerSetStrength Succesfully called LVM_SetControlParameters\n\n"); } /* end setStrength */ +//---------------------------------------------------------------------------- +// VirtualizerIsDeviceSupported() +//---------------------------------------------------------------------------- +// Purpose: +// Check if an audio device type is supported by this implementation +// +// Inputs: +// deviceType the type of device that affects the processing (e.g. for binaural vs transaural) +// Output: +// -EINVAL if the configuration is not supported or it is unknown +// 0 if the configuration is supported +//---------------------------------------------------------------------------- +int VirtualizerIsDeviceSupported(audio_devices_t deviceType) { + switch (deviceType) { + case AUDIO_DEVICE_OUT_WIRED_HEADSET: + case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: + case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES: + return 0; + default : + return -EINVAL; + } +} + +//---------------------------------------------------------------------------- +// VirtualizerIsConfigurationSupported() +//---------------------------------------------------------------------------- +// Purpose: +// Check if a channel mask + audio device type is supported by this implementation +// +// Inputs: +// channelMask the channel mask of the input to virtualize +// deviceType the type of device that affects the processing (e.g. for binaural vs transaural) +// Output: +// -EINVAL if the configuration is not supported or it is unknown +// 0 if the configuration is supported +//---------------------------------------------------------------------------- +int VirtualizerIsConfigurationSupported(audio_channel_mask_t channelMask, + audio_devices_t deviceType) { + uint32_t channelCount = audio_channel_count_from_out_mask(channelMask); + if ((channelCount == 0) || (channelCount > 2)) { + return -EINVAL; + } + + return VirtualizerIsDeviceSupported(deviceType); +} + +//---------------------------------------------------------------------------- +// VirtualizerForceVirtualizationMode() +//---------------------------------------------------------------------------- +// Purpose: +// Force the virtualization mode to that of the given audio device +// +// Inputs: +// pContext effect engine context +// forcedDevice the type of device whose virtualization mode we'll always use +// Output: +// -EINVAL if the device is not supported or is unknown +// 0 if the device is supported and the virtualization mode forced +// +//---------------------------------------------------------------------------- +int VirtualizerForceVirtualizationMode(EffectContext *pContext, audio_devices_t forcedDevice) { + ALOGV("VirtualizerForceVirtualizationMode: forcedDev=0x%x enabled=%d tmpDisabled=%d", + forcedDevice, pContext->pBundledContext->bVirtualizerEnabled, + pContext->pBundledContext->bVirtualizerTempDisabled); + int status = 0; + bool useVirtualizer = false; + + if (VirtualizerIsDeviceSupported(forcedDevice) != 0) { + // forced device is not supported, make it behave as a reset of forced mode + forcedDevice = AUDIO_DEVICE_NONE; + // but return an error + status = -EINVAL; + } + + if (forcedDevice == AUDIO_DEVICE_NONE) { + // disabling forced virtualization mode: + // verify whether the virtualization should be enabled or disabled + if (VirtualizerIsDeviceSupported(pContext->pBundledContext->nOutputDevice) == 0) { + useVirtualizer = (pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE); + } + pContext->pBundledContext->nVirtualizerForcedDevice = AUDIO_DEVICE_NONE; + } else { + // forcing virtualization mode: here we already know the device is supported + pContext->pBundledContext->nVirtualizerForcedDevice = AUDIO_DEVICE_OUT_WIRED_HEADPHONE; + // only enable for a supported mode, when the effect is enabled + useVirtualizer = (pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE); + } + + if (useVirtualizer) { + if (pContext->pBundledContext->bVirtualizerTempDisabled == LVM_TRUE) { + ALOGV("\tVirtualizerForceVirtualizationMode re-enable LVM_VIRTUALIZER"); + android::LvmEffect_enable(pContext); + pContext->pBundledContext->bVirtualizerTempDisabled = LVM_FALSE; + } else { + ALOGV("\tVirtualizerForceVirtualizationMode leaving LVM_VIRTUALIZER enabled"); + } + } else { + if (pContext->pBundledContext->bVirtualizerTempDisabled == LVM_FALSE) { + ALOGV("\tVirtualizerForceVirtualizationMode disable LVM_VIRTUALIZER"); + android::LvmEffect_disable(pContext); + pContext->pBundledContext->bVirtualizerTempDisabled = LVM_TRUE; + } else { + ALOGV("\tVirtualizerForceVirtualizationMode leaving LVM_VIRTUALIZER disabled"); + } + } + + ALOGV("\tafter VirtualizerForceVirtualizationMode: enabled=%d tmpDisabled=%d", + pContext->pBundledContext->bVirtualizerEnabled, + pContext->pBundledContext->bVirtualizerTempDisabled); + + return status; +} +//---------------------------------------------------------------------------- +// VirtualizerGetSpeakerAngles() +//---------------------------------------------------------------------------- +// Purpose: +// Get the virtual speaker angles for a channel mask + audio device type +// configuration which is guaranteed to be supported by this implementation +// +// Inputs: +// channelMask: the channel mask of the input to virtualize +// deviceType the type of device that affects the processing (e.g. for binaural vs transaural) +// Input/Output: +// pSpeakerAngles the array of integer where each speaker angle is written as a triplet in the +// following format: +// int32_t a bit mask with a single value selected for each speaker, following +// the convention of the audio_channel_mask_t type +// int32_t a value in degrees expressing the speaker azimuth, where 0 is in front +// of the user, 180 behind, -90 to the left, 90 to the right of the user +// int32_t a value in degrees expressing the speaker elevation, where 0 is the +// horizontal plane, +90 is directly above the user, -90 below +// +//---------------------------------------------------------------------------- +void VirtualizerGetSpeakerAngles(audio_channel_mask_t channelMask __unused, + audio_devices_t deviceType __unused, int32_t *pSpeakerAngles) { + // the channel count is guaranteed to be 1 or 2 + // the device is guaranteed to be of type headphone + // this virtualizer is always 2in with speakers at -90 and 90deg of azimuth, 0deg of elevation + *pSpeakerAngles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_LEFT; + *pSpeakerAngles++ = -90; // azimuth + *pSpeakerAngles++ = 0; // elevation + *pSpeakerAngles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_RIGHT; + *pSpeakerAngles++ = 90; // azimuth + *pSpeakerAngles = 0; // elevation +} + +//---------------------------------------------------------------------------- +// VirtualizerGetVirtualizationMode() +//---------------------------------------------------------------------------- +// Purpose: +// Retrieve the current device whose processing mode is used by this effect +// +// Output: +// AUDIO_DEVICE_NONE if the effect is not virtualizing +// or the device type if the effect is virtualizing +//---------------------------------------------------------------------------- +audio_devices_t VirtualizerGetVirtualizationMode(EffectContext *pContext) { + audio_devices_t virtDevice = AUDIO_DEVICE_NONE; + if ((pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE) + && (pContext->pBundledContext->bVirtualizerTempDisabled == LVM_FALSE)) { + if (pContext->pBundledContext->nVirtualizerForcedDevice != AUDIO_DEVICE_NONE) { + // virtualization mode is forced, return that device + virtDevice = pContext->pBundledContext->nVirtualizerForcedDevice; + } else { + // no forced mode, return the current device + virtDevice = pContext->pBundledContext->nOutputDevice; + } + } + ALOGV("VirtualizerGetVirtualizationMode() returning 0x%x", virtDevice); + return virtDevice; +} //---------------------------------------------------------------------------- // EqualizerLimitBandLevels() @@ -1903,7 +2076,17 @@ int Virtualizer_getParameter(EffectContext *pContext, } *pValueSize = sizeof(int16_t); break; - + case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES: + // return value size can only be interpreted as relative to input value, + // deferring validity check to below + break; + case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE: + if (*pValueSize != sizeof(uint32_t)){ + ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize); + return -EINVAL; + } + *pValueSize = sizeof(uint32_t); + break; default: ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid param %d", param); return -EINVAL; @@ -1924,13 +2107,36 @@ int Virtualizer_getParameter(EffectContext *pContext, // *(int16_t *)pValue); break; + case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES: { + const audio_channel_mask_t channelMask = (audio_channel_mask_t) *pParamTemp++; + const audio_devices_t deviceType = (audio_devices_t) *pParamTemp; + uint32_t nbChannels = audio_channel_count_from_out_mask(channelMask); + if (*pValueSize < 3 * nbChannels * sizeof(int32_t)){ + ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize); + return -EINVAL; + } + // verify the configuration is supported + status = VirtualizerIsConfigurationSupported(channelMask, deviceType); + if (status == 0) { + ALOGV("VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES supports mask=0x%x device=0x%x", + channelMask, deviceType); + // configuration is supported, get the angles + VirtualizerGetSpeakerAngles(channelMask, deviceType, (int32_t *)pValue); + } + } + break; + + case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE: + *(uint32_t *)pValue = (uint32_t) VirtualizerGetVirtualizationMode(pContext); + break; + default: ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid param %d", param); status = -EINVAL; break; } - //ALOGV("\tVirtualizer_getParameter end"); + ALOGV("\tVirtualizer_getParameter end returning status=%d", status); return status; } /* end Virtualizer_getParameter */ @@ -1965,6 +2171,15 @@ int Virtualizer_setParameter (EffectContext *pContext, void *pParam, void *pValu VirtualizerSetStrength(pContext, (int32_t)strength); //ALOGV("\tVirtualizer_setParameter() Called pVirtualizer->setStrength"); break; + + case VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE: { + const audio_devices_t deviceType = *(audio_devices_t *) pValue; + status = VirtualizerForceVirtualizationMode(pContext, deviceType); + //ALOGV("VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE device=0x%x result=%d", + // deviceType, status); + } + break; + default: ALOGV("\tLVM_ERROR : Virtualizer_setParameter() invalid param %d", param); break; @@ -2865,7 +3080,6 @@ int Effect_command(effect_handle_t self, (void *)p->data, &p->vsize, p->data + voffset); - *replySize = sizeof(effect_param_t) + voffset + p->vsize; //ALOGV("\tVirtualizer_command EFFECT_CMD_GET_PARAM " @@ -2976,14 +3190,17 @@ int Effect_command(effect_handle_t self, p->data + p->psize); } if(pContext->EffectType == LVM_VIRTUALIZER){ + // Warning this log will fail to properly read an int32_t value, assumes int16_t //ALOGV("\tVirtualizer_command EFFECT_CMD_SET_PARAM param %d, *replySize %d, value %d", // *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)), // *replySize, // *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t))); - if (pCmdData == NULL|| - cmdSize != (sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int16_t))|| - pReplyData == NULL|| + if (pCmdData == NULL || + // legal parameters are int16_t or int32_t + cmdSize > (sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int32_t)) || + cmdSize < (sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int16_t)) || + pReplyData == NULL || *replySize != sizeof(int32_t)){ ALOGV("\tLVM_ERROR : Virtualizer_command cmdCode Case: " "EFFECT_CMD_SET_PARAM: ERROR"); @@ -3075,6 +3292,7 @@ int Effect_command(effect_handle_t self, { ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_DEVICE start"); uint32_t device = *(uint32_t *)pCmdData; + pContext->pBundledContext->nOutputDevice = (audio_devices_t) device; if (pContext->EffectType == LVM_BASS_BOOST) { if((device == AUDIO_DEVICE_OUT_SPEAKER) || @@ -3110,37 +3328,38 @@ int Effect_command(effect_handle_t self, } } if (pContext->EffectType == LVM_VIRTUALIZER) { - if((device == AUDIO_DEVICE_OUT_SPEAKER)|| - (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT)|| - (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)){ - ALOGV("\tEFFECT_CMD_SET_DEVICE device is invalid for LVM_VIRTUALIZER %d", - *(int32_t *)pCmdData); - ALOGV("\tEFFECT_CMD_SET_DEVICE temporary disable LVM_VIRTUALIZER"); - - //If a device doesnt support virtualizer the effect must be temporarily disabled - // the effect must still report its original state as this can only be changed - // by the ENABLE/DISABLE command - - if (pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE) { - ALOGV("\tEFFECT_CMD_SET_DEVICE disable LVM_VIRTUALIZER %d", - *(int32_t *)pCmdData); - android::LvmEffect_disable(pContext); - } - pContext->pBundledContext->bVirtualizerTempDisabled = LVM_TRUE; - } else { - ALOGV("\tEFFECT_CMD_SET_DEVICE device is valid for LVM_VIRTUALIZER %d", - *(int32_t *)pCmdData); - - // If a device supports virtualizer and the effect has been temporarily disabled - // previously then re-enable it - - if(pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE){ - ALOGV("\tEFFECT_CMD_SET_DEVICE re-enable LVM_VIRTUALIZER %d", - *(int32_t *)pCmdData); - android::LvmEffect_enable(pContext); + if (pContext->pBundledContext->nVirtualizerForcedDevice == AUDIO_DEVICE_NONE) { + // default case unless configuration is forced + if (android::VirtualizerIsDeviceSupported(device) != 0) { + ALOGV("\tEFFECT_CMD_SET_DEVICE device is invalid for LVM_VIRTUALIZER %d", + *(int32_t *)pCmdData); + ALOGV("\tEFFECT_CMD_SET_DEVICE temporary disable LVM_VIRTUALIZER"); + + //If a device doesnt support virtualizer the effect must be temporarily + // disabled the effect must still report its original state as this can + // only be changed by the ENABLE/DISABLE command + + if (pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE) { + ALOGV("\tEFFECT_CMD_SET_DEVICE disable LVM_VIRTUALIZER %d", + *(int32_t *)pCmdData); + android::LvmEffect_disable(pContext); + } + pContext->pBundledContext->bVirtualizerTempDisabled = LVM_TRUE; + } else { + ALOGV("\tEFFECT_CMD_SET_DEVICE device is valid for LVM_VIRTUALIZER %d", + *(int32_t *)pCmdData); + + // If a device supports virtualizer and the effect has been temporarily + // disabled previously then re-enable it + + if(pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE){ + ALOGV("\tEFFECT_CMD_SET_DEVICE re-enable LVM_VIRTUALIZER %d", + *(int32_t *)pCmdData); + android::LvmEffect_enable(pContext); + } + pContext->pBundledContext->bVirtualizerTempDisabled = LVM_FALSE; } - pContext->pBundledContext->bVirtualizerTempDisabled = LVM_FALSE; - } + } // else virtualization mode is forced to a certain device, nothing to do } ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_DEVICE end"); break; diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h index 330bb32..420f973 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h @@ -73,6 +73,8 @@ struct BundledEffectContext{ bool bBassTempDisabled; /* Flag for Bass to be re-enabled */ bool bVirtualizerEnabled; /* Flag for Virtualizer */ bool bVirtualizerTempDisabled; /* Flag for effect to be re-enabled */ + audio_devices_t nOutputDevice; /* Output device for the effect */ + audio_devices_t nVirtualizerForcedDevice; /* Forced device virtualization mode*/ int NumberEffectsEnabled; /* Effects in this session */ int NumberEffectsCalled; /* Effects called so far */ bool firstVolume; /* No smoothing on first Vol change */ -- cgit v1.1 From 671160ffe81592efa376dc1ff0fc3f4ddcdebc35 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Tue, 15 Jul 2014 07:56:04 -0700 Subject: stagefright: add MediaCodec.reset() Bug: 12034929 Change-Id: I326f1356df89474aa088c1c87f8505b33654139d --- media/libstagefright/MediaCodec.cpp | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'media') diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 24fd7ad..7a9cb0b 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -106,6 +106,11 @@ void MediaCodec::PostReplyWithError(int32_t replyID, int32_t err) { } status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) { + // save init parameters for reset + mInitName = name; + mInitNameIsType = nameIsType; + mInitIsEncoder = encoder; + // Current video decoders do not return from OMX_FillThisBuffer // quickly, violating the OpenMAX specs, until that is remedied // we need to invest in an extra looper to free the main event @@ -235,6 +240,40 @@ status_t MediaCodec::release() { return PostAndAwaitResponse(msg, &response); } +status_t MediaCodec::reset() { + /* When external-facing MediaCodec object is created, + it is already initialized. Thus, reset is essentially + release() followed by init(), plus clearing the state */ + + status_t err = release(); + + // unregister handlers + if (mCodec != NULL) { + if (mCodecLooper != NULL) { + mCodecLooper->unregisterHandler(mCodec->id()); + } else { + mLooper->unregisterHandler(mCodec->id()); + } + mCodec = NULL; + } + mLooper->unregisterHandler(id()); + + mFlags = 0; // clear all flags + + // reset state not reset by setState(UNINITIALIZED) + mReplyID = 0; + mDequeueInputReplyID = 0; + mDequeueOutputReplyID = 0; + mDequeueInputTimeoutGeneration = 0; + mDequeueOutputTimeoutGeneration = 0; + mHaveInputSurface = false; + + if (err == OK) { + err = init(mInitName.c_str(), mInitNameIsType, mInitIsEncoder); + } + return err; +} + status_t MediaCodec::queueInputBuffer( size_t index, size_t offset, @@ -1553,6 +1592,7 @@ void MediaCodec::setState(State newState) { mCrypto.clear(); setNativeWindow(NULL); + mInputFormat.clear(); mOutputFormat.clear(); mFlags &= ~kFlagOutputFormatChanged; mFlags &= ~kFlagOutputBuffersChanged; @@ -1566,6 +1606,9 @@ void MediaCodec::setState(State newState) { } if (newState == UNINITIALIZED) { + // 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 -- cgit v1.1 From a8454c29b15748964b5eb556d1e23fbb1ee19ceb Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 14 Jul 2014 09:35:25 -0700 Subject: Fix M3UParser relative path handling. Bug: 16017037 Change-Id: Ibfff99387fb5b3e721144a2b3f9174092d785137 --- media/libstagefright/httplive/M3UParser.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 281e0da..4f7668c 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -413,6 +413,8 @@ static bool MakeURL(const char *baseURL, const char *url, AString *out) { // Base URL must be absolute return false; } + const size_t schemeEnd = (strstr(baseURL, "//") - baseURL) + 2; + CHECK(schemeEnd == 7 || schemeEnd == 8); if (!strncasecmp("http://", url, 7) || !strncasecmp("https://", url, 8)) { // "url" is already an absolute URL, ignore base URL. @@ -457,7 +459,7 @@ static bool MakeURL(const char *baseURL, const char *url, AString *out) { // Check whether the found slash actually is part of the path // and not part of the "http://". - if (end > 6) { + if (end >= schemeEnd) { out->setTo(baseURL, end); } else { out->setTo(baseURL); -- cgit v1.1 From dd235727a1b4e283deeb581559f99c2c8889da07 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 12 Jun 2014 14:49:23 -0700 Subject: GenericSource: implement getTrackCount/getTrackInfo Bug: 15153976 Change-Id: I0204c4188d485cda026497469c7cde24f7bd5c95 --- .../nuplayer/GenericSource.cpp | 59 ++++++++++++++++++++-- .../libmediaplayerservice/nuplayer/GenericSource.h | 5 ++ 2 files changed, 61 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 388f77a..cc0cb01 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -81,11 +81,12 @@ void NuPlayer::GenericSource::initFromDataSource( const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); - sp track; + sp track = extractor->getTrack(i); if (!strncasecmp(mime, "audio/", 6)) { if (mAudioTrack.mSource == NULL) { - mAudioTrack.mSource = track = extractor->getTrack(i); + mAudioTrack.mIndex = i; + mAudioTrack.mSource = track; if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { mAudioIsVorbis = true; @@ -95,11 +96,13 @@ void NuPlayer::GenericSource::initFromDataSource( } } else if (!strncasecmp(mime, "video/", 6)) { if (mVideoTrack.mSource == NULL) { - mVideoTrack.mSource = track = extractor->getTrack(i); + mVideoTrack.mIndex = i; + mVideoTrack.mSource = track; } } if (track != NULL) { + mSources.push(track); int64_t durationUs; if (meta->findInt64(kKeyDuration, &durationUs)) { if (durationUs > mDurationUs) { @@ -194,6 +197,56 @@ status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) { return OK; } +size_t NuPlayer::GenericSource::getTrackCount() const { + return mSources.size(); +} + +sp NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { + size_t trackCount = mSources.size(); + if (trackIndex >= trackCount) { + return NULL; + } + + sp format = new AMessage(); + sp meta = mSources.itemAt(trackIndex)->getFormat(); + + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + + int32_t trackType; + if (!strncasecmp(mime, "video/", 6)) { + trackType = MEDIA_TRACK_TYPE_VIDEO; + } else if (!strncasecmp(mime, "audio/", 6)) { + trackType = MEDIA_TRACK_TYPE_AUDIO; + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { + trackType = MEDIA_TRACK_TYPE_TIMEDTEXT; + } else { + trackType = MEDIA_TRACK_TYPE_UNKNOWN; + } + format->setInt32("type", trackType); + + const char *lang; + if (!meta->findCString(kKeyMediaLanguage, &lang)) { + lang = "und"; + } + format->setString("language", lang); + + if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { + format->setString("mime", mime); + + int32_t isAutoselect = 1, isDefault = 0, isForced = 0; + meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect); + meta->findInt32(kKeyTrackIsDefault, &isDefault); + meta->findInt32(kKeyTrackIsForced, &isForced); + + format->setInt32("auto", !!isAutoselect); + format->setInt32("default", !!isDefault); + format->setInt32("forced", !!isForced); + } + + return format; +} + status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { if (mVideoTrack.mSource != NULL) { int64_t actualTimeUs; diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 20d597e..e0cd20f 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -50,6 +50,8 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual status_t dequeueAccessUnit(bool audio, sp *accessUnit); virtual status_t getDuration(int64_t *durationUs); + virtual size_t getTrackCount() const; + virtual sp getTrackInfo(size_t trackIndex) const; virtual status_t seekTo(int64_t seekTimeUs); protected: @@ -58,7 +60,10 @@ protected: virtual sp getFormatMeta(bool audio); private: + Vector > mSources; + struct Track { + size_t mIndex; sp mSource; sp mPackets; }; -- cgit v1.1 From 5154f98277922aba7103ac19529ecc00b1889c1e Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 16 Jul 2014 15:27:43 -0700 Subject: M3UParser: check for NULL before setting meta data Bug:16351654 Change-Id: I64e9510f719b220471522b4d78a9b00a98bda772 --- media/libstagefright/httplive/M3UParser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'media') diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 4f7668c..efd852c 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -730,6 +730,9 @@ status_t M3UParser::parseStreamInf( key.tolower(); const AString &codecs = unquoteString(val); + if (meta->get() == NULL) { + *meta = new AMessage; + } (*meta)->setString(key.c_str(), codecs.c_str()); } else if (!strcasecmp("audio", key.c_str()) || !strcasecmp("video", key.c_str()) @@ -753,6 +756,9 @@ status_t M3UParser::parseStreamInf( } key.tolower(); + if (meta->get() == NULL) { + *meta = new AMessage; + } (*meta)->setString(key.c_str(), groupID.c_str()); } } -- cgit v1.1 From 7a727021b86c2fb2c9f60af2c999154dce1766eb Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Thu, 17 Jul 2014 16:20:13 -0700 Subject: stagefright: add error log when create omx component failed Bug: 16343447 Change-Id: I6854b9b837a141a77ab318953dc002ec5ad5d31d --- media/libstagefright/ACodec.cpp | 2 ++ media/libstagefright/omx/OMX.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 9c64d72..fdb401a 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -3989,6 +3989,8 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp &msg) { if (err == OK) { break; + } else { + ALOGW("Allocating component '%s' failed, try next one.", componentName.c_str()); } node = NULL; diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index 22b12d9..cc4770a 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -233,7 +233,7 @@ status_t OMX::allocateNode( instance, &handle); if (err != OMX_ErrorNone) { - ALOGV("FAILED to allocate omx component '%s'", name); + ALOGE("FAILED to allocate omx component '%s'", name); instance->onGetHandleFailed(); -- cgit v1.1 From ec40d284218466d8f0e832e7eb88e6ea6c479c88 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 15 Jul 2014 15:31:26 -0700 Subject: Add audio_input_flags_t to IAudioFlinger::openInput For backward compatibility, until flags are correctly calculated, we will assume that the request is for a low latency input stream. Change-Id: I76746834e870df00833dc77cbdaa2edd2ffeec95 --- media/libmedia/IAudioFlinger.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 5cf42f7..7795fdb 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -532,7 +532,8 @@ public: audio_devices_t *pDevices, uint32_t *pSamplingRate, audio_format_t *pFormat, - audio_channel_mask_t *pChannelMask) + audio_channel_mask_t *pChannelMask, + audio_input_flags_t flags) { Parcel data, reply; audio_devices_t devices = pDevices != NULL ? *pDevices : AUDIO_DEVICE_NONE; @@ -547,6 +548,7 @@ public: data.writeInt32(samplingRate); data.writeInt32(format); data.writeInt32(channelMask); + data.writeInt32(flags); remote()->transact(OPEN_INPUT, data, &reply); audio_io_handle_t input = (audio_io_handle_t) reply.readInt32(); devices = (audio_devices_t)reply.readInt32(); @@ -1157,12 +1159,14 @@ status_t BnAudioFlinger::onTransact( uint32_t samplingRate = data.readInt32(); audio_format_t format = (audio_format_t) data.readInt32(); audio_channel_mask_t channelMask = (audio_channel_mask_t)data.readInt32(); + audio_input_flags_t flags = (audio_input_flags_t) data.readInt32(); audio_io_handle_t input = openInput(module, &devices, &samplingRate, &format, - &channelMask); + &channelMask, + flags); reply->writeInt32((int32_t) input); reply->writeInt32(devices); reply->writeInt32(samplingRate); -- cgit v1.1 From b3b1660ecb67f61f9da54efced8677fa3a6f4863 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 16 Jul 2014 08:36:31 -0700 Subject: Add audio_input_flags_t to IAudioPolicyService::getInput Change-Id: I9f37be05f8dc7b85a8827a94e76ca0f45453e170 --- media/libmedia/AudioRecord.cpp | 6 +++--- media/libmedia/AudioSystem.cpp | 5 +++-- media/libmedia/IAudioPolicyService.cpp | 8 ++++++-- 3 files changed, 12 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 3ee5809..c474a25 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -481,11 +481,11 @@ status_t AudioRecord::openRecord_l(size_t epoch) } audio_io_handle_t input = AudioSystem::getInput(mInputSource, mSampleRate, mFormat, - mChannelMask, mSessionId); + mChannelMask, mSessionId, mFlags); if (input == AUDIO_IO_HANDLE_NONE) { ALOGE("Could not get audio input for record source %d, sample rate %u, format %#x, " - "channel mask %#x, session %d", - mInputSource, mSampleRate, mFormat, mChannelMask, mSessionId); + "channel mask %#x, session %d, flags %#x", + mInputSource, mSampleRate, mFormat, mChannelMask, mSessionId, mFlags); return BAD_VALUE; } { diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index a47d45c..fd5824b 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -688,11 +688,12 @@ audio_io_handle_t AudioSystem::getInput(audio_source_t inputSource, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, - int sessionId) + int sessionId, + audio_input_flags_t flags) { const sp& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return 0; - return aps->getInput(inputSource, samplingRate, format, channelMask, sessionId); + return aps->getInput(inputSource, samplingRate, format, channelMask, sessionId, flags); } status_t AudioSystem::startInput(audio_io_handle_t input) diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 41a9065..40dfb58 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -225,7 +225,8 @@ public: uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, - int audioSession) + int audioSession, + audio_input_flags_t flags) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); @@ -234,6 +235,7 @@ public: data.writeInt32(static_cast (format)); data.writeInt32(channelMask); data.writeInt32(audioSession); + data.writeInt32(flags); remote()->transact(GET_INPUT, data, &reply); return static_cast (reply.readInt32()); } @@ -707,11 +709,13 @@ status_t BnAudioPolicyService::onTransact( audio_format_t format = (audio_format_t) data.readInt32(); audio_channel_mask_t channelMask = data.readInt32(); int audioSession = data.readInt32(); + audio_input_flags_t flags = (audio_input_flags_t) data.readInt32(); audio_io_handle_t input = getInput(inputSource, samplingRate, format, channelMask, - audioSession); + audioSession, + flags); reply->writeInt32(static_cast (input)); return NO_ERROR; } break; -- cgit v1.1 From 7410591dad836434c72ddee66680802708b70c10 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 3 Jul 2014 12:28:53 -0700 Subject: Move AudioRecord frame count calculations to server Buffer frame count and notification frame count are now calculated by server instead of by client. The server has more information and can do a better job. Also fix a few bugs: - If a fast track was re-created, even with same pipe depth, it would fail. Now it can correctly re-create a fast track provided the pipe depth is same. - Notification frame count for fast tracks was calculated by client as 1/2 of the total frame count, which is a large value due to the pipe. Now the notification frame count is set by server to the HAL frame count. This should reduce latency for fast tracks. - EVENT_OVERRUN were happening frequently when there was sample rate conversion, because the client didn't know about the sample rate conversion, and under-estimated the necessary buffer size. Now since server calculates the buffer sizes, EVENT_OVERRUN is unlikely. - RecordThread::createRecordTrack_l was checking for mono and stereo for fast tracks. This is not necessary, and now we can handle a multi-channel fast track. Bug: 7498763 Change-Id: I0c581618e8db33084d5ff9ed50a592990c9749e8 --- media/libmedia/AudioRecord.cpp | 53 +++++++--------------------------------- media/libmedia/IAudioFlinger.cpp | 3 ++- 2 files changed, 11 insertions(+), 45 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index c474a25..80c8c5e 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -211,7 +211,7 @@ status_t AudioRecord::set( mReqFrameCount = frameCount; mNotificationFramesReq = notificationFrames; - mNotificationFramesAct = 0; + // mNotificationFramesAct is initialized in openRecord_l if (sessionId == AUDIO_SESSION_ALLOCATE) { mSessionId = AudioSystem::newAudioSessionId(); @@ -444,42 +444,6 @@ status_t AudioRecord::openRecord_l(size_t epoch) } } - // FIXME Assume double buffering, because we don't know the true HAL sample rate - const uint32_t nBuffering = 2; - - mNotificationFramesAct = mNotificationFramesReq; - size_t frameCount = mReqFrameCount; - - if (!(mFlags & AUDIO_INPUT_FLAG_FAST)) { - // validate framecount - // If fast track was not requested, this preserves - // the old behavior of validating on client side. - // FIXME Eventually the validation should be done on server side - // regardless of whether it's a fast or normal track. It's debatable - // whether to account for the input latency to provision buffers appropriately. - size_t minFrameCount; - status = AudioRecord::getMinFrameCount(&minFrameCount, - mSampleRate, mFormat, mChannelMask); - if (status != NO_ERROR) { - ALOGE("getMinFrameCount() failed for sampleRate %u, format %#x, channelMask %#x; " - "status %d", - mSampleRate, mFormat, mChannelMask, status); - return status; - } - - if (frameCount == 0) { - frameCount = minFrameCount; - } else if (frameCount < minFrameCount) { - ALOGE("frameCount %zu < minFrameCount %zu", frameCount, minFrameCount); - return BAD_VALUE; - } - - // Make sure that application is notified with sufficient margin before overrun - if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/2) { - mNotificationFramesAct = frameCount/2; - } - } - audio_io_handle_t input = AudioSystem::getInput(mInputSource, mSampleRate, mFormat, mChannelMask, mSessionId, mFlags); if (input == AUDIO_IO_HANDLE_NONE) { @@ -492,12 +456,13 @@ status_t AudioRecord::openRecord_l(size_t epoch) // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger, // we must release it ourselves if anything goes wrong. + size_t frameCount = mReqFrameCount; size_t temp = frameCount; // temp may be replaced by a revised value of frameCount, // but we will still need the original value also int originalSessionId = mSessionId; // The notification frame count is the period between callbacks, as suggested by the server. - size_t notificationFrames; + size_t notificationFrames = mNotificationFramesReq; sp iMem; // for cblk sp bufferMem; @@ -576,14 +541,14 @@ status_t AudioRecord::openRecord_l(size_t epoch) // once denied, do not request again if IAudioRecord is re-created mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST); } - // Theoretically double-buffering is not required for fast tracks, - // due to tighter scheduling. But in practice, to accomodate kernels with - // scheduling jitter, and apps with computation jitter, we use double-buffering. - if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/nBuffering) { - mNotificationFramesAct = frameCount/nBuffering; - } } + // Make sure that application is notified with sufficient margin before overrun + if (notificationFrames == 0 || notificationFrames > frameCount) { + ALOGW("Received notificationFrames %zu for frameCount %zu", notificationFrames, frameCount); + } + mNotificationFramesAct = notificationFrames; + // We retain a copy of the I/O handle, but don't own the reference mInput = input; mRefreshRemaining = true; diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 7795fdb..bd7ea46 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -197,6 +197,7 @@ public: lSessionId = *sessionId; } data.writeInt32(lSessionId); + data.writeInt64(notificationFrames != NULL ? *notificationFrames : 0); cblk.clear(); buffers.clear(); status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply); @@ -966,7 +967,7 @@ status_t BnAudioFlinger::onTransact( track_flags_t flags = (track_flags_t) data.readInt32(); pid_t tid = (pid_t) data.readInt32(); int sessionId = data.readInt32(); - size_t notificationFrames = 0; + size_t notificationFrames = data.readInt64(); sp cblk; sp buffers; status_t status; -- cgit v1.1 From d8cf55d878edddfc36bb821a95b88dfb2453c2c3 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 17 Jul 2014 11:46:13 -0700 Subject: MediaWriter: make get/setStartTimeOffsetMs virtual Bug: 16329805 Change-Id: Ib971dd95b54829438c8af97528f9e00b87ab3f1e --- media/libstagefright/webm/WebmWriter.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'media') diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/WebmWriter.h index 529dec8..36b6965 100644 --- a/media/libstagefright/webm/WebmWriter.h +++ b/media/libstagefright/webm/WebmWriter.h @@ -41,14 +41,14 @@ public: ~WebmWriter() { reset(); } - status_t addSource(const sp &source); - status_t start(MetaData *param = NULL); - status_t stop(); - status_t pause(); - bool reachedEOS(); - - void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; } - int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; } + virtual status_t addSource(const sp &source); + virtual status_t start(MetaData *param = NULL); + virtual status_t stop(); + virtual status_t pause(); + virtual bool reachedEOS(); + + virtual void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; } + virtual int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; } private: int mFd; -- cgit v1.1 From 513d967dae82cd03e67bff17b927cf869d9bc43e Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Tue, 15 Jul 2014 07:57:52 -0700 Subject: Add MediaCodecList capabilities Bug: 12065651 Change-Id: Icfb73c0009621cd747e113d8a0cd84c966bf055d --- media/libstagefright/MediaCodecList.cpp | 295 ++++++++++++++++++++++++++- media/libstagefright/foundation/AMessage.cpp | 19 ++ 2 files changed, 313 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index cd51582..d1e9272 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -79,6 +80,19 @@ void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml) { info->mName.c_str()); mCodecInfos.removeAt(i); +#if LOG_NDEBUG == 0 + } else { + for (size_t type_ix = 0; type_ix < mTypes.size(); ++type_ix) { + uint32_t typeMask = 1ul << mTypes.valueAt(type_ix); + if (info->mTypes & typeMask) { + AString mime = mTypes.keyAt(type_ix); + uint32_t bit = mTypes.valueAt(type_ix); + + ALOGV("%s codec info for %s: %s", info->mName.c_str(), mime.c_str(), + info->mCaps.editValueFor(bit)->debugString().c_str()); + } + } +#endif } } @@ -217,6 +231,8 @@ void MediaCodecList::startElementHandler( return; } + bool inType = true; + if (!strcmp(name, "Include")) { mInitCheck = includeXMLFile(attrs); if (mInitCheck == OK) { @@ -267,6 +283,26 @@ void MediaCodecList::startElementHandler( mInitCheck = addQuirk(attrs); } else if (!strcmp(name, "Type")) { mInitCheck = addTypeFromAttributes(attrs); + mCurrentSection = + (mCurrentSection == SECTION_DECODER + ? SECTION_DECODER_TYPE : SECTION_ENCODER_TYPE); + } + } + inType = false; + // fall through + + case SECTION_DECODER_TYPE: + case SECTION_ENCODER_TYPE: + { + CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); + // ignore limits and features specified outside of type + bool outside = !inType && info->mSoleType == 0; + if (outside && (!strcmp(name, "Limit") || !strcmp(name, "Feature"))) { + ALOGW("ignoring %s specified outside of a Type", name); + } else if (!strcmp(name, "Limit")) { + mInitCheck = addLimit(attrs); + } else if (!strcmp(name, "Feature")) { + mInitCheck = addFeature(attrs); } break; } @@ -300,10 +336,27 @@ void MediaCodecList::endElementHandler(const char *name) { break; } + case SECTION_DECODER_TYPE: + case SECTION_ENCODER_TYPE: + { + if (!strcmp(name, "Type")) { + mCurrentSection = + (mCurrentSection == SECTION_DECODER_TYPE + ? SECTION_DECODER : SECTION_ENCODER); + + CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); + info->mCurrentCaps = NULL; + } + break; + } + case SECTION_DECODER: { if (!strcmp(name, "MediaCodec")) { mCurrentSection = SECTION_DECODERS; + + CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); + info->mCurrentCaps = NULL; } break; } @@ -312,6 +365,9 @@ void MediaCodecList::endElementHandler(const char *name) { { if (!strcmp(name, "MediaCodec")) { mCurrentSection = SECTION_ENCODERS; + + CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); + info->mCurrentCaps = NULL; } break; } @@ -373,11 +429,16 @@ void MediaCodecList::addMediaCodec( CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); info->mName = name; info->mIsEncoder = encoder; + info->mSoleType = 0; info->mTypes = 0; info->mQuirks = 0; + info->mCurrentCaps = NULL; if (type != NULL) { addType(type); + // if type was specified in attributes, we do not allow + // subsequent types + info->mSoleType = info->mTypes; } } @@ -427,6 +488,12 @@ status_t MediaCodecList::addQuirk(const char **attrs) { status_t MediaCodecList::addTypeFromAttributes(const char **attrs) { const char *name = NULL; + CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); + if (info->mSoleType != 0) { + ALOGE("Codec '%s' already had its type specified", info->mName.c_str()); + return -EINVAL; + } + size_t i = 0; while (attrs[i] != NULL) { if (!strcmp(attrs[i], "name")) { @@ -469,6 +536,11 @@ void MediaCodecList::addType(const char *name) { CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); info->mTypes |= 1ul << bit; + if (info->mCaps.indexOfKey(bit) < 0) { + AMessage *msg = new AMessage(); + info->mCaps.add(bit, msg); + } + info->mCurrentCaps = info->mCaps.editValueFor(bit); } ssize_t MediaCodecList::findCodecByType( @@ -494,6 +566,216 @@ ssize_t MediaCodecList::findCodecByType( return -ENOENT; } +static status_t limitFoundMissingAttr(AString name, const char *attr, bool found = true) { + ALOGE("limit '%s' with %s'%s' attribute", name.c_str(), + (found ? "" : "no "), attr); + return -EINVAL; +} + +static status_t limitError(AString name, const char *msg) { + ALOGE("limit '%s' %s", name.c_str(), msg); + return -EINVAL; +} + +static status_t limitInvalidAttr(AString name, const char *attr, AString value) { + ALOGE("limit '%s' with invalid '%s' attribute (%s)", name.c_str(), + attr, value.c_str()); + return -EINVAL; +} + +status_t MediaCodecList::addLimit(const char **attrs) { + sp msg = new AMessage(); + + size_t i = 0; + while (attrs[i] != NULL) { + if (attrs[i + 1] == NULL) { + return -EINVAL; + } + + // attributes with values + if (!strcmp(attrs[i], "name") + || !strcmp(attrs[i], "default") + || !strcmp(attrs[i], "in") + || !strcmp(attrs[i], "max") + || !strcmp(attrs[i], "min") + || !strcmp(attrs[i], "range") + || !strcmp(attrs[i], "ranges") + || !strcmp(attrs[i], "scale") + || !strcmp(attrs[i], "value")) { + msg->setString(attrs[i], attrs[i + 1]); + ++i; + } else { + return -EINVAL; + } + ++i; + } + + AString name; + if (!msg->findString("name", &name)) { + ALOGE("limit with no 'name' attribute"); + return -EINVAL; + } + + CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); + + // size, blocks, bitrate, frame-rate, blocks-per-second, aspect-ratio: range + // quality: range + default + [scale] + // complexity: range + default + bool found; + if (name == "aspect-ratio" || name == "bitrate" || name == "block-count" + || name == "blocks-per-second" || name == "complexity" + || name == "frame-rate" || name == "quality" || name == "size") { + AString min, max; + if (msg->findString("min", &min) && msg->findString("max", &max)) { + min.append("-"); + min.append(max); + if (msg->contains("range") || msg->contains("value")) { + return limitError(name, "has 'min' and 'max' as well as 'range' or " + "'value' attributes"); + } + msg->setString("range", min); + } else if (msg->contains("min") || msg->contains("max")) { + return limitError(name, "has only 'min' or 'max' attribute"); + } else if (msg->findString("value", &max)) { + min = max; + min.append("-"); + min.append(max); + if (msg->contains("range")) { + return limitError(name, "has both 'range' and 'value' attributes"); + } + msg->setString("range", min); + } + + AString range, scale = "linear", def, in_; + if (!msg->findString("range", &range)) { + return limitError(name, "with no 'range', 'value' or 'min'/'max' attributes"); + } + + if ((name == "quality" || name == "complexity") ^ + (found = msg->findString("default", &def))) { + return limitFoundMissingAttr(name, "default", found); + } + if (name != "quality" && msg->findString("scale", &scale)) { + return limitFoundMissingAttr(name, "scale"); + } + if ((name == "aspect-ratio") ^ (found = msg->findString("in", &in_))) { + return limitFoundMissingAttr(name, "in", found); + } + + if (name == "aspect-ratio") { + if (!(in_ == "pixels") && !(in_ == "blocks")) { + return limitInvalidAttr(name, "in", in_); + } + in_.erase(5, 1); // (pixel|block)-aspect-ratio + in_.append("-"); + in_.append(name); + name = in_; + } + if (name == "quality") { + info->mCurrentCaps->setString("quality-scale", scale); + } + if (name == "quality" || name == "complexity") { + AString tag = name; + tag.append("-default"); + info->mCurrentCaps->setString(tag.c_str(), def); + } + AString tag = name; + tag.append("-range"); + info->mCurrentCaps->setString(tag.c_str(), range); + } else { + AString max, value, ranges; + if (msg->contains("default")) { + return limitFoundMissingAttr(name, "default"); + } else if (msg->contains("in")) { + return limitFoundMissingAttr(name, "in"); + } else if ((name == "channel-count") ^ + (found = msg->findString("max", &max))) { + return limitFoundMissingAttr(name, "max", found); + } else if (msg->contains("min")) { + return limitFoundMissingAttr(name, "min"); + } else if (msg->contains("range")) { + return limitFoundMissingAttr(name, "range"); + } else if ((name == "sample-rate") ^ + (found = msg->findString("ranges", &ranges))) { + return limitFoundMissingAttr(name, "ranges", found); + } else if (msg->contains("scale")) { + return limitFoundMissingAttr(name, "scale"); + } else if ((name == "alignment" || name == "block-size") ^ + (found = msg->findString("value", &value))) { + return limitFoundMissingAttr(name, "value", found); + } + + if (max.size()) { + AString tag = "max-"; + tag.append(name); + info->mCurrentCaps->setString(tag.c_str(), max); + } else if (value.size()) { + info->mCurrentCaps->setString(name.c_str(), value); + } else if (ranges.size()) { + AString tag = name; + tag.append("-ranges"); + info->mCurrentCaps->setString(tag.c_str(), ranges); + } else { + ALOGW("Ignoring unrecognized limit '%s'", name.c_str()); + } + } + return OK; +} + +static bool parseBoolean(const char *s) { + if (!strcasecmp(s, "true") || !strcasecmp(s, "yes") || !strcasecmp(s, "y")) { + return true; + } + char *end; + unsigned long res = strtoul(s, &end, 10); + return *s != '\0' && *end == '\0' && res > 0; +} + +status_t MediaCodecList::addFeature(const char **attrs) { + size_t i = 0; + const char *name = NULL; + int32_t optional = -1; + int32_t required = -1; + + while (attrs[i] != NULL) { + if (attrs[i + 1] == NULL) { + return -EINVAL; + } + + // attributes with values + if (!strcmp(attrs[i], "name")) { + name = attrs[i + 1]; + ++i; + } else if (!strcmp(attrs[i], "optional") || !strcmp(attrs[i], "required")) { + int value = (int)parseBoolean(attrs[i + 1]); + if (!strcmp(attrs[i], "optional")) { + optional = value; + } else { + required = value; + } + ++i; + } else { + return -EINVAL; + } + ++i; + } + if (name == NULL) { + ALOGE("feature with no 'name' attribute"); + return -EINVAL; + } + + if (optional == required && optional != -1) { + ALOGE("feature '%s' is both/neither optional and required", name); + return -EINVAL; + } + + CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); + AString tag = "feature-"; + tag.append(name); + info->mCurrentCaps->setInt32(tag.c_str(), (required == 1) || (optional == 0)); + return OK; +} + ssize_t MediaCodecList::findCodecByName(const char *name) const { for (size_t i = 0; i < mCodecInfos.size(); ++i) { const CodecInfo &info = mCodecInfos.itemAt(i); @@ -571,7 +853,8 @@ status_t MediaCodecList::getCodecCapabilities( size_t index, const char *type, Vector *profileLevels, Vector *colorFormats, - uint32_t *flags) const { + uint32_t *flags, + sp *capabilities) const { profileLevels->clear(); colorFormats->clear(); @@ -581,6 +864,11 @@ status_t MediaCodecList::getCodecCapabilities( const CodecInfo &info = mCodecInfos.itemAt(index); + ssize_t typeIndex = mTypes.indexOfKey(type); + if (typeIndex < 0) { + return -EINVAL; + } + OMXClient client; status_t err = client.connect(); if (err != OK) { @@ -611,6 +899,11 @@ status_t MediaCodecList::getCodecCapabilities( *flags = caps.mFlags; + // TODO this check will be removed once JNI side is merged + if (capabilities != NULL) { + *capabilities = info.mCaps.valueFor(typeIndex); + } + return OK; } diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp index dc42f91..d268aa4 100644 --- a/media/libstagefright/foundation/AMessage.cpp +++ b/media/libstagefright/foundation/AMessage.cpp @@ -127,6 +127,20 @@ const AMessage::Item *AMessage::findItem( return NULL; } +bool AMessage::contains(const char *name) const { + name = AAtomizer::Atomize(name); + + for (size_t i = 0; i < mNumItems; ++i) { + const Item *item = &mItems[i]; + + if (item->mName == name) { + return true; + } + } + + return false; +} + #define BASIC_TYPE(NAME,FIELDNAME,TYPENAME) \ void AMessage::set##NAME(const char *name, TYPENAME value) { \ Item *item = allocateItem(name); \ @@ -160,6 +174,11 @@ void AMessage::setString( item->u.stringValue = new AString(s, len < 0 ? strlen(s) : len); } +void AMessage::setString( + const char *name, const AString &s) { + setString(name, s.c_str(), s.size()); +} + void AMessage::setObjectInternal( const char *name, const sp &obj, Type type) { Item *item = allocateItem(name); -- cgit v1.1 From 8eebda045d865c2e23fc439e87fe915467812967 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 17 Jul 2014 14:17:09 -0700 Subject: stagefright: add nonblocking read option to MediaBuffer Bug: 15699665 Change-Id: I2aaddc4c937cf5c1e36386bafd7d396d5781bf6d --- media/libstagefright/MediaSource.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'media') diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp index fd0e79c..576471a 100644 --- a/media/libstagefright/MediaSource.cpp +++ b/media/libstagefright/MediaSource.cpp @@ -32,6 +32,19 @@ void MediaSource::ReadOptions::reset() { mOptions = 0; mSeekTimeUs = 0; mLatenessUs = 0; + mNonBlocking = false; +} + +void MediaSource::ReadOptions::setNonBlocking() { + mNonBlocking = true; +} + +void MediaSource::ReadOptions::clearNonBlocking() { + mNonBlocking = false; +} + +bool MediaSource::ReadOptions::getNonBlocking() const { + return mNonBlocking; } void MediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) { -- cgit v1.1 From c9a11abbb6b48604ea063daedd6118024cfbfa92 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 17 Jul 2014 14:23:16 -0700 Subject: stagefright: add nonblocking MediaBufferGroup.acquire_buffer method Bug: 15699665 Change-Id: I31c1ab4413c62ff3dd4e0d5b06a398064b4aaddd --- media/libstagefright/MediaBufferGroup.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/MediaBufferGroup.cpp b/media/libstagefright/MediaBufferGroup.cpp index 80aae51..6ac6d4a 100644 --- a/media/libstagefright/MediaBufferGroup.cpp +++ b/media/libstagefright/MediaBufferGroup.cpp @@ -55,7 +55,8 @@ void MediaBufferGroup::add_buffer(MediaBuffer *buffer) { mLastBuffer = buffer; } -status_t MediaBufferGroup::acquire_buffer(MediaBuffer **out) { +status_t MediaBufferGroup::acquire_buffer( + MediaBuffer **out, bool nonBlocking) { Mutex::Autolock autoLock(mLock); for (;;) { @@ -70,6 +71,11 @@ status_t MediaBufferGroup::acquire_buffer(MediaBuffer **out) { } } + if (nonBlocking) { + *out = NULL; + return WOULD_BLOCK; + } + // All buffers are in use. Block until one of them is returned to us. mCondition.wait(mLock); } -- cgit v1.1 From 3cb576166020bfdc1522b33919fe5ff8d211d0a3 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 17 Jul 2014 14:23:58 -0700 Subject: stagefright: use all input buffers in ACodec Bug: 15699665 Change-Id: If37e5c70e56821375ede911e781b5d4b8d41f8ad --- media/libstagefright/ACodec.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index fdb401a..6cb1c64 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -4506,11 +4506,14 @@ void ACodec::ExecutingState::resume() { submitOutputBuffers(); - // Post the first input buffer. + // Post all available input buffers CHECK_GT(mCodec->mBuffers[kPortIndexInput].size(), 0u); - BufferInfo *info = &mCodec->mBuffers[kPortIndexInput].editItemAt(0); - - postFillThisBuffer(info); + for (size_t i = 0; i < mCodec->mBuffers[kPortIndexInput].size(); i++) { + BufferInfo *info = &mCodec->mBuffers[kPortIndexInput].editItemAt(i); + if (info->mStatus == BufferInfo::OWNED_BY_US) { + postFillThisBuffer(info); + } + } mActive = true; } -- cgit v1.1 From cc227036b05f7c2f960a89c567a61f9decefe742 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 17 Jul 2014 15:33:06 -0700 Subject: nuplayer: add widevine support to GenericSource Bug: 15699665 Change-Id: Ided823bd0b1118bbabb288cf62d6389518f820a9 --- .../nuplayer/GenericSource.cpp | 77 +++++++++++++++++++--- .../libmediaplayerservice/nuplayer/GenericSource.h | 10 ++- .../nuplayer/NuPlayerSource.h | 8 +++ 3 files changed, 84 insertions(+), 11 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index cc0cb01..d75408d 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -28,6 +28,7 @@ #include #include #include +#include "../../libstagefright/include/WVMExtractor.h" namespace android { @@ -35,10 +36,16 @@ NuPlayer::GenericSource::GenericSource( const sp ¬ify, const sp &httpService, const char *url, - const KeyedVector *headers) + const KeyedVector *headers, + bool isWidevine, + bool uidValid, + uid_t uid) : Source(notify), mDurationUs(0ll), - mAudioIsVorbis(false) { + mAudioIsVorbis(false), + mIsWidevine(isWidevine), + mUIDValid(uidValid), + mUID(uid) { DataSource::RegisterDefaultSniffers(); sp dataSource = @@ -63,7 +70,31 @@ NuPlayer::GenericSource::GenericSource( void NuPlayer::GenericSource::initFromDataSource( const sp &dataSource) { - sp extractor = MediaExtractor::Create(dataSource); + sp extractor; + + if (mIsWidevine) { + String8 mimeType; + float confidence; + sp dummy; + bool success; + + success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); + if (!success + || strcasecmp( + mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { + ALOGE("unsupported widevine mime: %s", mimeType.string()); + return; + } + + sp wvmExtractor = new WVMExtractor(dataSource); + wvmExtractor->setAdaptiveStreamingMode(true); + if (mUIDValid) { + wvmExtractor->setUID(mUID); + } + extractor = wvmExtractor; + } else { + extractor = MediaExtractor::Create(dataSource); + } CHECK(extractor != NULL); @@ -113,6 +144,13 @@ void NuPlayer::GenericSource::initFromDataSource( } } +status_t NuPlayer::GenericSource::setBuffers(bool audio, Vector &buffers) { + if (mIsWidevine && !audio) { + return mVideoTrack.mSource->setBuffers(buffers); + } + return INVALID_OPERATION; +} + NuPlayer::GenericSource::~GenericSource() { } @@ -128,7 +166,8 @@ void NuPlayer::GenericSource::prepareAsync() { } notifyFlagsChanged( - FLAG_CAN_PAUSE + (mIsWidevine ? FLAG_SECURE : 0) + | FLAG_CAN_PAUSE | FLAG_CAN_SEEK_BACKWARD | FLAG_CAN_SEEK_FORWARD | FLAG_CAN_SEEK); @@ -180,9 +219,14 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( return -EWOULDBLOCK; } + if (mIsWidevine && !audio) { + // try to read a buffer as we may not have been able to the last time + readBuffer(audio, -1ll); + } + status_t finalResult; if (!track->mPackets->hasBufferAvailable(&finalResult)) { - return finalResult == OK ? -EWOULDBLOCK : finalResult; + return (finalResult == OK ? -EWOULDBLOCK : finalResult); } status_t result = track->mPackets->dequeueAccessUnit(accessUnit); @@ -280,6 +324,10 @@ void NuPlayer::GenericSource::readBuffer( seeking = true; } + if (mIsWidevine && !audio) { + options.setNonBlocking(); + } + for (;;) { MediaBuffer *mbuf; status_t err = track->mSource->read(&mbuf, &options); @@ -293,11 +341,18 @@ void NuPlayer::GenericSource::readBuffer( outLength += sizeof(int32_t); } - sp buffer = new ABuffer(outLength); - - memcpy(buffer->data(), - (const uint8_t *)mbuf->data() + mbuf->range_offset(), - mbuf->range_length()); + sp buffer; + if (mIsWidevine && !audio) { + // data is already provided in the buffer + buffer = new ABuffer(NULL, mbuf->range_length()); + buffer->meta()->setPointer("mediaBuffer", mbuf); + mbuf->add_ref(); + } else { + buffer = new ABuffer(outLength); + memcpy(buffer->data(), + (const uint8_t *)mbuf->data() + mbuf->range_offset(), + mbuf->range_length()); + } if (audio && mAudioIsVorbis) { int32_t numPageSamples; @@ -332,6 +387,8 @@ void NuPlayer::GenericSource::readBuffer( track->mPackets->queueAccessUnit(buffer); break; + } else if (err == WOULD_BLOCK) { + break; } else if (err == INFO_FORMAT_CHANGED) { #if 0 track->mPackets->queueDiscontinuity( diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index e0cd20f..8e0209d 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -35,7 +35,10 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { const sp ¬ify, const sp &httpService, const char *url, - const KeyedVector *headers); + const KeyedVector *headers, + bool isWidevine = false, + bool uidValid = false, + uid_t uid = 0); GenericSource( const sp ¬ify, @@ -54,6 +57,8 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual sp getTrackInfo(size_t trackIndex) const; virtual status_t seekTo(int64_t seekTimeUs); + virtual status_t setBuffers(bool audio, Vector &buffers); + protected: virtual ~GenericSource(); @@ -73,6 +78,9 @@ private: int64_t mDurationUs; bool mAudioIsVorbis; + bool mIsWidevine; + bool mUIDValid; + uid_t mUID; void initFromDataSource(const sp &dataSource); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index 632c4a6..259925f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -21,11 +21,14 @@ #include "NuPlayer.h" #include +#include +#include namespace android { struct ABuffer; struct MetaData; +struct MediaBuffer; struct NuPlayer::Source : public AHandler { enum Flags { @@ -34,6 +37,7 @@ struct NuPlayer::Source : public AHandler { FLAG_CAN_SEEK_FORWARD = 4, // the "10 sec forward button" FLAG_CAN_SEEK = 8, // the "seek bar" FLAG_DYNAMIC_DURATION = 16, + FLAG_SECURE = 32, }; enum { @@ -89,6 +93,10 @@ struct NuPlayer::Source : public AHandler { return INVALID_OPERATION; } + virtual status_t setBuffers(bool /* audio */, Vector &/* buffers */) { + return INVALID_OPERATION; + } + virtual bool isRealTime() const { return false; } -- cgit v1.1 From 095248375e29adde961ec2a44989ecb3a6dda6a2 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 17 Jul 2014 14:29:51 -0700 Subject: nuplayer: support widevine sources - handle widevine:// scheme - add separate looper for renderer (as it can block initial buffer handling if all buffers are used) - initiate secure codecs before source is started - don't read secure buffers - share ACodec's input buffers with Widevine source on the decoder side - keep track of mediabuffers released by widevine source - keep track of dequeued input buffers (for safety) - release mediabuffer when buffer is subsequently dequeued. (This was hardcoded into OMXCodec to do this when buffer-empties message was handled, but MediaCodec does not support such functionality.) Bug: 15699665 Change-Id: I4a369443294e45c644be8b0257010e52db1d7c9b --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 55 +++++++++- media/libmediaplayerservice/nuplayer/NuPlayer.h | 1 + .../nuplayer/NuPlayerDecoder.cpp | 122 ++++++++++++++++++++- .../nuplayer/NuPlayerDecoder.h | 6 + .../nuplayer/NuPlayerRenderer.cpp | 3 + 5 files changed, 185 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 88c59bf..6ccd27a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -221,6 +222,10 @@ void NuPlayer::setDataSourceAsync( || strstr(url, ".sdp?"))) { source = new RTSPSource( notify, httpService, url, headers, mUIDValid, mUID, true); + } else if ((!strncasecmp(url, "widevine://", 11))) { + source = new GenericSource(notify, httpService, url, headers, + true /* isWidevine */, mUIDValid, mUID); + mSourceFlags |= Source::FLAG_SECURE; } else { source = new GenericSource(notify, httpService, url, headers); } @@ -512,6 +517,17 @@ void NuPlayer::onMessageReceived(const sp &msg) { mNumFramesDropped = 0; mStarted = true; + /* instantiate decoders now for secure playback */ + if (mSourceFlags & Source::FLAG_SECURE) { + if (mNativeWindow != NULL) { + instantiateDecoder(false, &mVideoDecoder); + } + + if (mAudioSink != NULL) { + instantiateDecoder(true, &mAudioDecoder); + } + } + mSource->start(); uint32_t flags = 0; @@ -540,7 +556,10 @@ void NuPlayer::onMessageReceived(const sp &msg) { new AMessage(kWhatRendererNotify, id()), flags); - looper()->registerHandler(mRenderer); + mRendererLooper = new ALooper; + mRendererLooper->setName("NuPlayerRenderer"); + mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO); + mRendererLooper->registerHandler(mRenderer); postScanSources(); break; @@ -1055,6 +1074,10 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp *decoder) { sp ccNotify = new AMessage(kWhatClosedCaptionNotify, id()); mCCDecoder = new CCDecoder(ccNotify); + + if (mSourceFlags & Source::FLAG_SECURE) { + format->setInt32("secure", true); + } } sp notify = @@ -1073,6 +1096,28 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp *decoder) { (*decoder)->init(); (*decoder)->configure(format); + // allocate buffers to decrypt widevine source buffers + if (!audio && (mSourceFlags & Source::FLAG_SECURE)) { + Vector > inputBufs; + CHECK_EQ((*decoder)->getInputBuffers(&inputBufs), (status_t)OK); + + Vector mediaBufs; + for (size_t i = 0; i < inputBufs.size(); i++) { + const sp &buffer = inputBufs[i]; + MediaBuffer *mbuf = new MediaBuffer(buffer->data(), buffer->size()); + mediaBufs.push(mbuf); + } + + status_t err = mSource->setBuffers(audio, mediaBufs); + if (err != OK) { + for (size_t i = 0; i < mediaBufs.size(); ++i) { + mediaBufs[i]->release(); + } + mediaBufs.clear(); + ALOGE("Secure source didn't support secure mediaBufs."); + return err; + } + } return OK; } @@ -1184,6 +1229,7 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { dropAccessUnit = false; if (!audio + && !(mSourceFlags & Source::FLAG_SECURE) && mVideoLateByUs > 100000ll && mVideoIsAVC && !IsAVCReferenceFrame(accessUnit)) { @@ -1497,6 +1543,13 @@ void NuPlayer::performReset() { ++mScanSourcesGeneration; mScanSourcesPending = false; + if (mRendererLooper != NULL) { + if (mRenderer != NULL) { + mRendererLooper->unregisterHandler(mRenderer->id()); + } + mRendererLooper->stop(); + mRendererLooper.clear(); + } mRenderer.clear(); if (mSource != NULL) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index d7c00aa..c04e277 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -125,6 +125,7 @@ private: sp mAudioDecoder; sp mCCDecoder; sp mRenderer; + sp mRendererLooper; List > mDeferredActions; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index dd73cc4..1b9bafb 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,22 @@ NuPlayer::Decoder::Decoder( NuPlayer::Decoder::~Decoder() { } +static +status_t PostAndAwaitResponse( + const sp &msg, sp *response) { + status_t err = msg->postAndAwaitResponse(response); + + if (err != OK) { + return err; + } + + if (!(*response)->findInt32("err", &err)) { + err = OK; + } + + return err; +} + void NuPlayer::Decoder::onConfigure(const sp &format) { CHECK(mCodec == NULL); @@ -72,8 +89,20 @@ void NuPlayer::Decoder::onConfigure(const sp &format) { ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get()); mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */); + int32_t secure = 0; + if (format->findInt32("secure", &secure) && secure != 0) { + if (mCodec != NULL) { + mCodec->getName(&mComponentName); + mComponentName.append(".secure"); + mCodec->release(); + ALOGI("[%s] creating", mComponentName.c_str()); + mCodec = MediaCodec::CreateByComponentName( + mCodecLooper, mComponentName.c_str()); + } + } if (mCodec == NULL) { - ALOGE("Failed to create %s decoder", mime.c_str()); + ALOGE("Failed to create %s%s decoder", + (secure ? "secure " : ""), mime.c_str()); handleError(UNKNOWN_ERROR); return; } @@ -107,6 +136,7 @@ void NuPlayer::Decoder::onConfigure(const sp &format) { // the following should work after start CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers)); + releaseAndResetMediaBuffers(); CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers)); ALOGV("[%s] got %zu input and %zu output buffers", mComponentName.c_str(), @@ -117,6 +147,18 @@ void NuPlayer::Decoder::onConfigure(const sp &format) { mPaused = false; } +void NuPlayer::Decoder::releaseAndResetMediaBuffers() { + for (size_t i = 0; i < mMediaBuffers.size(); i++) { + if (mMediaBuffers[i] != NULL) { + mMediaBuffers[i]->release(); + mMediaBuffers.editItemAt(i) = NULL; + } + } + mMediaBuffers.resize(mInputBuffers.size()); + mInputBufferIsDequeued.clear(); + mInputBufferIsDequeued.resize(mInputBuffers.size()); +} + void NuPlayer::Decoder::requestCodecNotification() { if (mCodec != NULL) { sp reply = new AMessage(kWhatCodecNotify, id()); @@ -141,6 +183,14 @@ void NuPlayer::Decoder::configure(const sp &format) { msg->post(); } +status_t NuPlayer::Decoder::getInputBuffers(Vector > *buffers) const { + sp msg = new AMessage(kWhatGetInputBuffers, id()); + msg->setPointer("buffers", buffers); + + sp response; + return PostAndAwaitResponse(msg, &response); +} + void NuPlayer::Decoder::handleError(int32_t err) { sp notify = mNotify->dup(); @@ -163,6 +213,12 @@ bool NuPlayer::Decoder::handleAnInputBuffer() { CHECK_LT(bufferIx, mInputBuffers.size()); + if (mMediaBuffers[bufferIx] != NULL) { + mMediaBuffers[bufferIx]->release(); + mMediaBuffers.editItemAt(bufferIx) = NULL; + } + mInputBufferIsDequeued.editItemAt(bufferIx) = true; + sp reply = new AMessage(kWhatInputBufferFilled, id()); reply->setSize("buffer-ix", bufferIx); reply->setInt32("generation", mBufferGeneration); @@ -183,6 +239,44 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { sp buffer; bool hasBuffer = msg->findBuffer("buffer", &buffer); + + // handle widevine classic source - that fills an arbitrary input buffer + MediaBuffer *mediaBuffer = NULL; + if (hasBuffer && buffer->meta()->findPointer( + "mediaBuffer", (void **)&mediaBuffer)) { + if (mediaBuffer == NULL) { + // received no actual buffer + ALOGW("[%s] received null MediaBuffer %s", + mComponentName.c_str(), msg->debugString().c_str()); + buffer = NULL; + } else { + // likely filled another buffer than we requested: adjust buffer index + size_t ix; + for (ix = 0; ix < mInputBuffers.size(); ix++) { + const sp &buf = mInputBuffers[ix]; + if (buf->data() == mediaBuffer->data()) { + // all input buffers are dequeued on start, hence the check + CHECK(mInputBufferIsDequeued[ix]); + ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu", + mComponentName.c_str(), ix, bufferIx); + + // TRICKY: need buffer for the metadata, so instead, set + // codecBuffer to the same (though incorrect) buffer to + // avoid a memcpy into the codecBuffer + codecBuffer = buffer; + codecBuffer->setRange( + mediaBuffer->range_offset(), + mediaBuffer->range_length()); + bufferIx = ix; + break; + } + } + CHECK(ix < mInputBuffers.size()); + } + } + + mInputBufferIsDequeued.editItemAt(bufferIx) = false; + if (buffer == NULL /* includes !hasBuffer */) { int32_t streamErr = ERROR_END_OF_STREAM; CHECK(msg->findInt32("err", &streamErr) || !hasBuffer); @@ -236,6 +330,11 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { mComponentName.c_str(), err); handleError(err); } + + if (mediaBuffer != NULL) { + CHECK(mMediaBuffers[bufferIx] == NULL); + mMediaBuffers.editItemAt(bufferIx) = mediaBuffer; + } } } @@ -352,6 +451,8 @@ void NuPlayer::Decoder::onFlush() { return; } + releaseAndResetMediaBuffers(); + sp notify = mNotify->dup(); notify->setInt32("what", kWhatFlushCompleted); notify->post(); @@ -379,6 +480,8 @@ void NuPlayer::Decoder::onShutdown() { mComponentName = "decoder"; } + releaseAndResetMediaBuffers(); + if (err != OK) { ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err); handleError(err); @@ -403,6 +506,23 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { break; } + case kWhatGetInputBuffers: + { + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + Vector > *dstBuffers; + CHECK(msg->findPointer("buffers", (void **)&dstBuffers)); + + dstBuffers->clear(); + for (size_t i = 0; i < mInputBuffers.size(); i++) { + dstBuffers->push(mInputBuffers[i]); + } + + (new AMessage)->postReply(replyID); + break; + } + case kWhatCodecNotify: { if (!isStaleReply(msg)) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index 4fa0dbd..c6fc237 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -26,6 +26,7 @@ namespace android { struct ABuffer; struct MediaCodec; +struct MediaBuffer; struct NuPlayer::Decoder : public AHandler { Decoder(const sp ¬ify, @@ -34,6 +35,7 @@ struct NuPlayer::Decoder : public AHandler { virtual void configure(const sp &format); virtual void init(); + status_t getInputBuffers(Vector > *dstBuffers) const; virtual void signalFlush(); virtual void signalResume(); virtual void initiateShutdown(); @@ -60,6 +62,7 @@ private: enum { kWhatCodecNotify = 'cdcN', kWhatConfigure = 'conf', + kWhatGetInputBuffers = 'gInB', kWhatInputBufferFilled = 'inpF', kWhatRenderBuffer = 'rndr', kWhatFlush = 'flus', @@ -77,11 +80,14 @@ private: Vector > mInputBuffers; Vector > mOutputBuffers; + Vector mInputBufferIsDequeued; + Vector mMediaBuffers; void handleError(int32_t err); bool handleAnInputBuffer(); bool handleAnOutputBuffer(); + void releaseAndResetMediaBuffers(); void requestCodecNotification(); bool isStaleReply(const sp &msg); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index f520ff7..8592ec2 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -26,6 +26,8 @@ #include #include +#include + namespace android { // static @@ -502,6 +504,7 @@ void NuPlayer::Renderer::postDrainVideoQueue() { } } + ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs); msg->post(delayUs); mDrainVideoQueuePending = true; -- cgit v1.1 From 599950efbb03b1672561d4cf2272504b879525e8 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 17 Jul 2014 10:52:36 -0700 Subject: stagefright: Fix seeking in MPEG4 container - seek based on user-visible timestamp - seek to previous, next and closest exactly Bug: 12786906 Change-Id: I2d5e1fbff6469b6f081a284be2222a4cb50aa754 --- media/libstagefright/MPEG4Extractor.cpp | 2 +- media/libstagefright/OggExtractor.cpp | 8 +- media/libstagefright/SampleTable.cpp | 189 ++++++++++++----------------- media/libstagefright/include/SampleTable.h | 10 +- 4 files changed, 91 insertions(+), 118 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 207acc8..19da6ee 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -3665,7 +3665,7 @@ status_t MPEG4Source::read( uint32_t sampleIndex; status_t err = mSampleTable->findSampleAtTime( - seekTimeUs * mTimescale / 1000000, + seekTimeUs, 1000000, mTimescale, &sampleIndex, findFlags); if (mode == ReadOptions::SEEK_CLOSEST) { diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp index 8c15929..0838004 100644 --- a/media/libstagefright/OggExtractor.cpp +++ b/media/libstagefright/OggExtractor.cpp @@ -320,14 +320,14 @@ status_t MyVorbisExtractor::seekToTime(int64_t timeUs) { } size_t left = 0; - size_t right = mTableOfContents.size(); - while (left < right) { - size_t center = left / 2 + right / 2 + (left & right & 1); + size_t right = mTableOfContents.size() - 1; + while (left <= right) { + size_t center = left + (right - left) / 2; const TOCEntry &entry = mTableOfContents.itemAt(center); if (timeUs < entry.mTimeUs) { - right = center; + right = center - 1; } else if (timeUs > entry.mTimeUs) { left = center + 1; } else { diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index 9a92805..c7e24fc 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -520,83 +520,72 @@ void SampleTable::buildSampleEntriesTable() { } status_t SampleTable::findSampleAtTime( - uint32_t req_time, uint32_t *sample_index, uint32_t flags) { + uint64_t req_time, uint64_t scale_num, uint64_t scale_den, + uint32_t *sample_index, uint32_t flags) { buildSampleEntriesTable(); uint32_t left = 0; - uint32_t right = mNumSampleSizes; - while (left < right) { - uint32_t center = (left + right) / 2; - uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime; + uint32_t right = mNumSampleSizes - 1; + while (left <= right) { + uint32_t center = left + (right - left) / 2; + uint64_t centerTime = + getSampleTime(center, scale_num, scale_den); if (req_time < centerTime) { - right = center; + right = center - 1; } else if (req_time > centerTime) { left = center + 1; } else { - left = center; - break; + *sample_index = mSampleTimeEntries[center].mSampleIndex; + return OK; } } - if (left == mNumSampleSizes) { + uint32_t closestIndex = left; + + if (closestIndex == mNumSampleSizes) { if (flags == kFlagAfter) { return ERROR_OUT_OF_RANGE; } - - --left; + flags = kFlagBefore; + } else if (closestIndex == 0) { + if (flags == kFlagBefore) { + // normally we should return out of range, but that is + // treated as end-of-stream. instead return first sample + // + // return ERROR_OUT_OF_RANGE; + } + flags = kFlagAfter; } - uint32_t closestIndex = left; - switch (flags) { case kFlagBefore: { - while (closestIndex > 0 - && mSampleTimeEntries[closestIndex].mCompositionTime - > req_time) { - --closestIndex; - } + --closestIndex; break; } case kFlagAfter: { - while (closestIndex + 1 < mNumSampleSizes - && mSampleTimeEntries[closestIndex].mCompositionTime - < req_time) { - ++closestIndex; - } + // nothing to do break; } default: { CHECK(flags == kFlagClosest); - - if (closestIndex > 0) { - // Check left neighbour and pick closest. - uint32_t absdiff1 = - abs_difference( - mSampleTimeEntries[closestIndex].mCompositionTime, - req_time); - - uint32_t absdiff2 = - abs_difference( - mSampleTimeEntries[closestIndex - 1].mCompositionTime, - req_time); - - if (absdiff1 > absdiff2) { - closestIndex = closestIndex - 1; - } + // pick closest based on timestamp. use abs_difference for safety + if (abs_difference( + getSampleTime(closestIndex, scale_num, scale_den), req_time) > + abs_difference( + req_time, getSampleTime(closestIndex - 1, scale_num, scale_den))) { + --closestIndex; } - break; } } *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex; - return OK; } @@ -618,109 +607,85 @@ status_t SampleTable::findSyncSampleNear( } uint32_t left = 0; - uint32_t right = mNumSyncSamples; - while (left < right) { + uint32_t right = mNumSyncSamples - 1; + while (left <= right) { uint32_t center = left + (right - left) / 2; uint32_t x = mSyncSamples[center]; if (start_sample_index < x) { - right = center; + right = center - 1; } else if (start_sample_index > x) { left = center + 1; } else { - left = center; - break; + *sample_index = x; + return OK; } } + if (left == mNumSyncSamples) { if (flags == kFlagAfter) { ALOGE("tried to find a sync frame after the last one: %d", left); return ERROR_OUT_OF_RANGE; } - left = left - 1; + flags = kFlagBefore; } + else if (left == 0) { + if (flags == kFlagBefore) { + ALOGE("tried to find a sync frame before the first one: %d", left); - // Now ssi[left] is the sync sample index just before (or at) - // start_sample_index. - // Also start_sample_index < ssi[left + 1], if left + 1 < mNumSyncSamples. - - uint32_t x = mSyncSamples[left]; - - if (left + 1 < mNumSyncSamples) { - uint32_t y = mSyncSamples[left + 1]; - - // our sample lies between sync samples x and y. - - status_t err = mSampleIterator->seekTo(start_sample_index); - if (err != OK) { - return err; - } - - uint32_t sample_time = mSampleIterator->getSampleTime(); - - err = mSampleIterator->seekTo(x); - if (err != OK) { - return err; - } - uint32_t x_time = mSampleIterator->getSampleTime(); - - err = mSampleIterator->seekTo(y); - if (err != OK) { - return err; - } - - uint32_t y_time = mSampleIterator->getSampleTime(); - - if (abs_difference(x_time, sample_time) - > abs_difference(y_time, sample_time)) { - // Pick the sync sample closest (timewise) to the start-sample. - x = y; - ++left; + // normally we should return out of range, but that is + // treated as end-of-stream. instead seek to first sync + // + // return ERROR_OUT_OF_RANGE; } + flags = kFlagAfter; } + // Now ssi[left - 1] <(=) start_sample_index <= ssi[left] switch (flags) { case kFlagBefore: { - if (x > start_sample_index) { - CHECK(left > 0); - - x = mSyncSamples[left - 1]; - - if (x > start_sample_index) { - // The table of sync sample indices was not sorted - // properly. - return ERROR_MALFORMED; - } - } + --left; break; } - case kFlagAfter: { - if (x < start_sample_index) { - if (left + 1 >= mNumSyncSamples) { - return ERROR_OUT_OF_RANGE; - } - - x = mSyncSamples[left + 1]; - - if (x < start_sample_index) { - // The table of sync sample indices was not sorted - // properly. - return ERROR_MALFORMED; - } - } - + // nothing to do break; } - default: + { + // this route is not used, but implement it nonetheless + CHECK(flags == kFlagClosest); + + status_t err = mSampleIterator->seekTo(start_sample_index); + if (err != OK) { + return err; + } + uint32_t sample_time = mSampleIterator->getSampleTime(); + + err = mSampleIterator->seekTo(mSyncSamples[left]); + if (err != OK) { + return err; + } + uint32_t upper_time = mSampleIterator->getSampleTime(); + + err = mSampleIterator->seekTo(mSyncSamples[left - 1]); + if (err != OK) { + return err; + } + uint32_t lower_time = mSampleIterator->getSampleTime(); + + // use abs_difference for safety + if (abs_difference(upper_time, sample_time) > + abs_difference(sample_time, lower_time)) { + --left; + } break; + } } - *sample_index = x; - + *sample_index = mSyncSamples[left]; return OK; } diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h index fe146f2..d06df7b 100644 --- a/media/libstagefright/include/SampleTable.h +++ b/media/libstagefright/include/SampleTable.h @@ -75,7 +75,8 @@ public: kFlagClosest }; status_t findSampleAtTime( - uint32_t req_time, uint32_t *sample_index, uint32_t flags); + uint64_t req_time, uint64_t scale_num, uint64_t scale_den, + uint32_t *sample_index, uint32_t flags); status_t findSyncSampleNear( uint32_t start_sample_index, uint32_t *sample_index, @@ -138,6 +139,13 @@ private: friend struct SampleIterator; + // normally we don't round + inline uint64_t getSampleTime( + size_t sample_index, uint64_t scale_num, uint64_t scale_den) const { + return (mSampleTimeEntries[sample_index].mCompositionTime + * scale_num) / scale_den; + } + status_t getSampleSize_l(uint32_t sample_index, size_t *sample_size); uint32_t getCompositionTimeOffset(uint32_t sampleIndex); -- cgit v1.1 From 65eeb3c92ffc8b90eb1330fdf9a74c55f3c6b463 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Fri, 18 Jul 2014 14:27:25 -0700 Subject: Free MediaBuffer when ABuffer is discarded. BUG: 15699665 Change-Id: Ie7da017cf32ccc08094fe4b01a2b07d2739770d2 --- media/libstagefright/mpeg2ts/AnotherPacketSource.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'media') diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index 871824a..a0319ab 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -230,6 +230,11 @@ void AnotherPacketSource::queueDiscontinuity( int32_t oldDiscontinuityType; if (!oldBuffer->meta()->findInt32( "discontinuity", &oldDiscontinuityType)) { + MediaBuffer *mbuf = NULL; + oldBuffer->meta()->findPointer("mediaBuffer", (void**)&mbuf); + if (mbuf != NULL) { + mbuf->release(); + } it = mBuffers.erase(it); continue; } -- cgit v1.1 From cf1f53baa636f1782ff924d6003c70c6b8542c0b Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Sat, 19 Jul 2014 02:27:41 -0700 Subject: Fix: Add MediaCodecList capabilities fix getting capability index from type Bug: 12065651 Change-Id: Id2bc60410a92e17c841a5dd072257bc40ad6236f --- media/libstagefright/MediaCodecList.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'media') diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index d1e9272..8f54343 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -868,6 +868,8 @@ status_t MediaCodecList::getCodecCapabilities( if (typeIndex < 0) { return -EINVAL; } + // essentially doing valueFor without the CHECK abort + typeIndex = mTypes.valueAt(typeIndex); OMXClient client; status_t err = client.connect(); -- cgit v1.1 From df813a3ba59109ca519ce0cb00a1a9144074f40e Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Sun, 20 Jul 2014 17:58:33 -0700 Subject: audio_attributes_t for SoundPool Add support for the audio_attributes_t structure in the SoundPoool constructor. Remove SRC quality which was never implemented. Remove stream types. Add file to contain audio helper functions related to policy. Change-Id: I1720ff15e7b23ea7b713a4395fdfac26dc3fd4da --- media/libmedia/SoundPool.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp index 2aa0592..d2e381b 100644 --- a/media/libmedia/SoundPool.cpp +++ b/media/libmedia/SoundPool.cpp @@ -28,6 +28,7 @@ #include #include #include "SoundPoolThread.h" +#include namespace android { @@ -39,10 +40,10 @@ uint32_t kDefaultFrameCount = 1200; size_t kDefaultHeapSize = 1024 * 1024; // 1MB -SoundPool::SoundPool(int maxChannels, audio_stream_type_t streamType, int srcQuality) +SoundPool::SoundPool(int maxChannels, const audio_attributes_t* pAttributes) { - ALOGV("SoundPool constructor: maxChannels=%d, streamType=%d, srcQuality=%d", - maxChannels, streamType, srcQuality); + ALOGV("SoundPool constructor: maxChannels=%d, attr.usage=%d, attr.flags=0x%x, attr.tags=%s", + maxChannels, pAttributes->usage, pAttributes->flags, pAttributes->tags); // check limits mMaxChannels = maxChannels; @@ -56,8 +57,7 @@ SoundPool::SoundPool(int maxChannels, audio_stream_type_t streamType, int srcQua mQuit = false; mDecodeThread = 0; - mStreamType = streamType; - mSrcQuality = srcQuality; + memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t)); mAllocated = 0; mNextSampleID = 0; mNextChannelID = 0; @@ -580,7 +580,7 @@ void SoundChannel::play(const sp& sample, int nextChannelID, float leftV // initialize track size_t afFrameCount; uint32_t afSampleRate; - audio_stream_type_t streamType = mSoundPool->streamType(); + audio_stream_type_t streamType = audio_attributes_to_stream_type(mSoundPool->attributes()); if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { afFrameCount = kDefaultFrameCount; } -- cgit v1.1 From 225d5b20409fd400bfa4ed5e9bc1d5babb498471 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 21 Jul 2014 13:47:21 -0700 Subject: stagefright: handle seeking to before first cue-point. Bug: 16446994 Change-Id: Id3f9d6780a7c4f62171cbfa8675a67334e8dfa10 --- media/libstagefright/OggExtractor.cpp | 14 +++++++++----- media/libstagefright/SampleTable.cpp | 16 ++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'media') diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp index 0838004..821bd81 100644 --- a/media/libstagefright/OggExtractor.cpp +++ b/media/libstagefright/OggExtractor.cpp @@ -320,22 +320,26 @@ status_t MyVorbisExtractor::seekToTime(int64_t timeUs) { } size_t left = 0; - size_t right = mTableOfContents.size() - 1; - while (left <= right) { - size_t center = left + (right - left) / 2; + size_t right_plus_one = mTableOfContents.size(); + while (left < right_plus_one) { + size_t center = left + (right_plus_one - left) / 2; const TOCEntry &entry = mTableOfContents.itemAt(center); if (timeUs < entry.mTimeUs) { - right = center - 1; + right_plus_one = center; } else if (timeUs > entry.mTimeUs) { left = center + 1; } else { - left = right = center; + left = center; break; } } + if (left == mTableOfContents.size()) { + --left; + } + const TOCEntry &entry = mTableOfContents.itemAt(left); ALOGV("seeking to entry %zu / %zu at offset %lld", diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index c7e24fc..bad43f2 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -525,14 +525,14 @@ status_t SampleTable::findSampleAtTime( buildSampleEntriesTable(); uint32_t left = 0; - uint32_t right = mNumSampleSizes - 1; - while (left <= right) { - uint32_t center = left + (right - left) / 2; + uint32_t right_plus_one = mNumSampleSizes; + while (left < right_plus_one) { + uint32_t center = left + (right_plus_one - left) / 2; uint64_t centerTime = getSampleTime(center, scale_num, scale_den); if (req_time < centerTime) { - right = center - 1; + right_plus_one = center; } else if (req_time > centerTime) { left = center + 1; } else { @@ -607,13 +607,13 @@ status_t SampleTable::findSyncSampleNear( } uint32_t left = 0; - uint32_t right = mNumSyncSamples - 1; - while (left <= right) { - uint32_t center = left + (right - left) / 2; + uint32_t right_plus_one = mNumSyncSamples; + while (left < right_plus_one) { + uint32_t center = left + (right_plus_one - left) / 2; uint32_t x = mSyncSamples[center]; if (start_sample_index < x) { - right = center - 1; + right_plus_one = center; } else if (start_sample_index > x) { left = center + 1; } else { -- cgit v1.1 From 114819633470ebd5b346c13c2a82a0025d2d39c0 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 9 Jul 2014 20:09:43 -0700 Subject: StagefrightRecorder: webm (video only) support Bug: 16329805 Change-Id: I8a0ecd100fca397add97a1416125bcc6aeb86364 --- media/libmedia/mediarecorder.cpp | 7 ++- media/libmediaplayerservice/Android.mk | 1 + .../libmediaplayerservice/StagefrightRecorder.cpp | 73 +++++++++++++--------- media/libmediaplayerservice/StagefrightRecorder.h | 4 +- 4 files changed, 52 insertions(+), 33 deletions(-) (limited to 'media') diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp index c8192e9..1952b86 100644 --- a/media/libmedia/mediarecorder.cpp +++ b/media/libmedia/mediarecorder.cpp @@ -186,8 +186,11 @@ status_t MediaRecorder::setOutputFormat(int of) ALOGE("setOutputFormat called in an invalid state: %d", mCurrentState); return INVALID_OPERATION; } - if (mIsVideoSourceSet && of >= OUTPUT_FORMAT_AUDIO_ONLY_START && of != OUTPUT_FORMAT_RTP_AVP && of != OUTPUT_FORMAT_MPEG2TS) { //first non-video output format - ALOGE("output format (%d) is meant for audio recording only and incompatible with video recording", of); + if (mIsVideoSourceSet + && of >= OUTPUT_FORMAT_AUDIO_ONLY_START //first non-video output format + && of < OUTPUT_FORMAT_AUDIO_ONLY_END) { + ALOGE("output format (%d) is meant for audio recording only" + " and incompatible with video recording", of); return INVALID_OPERATION; } diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index 48d44c1..0c7e590 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -49,6 +49,7 @@ LOCAL_C_INCLUDES := \ $(TOP)/frameworks/av/media/libstagefright/include \ $(TOP)/frameworks/av/media/libstagefright/rtsp \ $(TOP)/frameworks/av/media/libstagefright/wifi-display \ + $(TOP)/frameworks/av/media/libstagefright/webm \ $(TOP)/frameworks/native/include/media/openmax \ $(TOP)/external/tremolo/Tremolo \ diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index bfc075c..217b248 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -19,6 +19,7 @@ #include #include +#include "WebmWriter.h" #include "StagefrightRecorder.h" #include @@ -764,7 +765,8 @@ status_t StagefrightRecorder::prepareInternal() { case OUTPUT_FORMAT_DEFAULT: case OUTPUT_FORMAT_THREE_GPP: case OUTPUT_FORMAT_MPEG_4: - status = setupMPEG4Recording(); + case OUTPUT_FORMAT_WEBM: + status = setupMPEG4orWEBMRecording(); break; case OUTPUT_FORMAT_AMR_NB: @@ -826,9 +828,14 @@ status_t StagefrightRecorder::start() { case OUTPUT_FORMAT_DEFAULT: case OUTPUT_FORMAT_THREE_GPP: case OUTPUT_FORMAT_MPEG_4: + case OUTPUT_FORMAT_WEBM: { + bool isMPEG4 = true; + if (mOutputFormat == OUTPUT_FORMAT_WEBM) { + isMPEG4 = false; + } sp meta = new MetaData; - setupMPEG4MetaData(&meta); + setupMPEG4orWEBMMetaData(&meta); status = mWriter->start(meta.get()); break; } @@ -1538,12 +1545,17 @@ status_t StagefrightRecorder::setupAudioEncoder(const sp& writer) { return OK; } -status_t StagefrightRecorder::setupMPEG4Recording() { +status_t StagefrightRecorder::setupMPEG4orWEBMRecording() { mWriter.clear(); mTotalBitRate = 0; status_t err = OK; - sp writer = new MPEG4Writer(mOutputFd); + sp writer; + if (mOutputFormat == OUTPUT_FORMAT_MPEG_4) { + writer = new MPEG4Writer(mOutputFd); + } else { + writer = new WebmWriter(mOutputFd); + } if (mVideoSource < VIDEO_SOURCE_LIST_END) { @@ -1563,22 +1575,25 @@ status_t StagefrightRecorder::setupMPEG4Recording() { mTotalBitRate += mVideoBitRate; } - // Audio source is added at the end if it exists. - // This help make sure that the "recoding" sound is suppressed for - // camcorder applications in the recorded files. - if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) { - err = setupAudioEncoder(writer); - if (err != OK) return err; - mTotalBitRate += mAudioBitRate; - } + if (mOutputFormat == OUTPUT_FORMAT_MPEG_4) { + // Audio source is added at the end if it exists. + // This help make sure that the "recoding" sound is suppressed for + // camcorder applications in the recorded files. + // TODO Audio source is currently unsupported for webm output; vorbis encoder needed. + if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) { + err = setupAudioEncoder(writer); + if (err != OK) return err; + mTotalBitRate += mAudioBitRate; + } - if (mInterleaveDurationUs > 0) { - reinterpret_cast(writer.get())-> - setInterleaveDuration(mInterleaveDurationUs); - } - if (mLongitudex10000 > -3600000 && mLatitudex10000 > -3600000) { - reinterpret_cast(writer.get())-> - setGeoData(mLatitudex10000, mLongitudex10000); + if (mInterleaveDurationUs > 0) { + reinterpret_cast(writer.get())-> + setInterleaveDuration(mInterleaveDurationUs); + } + if (mLongitudex10000 > -3600000 && mLatitudex10000 > -3600000) { + reinterpret_cast(writer.get())-> + setGeoData(mLatitudex10000, mLongitudex10000); + } } if (mMaxFileDurationUs != 0) { writer->setMaxFileDuration(mMaxFileDurationUs); @@ -1586,7 +1601,6 @@ status_t StagefrightRecorder::setupMPEG4Recording() { if (mMaxFileSizeBytes != 0) { writer->setMaxFileSize(mMaxFileSizeBytes); } - if (mVideoSource == VIDEO_SOURCE_DEFAULT || mVideoSource == VIDEO_SOURCE_CAMERA) { mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId); @@ -1595,8 +1609,7 @@ status_t StagefrightRecorder::setupMPEG4Recording() { mStartTimeOffsetMs = 200; } if (mStartTimeOffsetMs > 0) { - reinterpret_cast(writer.get())-> - setStartTimeOffsetMs(mStartTimeOffsetMs); + writer->setStartTimeOffsetMs(mStartTimeOffsetMs); } writer->setListener(mListener); @@ -1604,20 +1617,22 @@ status_t StagefrightRecorder::setupMPEG4Recording() { return OK; } -void StagefrightRecorder::setupMPEG4MetaData(sp *meta) { +void StagefrightRecorder::setupMPEG4orWEBMMetaData(sp *meta) { int64_t startTimeUs = systemTime() / 1000; (*meta)->setInt64(kKeyTime, startTimeUs); (*meta)->setInt32(kKeyFileType, mOutputFormat); (*meta)->setInt32(kKeyBitRate, mTotalBitRate); - (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset); if (mMovieTimeScale > 0) { (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale); } - if (mTrackEveryTimeDurationUs > 0) { - (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs); - } - if (mRotationDegrees != 0) { - (*meta)->setInt32(kKeyRotation, mRotationDegrees); + if (mOutputFormat == OUTPUT_FORMAT_MPEG_4) { + (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset); + if (mTrackEveryTimeDurationUs > 0) { + (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs); + } + if (mRotationDegrees != 0) { + (*meta)->setInt32(kKeyRotation, mRotationDegrees); + } } } diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 377d168..9062f30 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -128,8 +128,8 @@ private: sp mLooper; status_t prepareInternal(); - status_t setupMPEG4Recording(); - void setupMPEG4MetaData(sp *meta); + status_t setupMPEG4orWEBMRecording(); + void setupMPEG4orWEBMMetaData(sp *meta); status_t setupAMRRecording(); status_t setupAACRecording(); status_t setupRawAudioRecording(); -- cgit v1.1 From 2606b10d51c2dceb851a2ea63e803aba4134bf00 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 22 Jul 2014 09:12:03 -0700 Subject: update battery stats for video/audio Bug: 12979595 Change-Id: Iafd93046a4fd9f22bcd66084deace746a7ca5d3c --- media/libstagefright/MediaCodec.cpp | 115 ++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 7a9cb0b..15e062e 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -16,13 +16,13 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaCodec" -#include #include -#include - +#include "include/avc_utils.h" #include "include/SoftwareRenderer.h" +#include +#include #include #include #include @@ -32,16 +32,85 @@ #include #include #include +#include #include #include #include #include #include - -#include "include/avc_utils.h" +#include +#include +#include namespace android { +struct MediaCodec::BatteryNotifier : public Singleton { + BatteryNotifier(); + + void noteStartVideo(); + void noteStopVideo(); + void noteStartAudio(); + void noteStopAudio(); + +private: + int32_t mVideoRefCount; + int32_t mAudioRefCount; + sp mBatteryStatService; +}; + +ANDROID_SINGLETON_STATIC_INSTANCE(MediaCodec::BatteryNotifier) + +MediaCodec::BatteryNotifier::BatteryNotifier() : + mVideoRefCount(0), + mAudioRefCount(0) { + // get battery service + const sp sm(defaultServiceManager()); + if (sm != NULL) { + const String16 name("batterystats"); + mBatteryStatService = interface_cast(sm->getService(name)); + if (mBatteryStatService == NULL) { + ALOGE("batterystats service unavailable!"); + } + } +} + +void MediaCodec::BatteryNotifier::noteStartVideo() { + if (mVideoRefCount == 0 && mBatteryStatService != NULL) { + mBatteryStatService->noteStartVideo(AID_MEDIA); + } + mVideoRefCount++; +} + +void MediaCodec::BatteryNotifier::noteStopVideo() { + if (mVideoRefCount == 0) { + ALOGW("BatteryNotifier::noteStop(): video refcount is broken!"); + return; + } + + mVideoRefCount--; + if (mVideoRefCount == 0 && mBatteryStatService != NULL) { + mBatteryStatService->noteStopVideo(AID_MEDIA); + } +} + +void MediaCodec::BatteryNotifier::noteStartAudio() { + if (mAudioRefCount == 0 && mBatteryStatService != NULL) { + mBatteryStatService->noteStartAudio(AID_MEDIA); + } + mAudioRefCount++; +} + +void MediaCodec::BatteryNotifier::noteStopAudio() { + if (mAudioRefCount == 0) { + ALOGW("BatteryNotifier::noteStop(): audio refcount is broken!"); + return; + } + + mAudioRefCount--; + if (mAudioRefCount == 0 && mBatteryStatService != NULL) { + mBatteryStatService->noteStopAudio(AID_MEDIA); + } +} // static sp MediaCodec::CreateByType( const sp &looper, const char *mime, bool encoder) { @@ -71,6 +140,8 @@ MediaCodec::MediaCodec(const sp &looper) mReplyID(0), mFlags(0), mSoftRenderer(NULL), + mBatteryStatNotified(false), + mIsVideo(false), mDequeueInputTimeoutGeneration(0), mDequeueInputReplyID(0), mDequeueOutputTimeoutGeneration(0), @@ -756,7 +827,6 @@ void MediaCodec::onMessageReceived(const sp &msg) { case CodecBase::kWhatComponentConfigured: { CHECK_EQ(mState, CONFIGURING); - setState(CONFIGURED); // reset input surface flag mHaveInputSurface = false; @@ -764,6 +834,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->findMessage("input-format", &mInputFormat)); CHECK(msg->findMessage("output-format", &mOutputFormat)); + setState(CONFIGURED); (new AMessage)->postReply(mReplyID); break; } @@ -1620,6 +1691,8 @@ void MediaCodec::setState(State newState) { mState = newState; cancelPendingDequeueOperations(); + + updateBatteryStat(); } void MediaCodec::returnBuffersToCodec() { @@ -2054,4 +2127,34 @@ status_t MediaCodec::amendOutputFormatWithCodecSpecificData( return OK; } +void MediaCodec::updateBatteryStat() { + if (mState == CONFIGURED && !mBatteryStatNotified) { + AString mime; + CHECK(mOutputFormat != NULL && + mOutputFormat->findString("mime", &mime)); + + mIsVideo = mime.startsWithIgnoreCase("video/"); + + BatteryNotifier& notifier(BatteryNotifier::getInstance()); + + if (mIsVideo) { + notifier.noteStartVideo(); + } else { + notifier.noteStartAudio(); + } + + mBatteryStatNotified = true; + } else if (mState == UNINITIALIZED && mBatteryStatNotified) { + BatteryNotifier& notifier(BatteryNotifier::getInstance()); + + if (mIsVideo) { + notifier.noteStopVideo(); + } else { + notifier.noteStopAudio(); + } + + mBatteryStatNotified = false; + } +} + } // namespace android -- cgit v1.1 From 3a2956d148d81194e297408179e84a47a309ef48 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Tue, 22 Jul 2014 16:01:33 -0700 Subject: Fall back to s/w decoding when audio offloading fails. Change-Id: Icde3d65c964b2a13fb1c6636adcce52ae048a3fb --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 17 +++++++++++++ .../nuplayer/NuPlayerRenderer.cpp | 29 +++++++++++++++++++++- .../nuplayer/NuPlayerRenderer.h | 3 +++ 3 files changed, 48 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 6ccd27a..fa6b1e5 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -754,6 +754,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { offloadInfo.has_video = (mVideoDecoder != NULL); offloadInfo.is_streaming = true; + ALOGV("try to open AudioSink in offload mode"); err = mAudioSink->open( sampleRate, numChannels, @@ -793,6 +794,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { if (!mOffloadAudio) { flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; + ALOGV("open AudioSink in NON-offload mode"); CHECK_EQ(mAudioSink->open( sampleRate, numChannels, @@ -940,6 +942,21 @@ void NuPlayer::onMessageReceived(const sp &msg) { } else if (what == Renderer::kWhatMediaRenderingStart) { ALOGV("media rendering started"); notifyListener(MEDIA_STARTED, 0, 0); + } else if (what == Renderer::kWhatAudioOffloadTearDown) { + ALOGV("Tear down audio offload, fall back to s/w path"); + int64_t positionUs; + CHECK(msg->findInt64("positionUs", &positionUs)); + mAudioSink->close(); + mAudioDecoder.clear(); + mRenderer->flush(true /* audio */); + if (mVideoDecoder != NULL) { + mRenderer->flush(false /* audio */); + } + mRenderer->signalDisableOffloadAudio(); + mOffloadAudio = false; + + performSeek(positionUs); + instantiateDecoder(true /* audio */, &mAudioDecoder); } break; } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 8592ec2..3640038 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -223,6 +223,12 @@ void NuPlayer::Renderer::onMessageReceived(const sp &msg) { break; } + case kWhatAudioOffloadTearDown: + { + onAudioOffloadTearDown(); + break; + } + default: TRESPASS(); break; @@ -294,7 +300,7 @@ size_t NuPlayer::Renderer::AudioSinkCallback( case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN: { - // TODO: send this to player. + me->notifyAudioOffloadTearDown(); break; } } @@ -582,6 +588,10 @@ void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult) { notify->post(); } +void NuPlayer::Renderer::notifyAudioOffloadTearDown() { + (new AMessage(kWhatAudioOffloadTearDown, id()))->post(); +} + void NuPlayer::Renderer::onQueueBuffer(const sp &msg) { int32_t audio; CHECK(msg->findInt32("audio", &audio)); @@ -814,6 +824,7 @@ void NuPlayer::Renderer::onAudioSinkChanged() { void NuPlayer::Renderer::onDisableOffloadAudio() { Mutex::Autolock autoLock(mLock); mFlags &= ~FLAG_OFFLOAD_AUDIO; + ++mAudioQueueGeneration; } void NuPlayer::Renderer::notifyPosition() { @@ -880,5 +891,21 @@ void NuPlayer::Renderer::onResume() { } } +void NuPlayer::Renderer::onAudioOffloadTearDown() { + uint32_t numFramesPlayed; + CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); + + int64_t currentPositionUs = mFirstAudioTimeUs + + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll; + + mAudioSink->stop(); + mAudioSink->flush(); + + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatAudioOffloadTearDown); + notify->setInt64("positionUs", currentPositionUs); + notify->post(); +} + } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 6e86a8f..1cba1a0 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -62,6 +62,7 @@ struct NuPlayer::Renderer : public AHandler { kWhatPosition = 'posi', kWhatVideoRenderingStart = 'vdrd', kWhatMediaRenderingStart = 'mdrd', + kWhatAudioOffloadTearDown = 'aOTD', }; protected: @@ -143,12 +144,14 @@ private: void onDisableOffloadAudio(); void onPause(); void onResume(); + void onAudioOffloadTearDown(); void notifyEOS(bool audio, status_t finalResult); void notifyFlushComplete(bool audio); void notifyPosition(); void notifyVideoLateBy(int64_t lateByUs); void notifyVideoRenderingStart(); + void notifyAudioOffloadTearDown(); void flushQueue(List *queue); bool dropBufferWhileFlushing(bool audio, const sp &msg); -- cgit v1.1 From 05312bc7478feec11d9ae88e951c0857a7a3f28d Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 16 Jul 2014 15:47:09 -0700 Subject: GenericSource: support track (de)selection Bug: 15153976 Change-Id: I522b1f9f0ffedf4edbea03a6654a6dbc0262860a --- .../nuplayer/GenericSource.cpp | 353 +++++++++++++++++---- .../libmediaplayerservice/nuplayer/GenericSource.h | 23 +- .../libstagefright/mpeg2ts/AnotherPacketSource.cpp | 12 +- media/libstagefright/mpeg2ts/AnotherPacketSource.h | 1 + 4 files changed, 322 insertions(+), 67 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index d75408d..63a907c 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -41,6 +41,7 @@ NuPlayer::GenericSource::GenericSource( bool uidValid, uid_t uid) : Source(notify), + mFetchSubtitleDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false), mIsWidevine(isWidevine), @@ -59,6 +60,7 @@ NuPlayer::GenericSource::GenericSource( const sp ¬ify, int fd, int64_t offset, int64_t length) : Source(notify), + mFetchSubtitleDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false) { DataSource::RegisterDefaultSniffers(); @@ -133,6 +135,7 @@ void NuPlayer::GenericSource::initFromDataSource( } if (track != NULL) { + CHECK_EQ(track->start(), (status_t)OK); mSources.push(track); int64_t durationUs; if (meta->findInt64(kKeyDuration, &durationUs)) { @@ -179,21 +182,17 @@ void NuPlayer::GenericSource::start() { ALOGI("start"); if (mAudioTrack.mSource != NULL) { - CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); - mAudioTrack.mPackets = new AnotherPacketSource(mAudioTrack.mSource->getFormat()); - readBuffer(true /* audio */); + readBuffer(MEDIA_TRACK_TYPE_AUDIO); } if (mVideoTrack.mSource != NULL) { - CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); - mVideoTrack.mPackets = new AnotherPacketSource(mVideoTrack.mSource->getFormat()); - readBuffer(false /* audio */); + readBuffer(MEDIA_TRACK_TYPE_VIDEO); } } @@ -201,6 +200,123 @@ status_t NuPlayer::GenericSource::feedMoreTSData() { return OK; } +void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { + switch (msg->what()) { + case kWhatFetchSubtitleData: + { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + if (generation != mFetchSubtitleDataGeneration) { + // stale + break; + } + + int32_t avail; + if (mSubtitleTrack.mPackets->hasBufferAvailable(&avail)) { + break; + } + + int64_t timeUs; + CHECK(msg->findInt64("timeUs", &timeUs)); + + int64_t subTimeUs; + readBuffer(MEDIA_TRACK_TYPE_SUBTITLE, timeUs, &subTimeUs); + + const int64_t oneSecUs = 1000000ll; + const int64_t delayUs = subTimeUs - timeUs - oneSecUs; + sp msg2 = new AMessage(kWhatSendSubtitleData, id()); + msg2->setInt32("generation", generation); + msg2->post(delayUs < 0 ? 0 : delayUs); + ALOGV("kWhatFetchSubtitleData generation %d, delayUs %lld", + mFetchSubtitleDataGeneration, delayUs); + + break; + } + + case kWhatSendSubtitleData: + { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + if (generation != mFetchSubtitleDataGeneration) { + // stale + break; + } + + int64_t subTimeUs; + if (mSubtitleTrack.mPackets->nextBufferTime(&subTimeUs) != OK) { + break; + } + + int64_t nextSubTimeUs; + readBuffer(MEDIA_TRACK_TYPE_SUBTITLE, -1, &nextSubTimeUs); + + sp buffer; + status_t dequeueStatus = mSubtitleTrack.mPackets->dequeueAccessUnit(&buffer); + if (dequeueStatus != OK) { + ALOGE("kWhatSendSubtitleData dequeueAccessUnit: %d", dequeueStatus); + } else { + sp notify = dupNotify(); + notify->setInt32("what", kWhatSubtitleData); + notify->setBuffer("buffer", buffer); + notify->post(); + + const int64_t delayUs = nextSubTimeUs - subTimeUs; + msg->post(delayUs < 0 ? 0 : delayUs); + } + + break; + } + + case kWhatChangeAVSource: + { + int32_t trackIndex; + CHECK(msg->findInt32("trackIndex", &trackIndex)); + const sp source = mSources.itemAt(trackIndex); + + Track* track; + const char *mime; + media_track_type trackType, counterpartType; + sp meta = source->getFormat(); + meta->findCString(kKeyMIMEType, &mime); + if (!strncasecmp(mime, "audio/", 6)) { + track = &mAudioTrack; + trackType = MEDIA_TRACK_TYPE_AUDIO; + counterpartType = MEDIA_TRACK_TYPE_VIDEO;; + } else { + CHECK(!strncasecmp(mime, "video/", 6)); + track = &mVideoTrack; + trackType = MEDIA_TRACK_TYPE_VIDEO; + counterpartType = MEDIA_TRACK_TYPE_AUDIO;; + } + + + track->mSource = source; + track->mIndex = trackIndex; + + status_t avail; + if (!track->mPackets->hasBufferAvailable(&avail)) { + // sync from other source + TRESPASS(); + break; + } + + int64_t timeUs, actualTimeUs; + const bool formatChange = true; + sp latestMeta = track->mPackets->getLatestMeta(); + CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs)); + readBuffer(trackType, timeUs, &actualTimeUs, formatChange); + readBuffer(counterpartType, -1, NULL, formatChange); + ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs); + + break; + } + + default: + Source::onMessageReceived(msg); + break; + } +} + sp NuPlayer::GenericSource::getFormatMeta(bool audio) { sp source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; @@ -221,7 +337,7 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( if (mIsWidevine && !audio) { // try to read a buffer as we may not have been able to the last time - readBuffer(audio, -1ll); + readBuffer(MEDIA_TRACK_TYPE_AUDIO, -1ll); } status_t finalResult; @@ -231,7 +347,30 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( status_t result = track->mPackets->dequeueAccessUnit(accessUnit); - readBuffer(audio, -1ll); + if (!track->mPackets->hasBufferAvailable(&finalResult)) { + readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll); + } + + if (mSubtitleTrack.mSource == NULL) { + return result; + } + + CHECK(mSubtitleTrack.mPackets != NULL); + if (result != OK) { + mSubtitleTrack.mPackets->clear(); + mFetchSubtitleDataGeneration++; + return result; + } + + int64_t timeUs; + status_t eosResult; // ignored + CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); + if (!mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { + sp msg = new AMessage(kWhatFetchSubtitleData, id()); + msg->setInt64("timeUs", timeUs); + msg->setInt32("generation", mFetchSubtitleDataGeneration); + msg->post(); + } return result; } @@ -291,25 +430,150 @@ sp NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { return format; } +status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { + ALOGV("selectTrack: %zu", trackIndex); + if (trackIndex >= mSources.size()) { + return BAD_INDEX; + } + + if (!select) { + if (mSubtitleTrack.mSource == NULL || trackIndex != mSubtitleTrack.mIndex) { + return INVALID_OPERATION; + } + mSubtitleTrack.mSource = NULL; + mSubtitleTrack.mPackets->clear(); + mFetchSubtitleDataGeneration++; + return OK; + } + + const sp source = mSources.itemAt(trackIndex); + sp meta = source->getFormat(); + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + if (!strncasecmp(mime, "text/", 5)) { + if (mSubtitleTrack.mSource != NULL && mSubtitleTrack.mIndex == trackIndex) { + return OK; + } + mSubtitleTrack.mIndex = trackIndex; + mSubtitleTrack.mSource = mSources.itemAt(trackIndex); + if (mSubtitleTrack.mPackets == NULL) { + mSubtitleTrack.mPackets = new AnotherPacketSource(mSubtitleTrack.mSource->getFormat()); + } else { + mSubtitleTrack.mPackets->clear(); + + } + mFetchSubtitleDataGeneration++; + return OK; + } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { + bool audio = !strncasecmp(mime, "audio/", 6); + Track *track = audio ? &mAudioTrack : &mVideoTrack; + if (track->mSource != NULL && track->mIndex == trackIndex) { + return OK; + } + + sp msg = new AMessage(kWhatChangeAVSource, id()); + msg->setInt32("trackIndex", trackIndex); + msg->post(); + return OK; + } + + return INVALID_OPERATION; +} + status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { if (mVideoTrack.mSource != NULL) { int64_t actualTimeUs; - readBuffer(false /* audio */, seekTimeUs, &actualTimeUs); + readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs); seekTimeUs = actualTimeUs; } if (mAudioTrack.mSource != NULL) { - readBuffer(true /* audio */, seekTimeUs); + readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs); } return OK; } +sp NuPlayer::GenericSource::mediaBufferToABuffer( + MediaBuffer* mb, + media_track_type trackType, + int64_t *actualTimeUs) { + bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO; + size_t outLength = mb->range_length(); + + if (audio && mAudioIsVorbis) { + outLength += sizeof(int32_t); + } + + sp ab; + if (mIsWidevine && !audio) { + // data is already provided in the buffer + ab = new ABuffer(NULL, mb->range_length()); + ab->meta()->setPointer("mediaBuffer", mb); + mb->add_ref(); + } else { + ab = new ABuffer(outLength); + memcpy(ab->data(), + (const uint8_t *)mb->data() + mb->range_offset(), + mb->range_length()); + } + + if (audio && mAudioIsVorbis) { + int32_t numPageSamples; + if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) { + numPageSamples = -1; + } + + uint8_t* abEnd = ab->data() + mb->range_length(); + memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); + } + + int64_t timeUs; + CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); + + sp meta = ab->meta(); + meta->setInt64("timeUs", timeUs); + + int64_t durationUs; + if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { + meta->setInt64("durationUs", durationUs); + } + + if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { + meta->setInt32("trackIndex", mSubtitleTrack.mIndex); + } + + if (actualTimeUs) { + *actualTimeUs = timeUs; + } + + mb->release(); + mb = NULL; + + return ab; +} + void NuPlayer::GenericSource::readBuffer( - bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) { - Track *track = audio ? &mAudioTrack : &mVideoTrack; - CHECK(track->mSource != NULL); + media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) { + Track *track; + switch (trackType) { + case MEDIA_TRACK_TYPE_VIDEO: + track = &mVideoTrack; + break; + case MEDIA_TRACK_TYPE_AUDIO: + track = &mAudioTrack; + break; + case MEDIA_TRACK_TYPE_SUBTITLE: + track = &mSubtitleTrack; + break; + default: + TRESPASS(); + } + + if (track->mSource == NULL) { + return; + } if (actualTimeUs) { *actualTimeUs = seekTimeUs; @@ -320,11 +584,11 @@ void NuPlayer::GenericSource::readBuffer( bool seeking = false; if (seekTimeUs >= 0) { - options.setSeekTo(seekTimeUs); + options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); seeking = true; } - if (mIsWidevine && !audio) { + if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) { options.setNonBlocking(); } @@ -335,56 +599,19 @@ void NuPlayer::GenericSource::readBuffer( options.clearSeekTo(); if (err == OK) { - size_t outLength = mbuf->range_length(); - - if (audio && mAudioIsVorbis) { - outLength += sizeof(int32_t); - } - - sp buffer; - if (mIsWidevine && !audio) { - // data is already provided in the buffer - buffer = new ABuffer(NULL, mbuf->range_length()); - buffer->meta()->setPointer("mediaBuffer", mbuf); - mbuf->add_ref(); - } else { - buffer = new ABuffer(outLength); - memcpy(buffer->data(), - (const uint8_t *)mbuf->data() + mbuf->range_offset(), - mbuf->range_length()); - } - - if (audio && mAudioIsVorbis) { - int32_t numPageSamples; - if (!mbuf->meta_data()->findInt32( - kKeyValidSamples, &numPageSamples)) { - numPageSamples = -1; - } - - memcpy(buffer->data() + mbuf->range_length(), - &numPageSamples, - sizeof(numPageSamples)); - } - - int64_t timeUs; - CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); - - buffer->meta()->setInt64("timeUs", timeUs); - - if (actualTimeUs) { - *actualTimeUs = timeUs; - } - - mbuf->release(); - mbuf = NULL; - - if (seeking) { - track->mPackets->queueDiscontinuity( - ATSParser::DISCONTINUITY_SEEK, - NULL, - true /* discard */); + // formatChange && seeking: track whose source is changed during selection + // formatChange && !seeking: track whose source is not changed during selection + // !formatChange: normal seek + if ((seeking || formatChange) && trackType != MEDIA_TRACK_TYPE_SUBTITLE) { + ATSParser::DiscontinuityType type = formatChange + ? (seeking + ? ATSParser::DISCONTINUITY_FORMATCHANGE + : ATSParser::DISCONTINUITY_NONE) + : ATSParser::DISCONTINUITY_SEEK; + track->mPackets->queueDiscontinuity( type, NULL, true /* discard */); } + sp buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs); track->mPackets->queueAccessUnit(buffer); break; } else if (err == WOULD_BLOCK) { diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 8e0209d..4e25d55 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -23,12 +23,15 @@ #include "ATSParser.h" +#include + namespace android { struct AnotherPacketSource; struct ARTSPController; struct DataSource; struct MediaSource; +class MediaBuffer; struct NuPlayer::GenericSource : public NuPlayer::Source { GenericSource( @@ -55,6 +58,7 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual status_t getDuration(int64_t *durationUs); virtual size_t getTrackCount() const; virtual sp getTrackInfo(size_t trackIndex) const; + virtual status_t selectTrack(size_t trackIndex, bool select); virtual status_t seekTo(int64_t seekTimeUs); virtual status_t setBuffers(bool audio, Vector &buffers); @@ -62,9 +66,17 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { protected: virtual ~GenericSource(); + virtual void onMessageReceived(const sp &msg); + virtual sp getFormatMeta(bool audio); private: + enum { + kWhatFetchSubtitleData, + kWhatSendSubtitleData, + kWhatChangeAVSource, + }; + Vector > mSources; struct Track { @@ -75,7 +87,9 @@ private: Track mAudioTrack; Track mVideoTrack; + Track mSubtitleTrack; + int32_t mFetchSubtitleDataGeneration; int64_t mDurationUs; bool mAudioIsVorbis; bool mIsWidevine; @@ -84,9 +98,14 @@ private: void initFromDataSource(const sp &dataSource); + sp mediaBufferToABuffer( + MediaBuffer *mbuf, + media_track_type trackType, + int64_t *actualTimeUs = NULL); + void readBuffer( - bool audio, - int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL); + media_track_type trackType, + int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL, bool formatChange = false); DISALLOW_EVIL_CONSTRUCTORS(GenericSource); }; diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index a0319ab..72c9dae 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -34,6 +34,7 @@ const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs AnotherPacketSource::AnotherPacketSource(const sp &meta) : mIsAudio(false), + mIsVideo(false), mFormat(NULL), mLastQueuedTimeUs(0), mEOSResult(OK), @@ -45,6 +46,7 @@ void AnotherPacketSource::setFormat(const sp &meta) { CHECK(mFormat == NULL); mIsAudio = false; + mIsVideo = false; if (meta == NULL) { return; @@ -56,8 +58,10 @@ void AnotherPacketSource::setFormat(const sp &meta) { if (!strncasecmp("audio/", mime, 6)) { mIsAudio = true; + } else if (!strncasecmp("video/", mime, 6)) { + mIsVideo = true; } else { - CHECK(!strncasecmp("video/", mime, 6)); + CHECK(!strncasecmp("text/", mime, 5)); } } @@ -175,7 +179,11 @@ bool AnotherPacketSource::wasFormatChange( return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0; } - return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0; + if (mIsVideo) { + return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0; + } + + return false; } void AnotherPacketSource::queueAccessUnit(const sp &buffer) { diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h index 06c49bd..f38f9dc 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h @@ -74,6 +74,7 @@ private: Condition mCondition; bool mIsAudio; + bool mIsVideo; sp mFormat; int64_t mLastQueuedTimeUs; List > mBuffers; -- cgit v1.1 From d88adb96ec867ed1b629c434f87514d2fabaf5e9 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 23 Jul 2014 11:43:46 -0700 Subject: NuPlayer: save thread id in MediaPlayer::start so that when MediaPlayer::notify is called from within start, it doesn't try to lock itself again. Bug: 15323063 Change-Id: Idd77e892cd22538bbfe3e65c64c9dd2a216a0aee --- media/libmedia/mediaplayer.cpp | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'media') diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 889bd7f..2b7ea97 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -283,16 +283,21 @@ status_t MediaPlayer::prepareAsync() status_t MediaPlayer::start() { ALOGV("start"); + + status_t ret = NO_ERROR; Mutex::Autolock _l(mLock); - if (mCurrentState & MEDIA_PLAYER_STARTED) - return NO_ERROR; - if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED | + + mLockThreadId = getThreadId(); + + if (mCurrentState & MEDIA_PLAYER_STARTED) { + ret = NO_ERROR; + } else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) { mPlayer->setLooping(mLoop); mPlayer->setVolume(mLeftVolume, mRightVolume); mPlayer->setAuxEffectSendLevel(mSendLevel); mCurrentState = MEDIA_PLAYER_STARTED; - status_t ret = mPlayer->start(); + ret = mPlayer->start(); if (ret != NO_ERROR) { mCurrentState = MEDIA_PLAYER_STATE_ERROR; } else { @@ -300,10 +305,14 @@ status_t MediaPlayer::start() ALOGV("playback completed immediately following start()"); } } - return ret; + } else { + ALOGE("start called in state %d", mCurrentState); + ret = INVALID_OPERATION; } - ALOGE("start called in state %d", mCurrentState); - return INVALID_OPERATION; + + mLockThreadId = 0; + + return ret; } status_t MediaPlayer::stop() @@ -706,8 +715,8 @@ void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj) // running in the same process as the media server. In that case, // this will deadlock. // - // The threadId hack below works around this for the care of prepare - // and seekTo within the same process. + // The threadId hack below works around this for the care of prepare, + // seekTo and start within the same process. // FIXME: Remember, this is a hack, it's not even a hack that is applied // consistently for all use-cases, this needs to be revisited. if (mLockThreadId != getThreadId()) { -- cgit v1.1 From 4730fa07a3290cc3a904dcb16dbb92fcf46c36ac Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 23 Jul 2014 10:40:46 -0700 Subject: Hook up querying of VP8 temporal layering support. Bug: 14562236 Change-Id: I0ec5866173f7fb84dd3f79b588d1b35b523ca08a --- media/libstagefright/ACodec.cpp | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 6cb1c64..b6cc742 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -2765,6 +2765,50 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { break; } + + case OMX_VIDEO_CodingVP8: + case OMX_VIDEO_CodingVP9: + { + OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE vp8type; + InitOMXParams(&vp8type); + vp8type.nPortIndex = kPortIndexOutput; + status_t err = mOMX->getParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamVideoAndroidVp8Encoder, + &vp8type, + sizeof(vp8type)); + + if (err == OK) { + AString tsSchema = "none"; + if (vp8type.eTemporalPattern + == OMX_VIDEO_VPXTemporalLayerPatternWebRTC) { + switch (vp8type.nTemporalLayerCount) { + case 1: + { + tsSchema = "webrtc.vp8.1-layer"; + break; + } + case 2: + { + tsSchema = "webrtc.vp8.2-layer"; + break; + } + case 3: + { + tsSchema = "webrtc.vp8.3-layer"; + break; + } + default: + { + break; + } + } + } + notify->setString("ts-schema", tsSchema); + } + // Fall through to set up mime. + } + default: { CHECK(mIsEncoder ^ (portIndex == kPortIndexInput)); -- cgit v1.1 From 0b30fd4ccf5218b15f770e778703d69cd3432446 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 23 Jul 2014 14:46:05 -0700 Subject: reset battery stats when media player service is started Bug: 12979595 Change-Id: Ia800de3e65ed4dec8334c6fde566edab12d23c42 --- media/libmediaplayerservice/MediaPlayerService.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 7218467..735344c 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -34,6 +34,7 @@ #include +#include #include #include #include @@ -275,6 +276,20 @@ MediaPlayerService::MediaPlayerService() // speaker is on by default mBatteryAudio.deviceOn[SPEAKER] = 1; + // reset battery stats + // if the mediaserver has crashed, battery stats could be left + // in bad state, reset the state upon service start. + const sp sm(defaultServiceManager()); + if (sm != NULL) { + const String16 name("batterystats"); + sp batteryStats = + interface_cast(sm->getService(name)); + if (batteryStats != NULL) { + batteryStats->noteResetVideo(); + batteryStats->noteResetAudio(); + } + } + MediaPlayerFactory::registerBuiltinFactories(); } -- cgit v1.1 From e07909715b44cc56df723750af93f0608210f94d Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Wed, 23 Jul 2014 15:17:26 -0700 Subject: CamcorderProfiles: add high speed profile constants Change-Id: I8f783466f8c2560820db14488acc1a309d27ab0f --- media/libmedia/MediaProfiles.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp index e9e453b..d2e181b 100644 --- a/media/libmedia/MediaProfiles.cpp +++ b/media/libmedia/MediaProfiles.cpp @@ -81,6 +81,12 @@ const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = { {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P}, {"timelapse2160p", CAMCORDER_QUALITY_TIME_LAPSE_2160P}, {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA}, + + {"highspeedlow", CAMCORDER_QUALITY_HIGH_SPEED_LOW}, + {"highspeedhigh", CAMCORDER_QUALITY_HIGH_SPEED_HIGH}, + {"highspeed480p", CAMCORDER_QUALITY_HIGH_SPEED_480P}, + {"highspeed720p", CAMCORDER_QUALITY_HIGH_SPEED_720P}, + {"highspeed1080p", CAMCORDER_QUALITY_HIGH_SPEED_1080P}, }; #if LOG_NDEBUG @@ -474,6 +480,11 @@ static bool isTimelapseProfile(camcorder_quality quality) { quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END; } +static bool isHighSpeedProfile(camcorder_quality quality) { + return quality >= CAMCORDER_QUALITY_HIGH_SPEED_LIST_START && + quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END; +} + void MediaProfiles::initRequiredProfileRefs(const Vector& cameraIds) { ALOGV("Number of camera ids: %zu", cameraIds.size()); CHECK(cameraIds.size() > 0); @@ -521,14 +532,17 @@ void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() { camcorder_quality refQuality; VideoCodec *codec = NULL; - // Check high and low from either camcorder profile or timelapse profile - // but not both. Default, check camcorder profile + // Check high and low from either camcorder profile, timelapse profile + // or high speed profile, but not all of them. Default, check camcorder profile size_t j = 0; size_t o = 2; if (isTimelapseProfile(quality)) { // Check timelapse profile instead. j = 2; o = kNumRequiredProfiles; + } else if (isHighSpeedProfile(quality)) { + // Skip the check for high speed profile. + continue; } else { // Must be camcorder profile. CHECK(isCamcorderProfile(quality)); -- cgit v1.1 From d459e303f2f1d34c2b8c1af4f943747b20a8b1b2 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 23 Jul 2014 19:23:16 -0700 Subject: signal mFrameAvailableCondition when AudioSource is stopped This allows last read() to exit properly, otherwise it could get stuck waiting for the condition forever. Bug: 15849309 Change-Id: I79bba53630e59783a5fc041cfc5d3fdb2545cc2c --- media/libstagefright/AudioSource.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'media') diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index d9aed01..a67fabe 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -159,6 +159,8 @@ status_t AudioSource::reset() { waitOutstandingEncodingFrames_l(); releaseQueuedFrames_l(); + mFrameAvailableCondition.signal(); + return OK; } -- cgit v1.1 From 81e50d0c782cc18eab4ef40ecd6c7f36df50fea5 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Thu, 24 Jul 2014 10:28:47 -0700 Subject: Reset the value for Vector of pointers. Bug: 16467066 Change-Id: I3674e07779a59f4d4fa639d066ed1988df89b3f5 --- media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 1b9bafb..8fce2f4 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -155,8 +155,14 @@ void NuPlayer::Decoder::releaseAndResetMediaBuffers() { } } mMediaBuffers.resize(mInputBuffers.size()); + for (size_t i = 0; i < mMediaBuffers.size(); i++) { + mMediaBuffers.editItemAt(i) = NULL; + } mInputBufferIsDequeued.clear(); mInputBufferIsDequeued.resize(mInputBuffers.size()); + for (size_t i = 0; i < mInputBufferIsDequeued.size(); i++) { + mInputBufferIsDequeued.editItemAt(i) = false; + } } void NuPlayer::Decoder::requestCodecNotification() { -- cgit v1.1 From 68e97e7388bc9efa03e56c999645002cc3f38df5 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 24 Jul 2014 14:00:09 -0700 Subject: StagefrightRecorder: check for WEBM format instead of MP4 Bug: 16544665 Change-Id: Idc45bd4cafc65a11132d10fdf21f8439e186f35f --- media/libmediaplayerservice/StagefrightRecorder.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 217b248..8774117 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -1551,10 +1551,10 @@ status_t StagefrightRecorder::setupMPEG4orWEBMRecording() { status_t err = OK; sp writer; - if (mOutputFormat == OUTPUT_FORMAT_MPEG_4) { - writer = new MPEG4Writer(mOutputFd); - } else { + if (mOutputFormat == OUTPUT_FORMAT_WEBM) { writer = new WebmWriter(mOutputFd); + } else { + writer = new MPEG4Writer(mOutputFd); } if (mVideoSource < VIDEO_SOURCE_LIST_END) { @@ -1575,7 +1575,7 @@ status_t StagefrightRecorder::setupMPEG4orWEBMRecording() { mTotalBitRate += mVideoBitRate; } - if (mOutputFormat == OUTPUT_FORMAT_MPEG_4) { + if (mOutputFormat != OUTPUT_FORMAT_WEBM) { // Audio source is added at the end if it exists. // This help make sure that the "recoding" sound is suppressed for // camcorder applications in the recorded files. @@ -1625,7 +1625,7 @@ void StagefrightRecorder::setupMPEG4orWEBMMetaData(sp *meta) { if (mMovieTimeScale > 0) { (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale); } - if (mOutputFormat == OUTPUT_FORMAT_MPEG_4) { + if (mOutputFormat != OUTPUT_FORMAT_WEBM) { (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset); if (mTrackEveryTimeDurationUs > 0) { (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs); -- cgit v1.1 From 37b216c75ca5e38f1a56a86a95b04ff6b4e71ae7 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 24 Jul 2014 15:42:39 -0700 Subject: Remove last user of . Bug: 15765976 (cherry picked from commit 56687f7cbf0a3d7909830fc1390a98c713a05e6f) Change-Id: Iacb225584c3acdbb512f46b638a215b75b32cdcb --- media/mtp/Android.mk | 3 --- media/mtp/MtpUtils.cpp | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk index ac608a1..3af0956 100644 --- a/media/mtp/Android.mk +++ b/media/mtp/Android.mk @@ -39,9 +39,6 @@ LOCAL_MODULE:= libmtp LOCAL_CFLAGS := -DMTP_DEVICE -DMTP_HOST -# Needed for -LOCAL_C_INCLUDES := bionic/libc/private - LOCAL_SHARED_LIBRARIES := libutils libcutils liblog libusbhost libbinder include $(BUILD_SHARED_LIBRARY) diff --git a/media/mtp/MtpUtils.cpp b/media/mtp/MtpUtils.cpp index 6ec8876..0667bdd 100644 --- a/media/mtp/MtpUtils.cpp +++ b/media/mtp/MtpUtils.cpp @@ -19,7 +19,8 @@ #include #include -#include +#include <../private/bionic_time.h> /* TODO: switch this code to icu4c! */ + #include "MtpUtils.h" namespace android { -- cgit v1.1 From d3b0bbb8a37f90fba84eb4e95c58aa0fec6c51e7 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 23 Jul 2014 15:00:25 -0700 Subject: NuPlayer: timed text support Bug: 16385674 Change-Id: Ifa9fbc17a1276aa774d57b82cdce500876a0b543 --- media/libmediaplayerservice/nuplayer/Android.mk | 1 + media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 74 ++++++++++++++++++++++ media/libmediaplayerservice/nuplayer/NuPlayer.h | 2 + .../nuplayer/NuPlayerSource.h | 1 + 4 files changed, 78 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk index 25002e3..0dd2b61 100644 --- a/media/libmediaplayerservice/nuplayer/Android.mk +++ b/media/libmediaplayerservice/nuplayer/Android.mk @@ -18,6 +18,7 @@ LOCAL_C_INCLUDES := \ $(TOP)/frameworks/av/media/libstagefright/include \ $(TOP)/frameworks/av/media/libstagefright/mpeg2ts \ $(TOP)/frameworks/av/media/libstagefright/rtsp \ + $(TOP)/frameworks/av/media/libstagefright/timedtext \ $(TOP)/frameworks/native/include/media/openmax LOCAL_MODULE:= libstagefright_nuplayer diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 6ccd27a..f876cce 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -29,6 +29,7 @@ #include "RTSPSource.h" #include "StreamingSource.h" #include "GenericSource.h" +#include "TextDescriptions.h" #include "ATSParser.h" @@ -151,6 +152,7 @@ NuPlayer::NuPlayer() mScanSourcesPending(false), mScanSourcesGeneration(0), mPollDurationGeneration(0), + mTimedTextGeneration(0), mTimeDiscontinuityPending(false), mFlushingAudio(NONE), mFlushingVideo(NONE), @@ -428,6 +430,16 @@ void NuPlayer::onMessageReceived(const sp &msg) { if (trackIndex < inbandTracks) { err = mSource->selectTrack(trackIndex, select); + + if (!select && err == OK) { + int32_t type; + sp info = mSource->getTrackInfo(trackIndex); + if (info != NULL + && info->findInt32("type", &type) + && type == MEDIA_TRACK_TYPE_TIMEDTEXT) { + ++mTimedTextGeneration; + } + } } else { trackIndex -= inbandTracks; @@ -1475,6 +1487,7 @@ void NuPlayer::performSeek(int64_t seekTimeUs) { seekTimeUs / 1E6); mSource->seekTo(seekTimeUs); + ++mTimedTextGeneration; if (mDriver != NULL) { sp driver = mDriver.promote(); @@ -1683,6 +1696,39 @@ void NuPlayer::onSourceNotify(const sp &msg) { break; } + case Source::kWhatTimedTextData: + { + int32_t generation; + if (msg->findInt32("generation", &generation) + && generation != mTimedTextGeneration) { + break; + } + + sp buffer; + CHECK(msg->findBuffer("buffer", &buffer)); + + sp driver = mDriver.promote(); + if (driver == NULL) { + break; + } + + int posMs; + int64_t timeUs, posUs; + driver->getCurrentPosition(&posMs); + posUs = posMs * 1000; + CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); + + if (posUs < timeUs) { + if (!msg->findInt32("generation", &generation)) { + msg->setInt32("generation", mTimedTextGeneration); + } + msg->post(timeUs - posUs); + } else { + sendTimedTextData(buffer); + } + break; + } + case Source::kWhatQueueDecoderShutdown: { int32_t audio, video; @@ -1751,6 +1797,34 @@ void NuPlayer::sendSubtitleData(const sp &buffer, int32_t baseIndex) { notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in); } + +void NuPlayer::sendTimedTextData(const sp &buffer) { + const void *data; + size_t size = 0; + int64_t timeUs; + int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS; + + AString mime; + CHECK(buffer->meta()->findString("mime", &mime)); + CHECK(strcasecmp(mime.c_str(), MEDIA_MIMETYPE_TEXT_3GPP) == 0); + + data = buffer->data(); + size = buffer->size(); + + Parcel parcel; + if (size > 0) { + CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); + flag |= TextDescriptions::IN_BAND_TEXT_3GPP; + TextDescriptions::getParcelOfDescriptions( + (const uint8_t *)data, size, flag, timeUs / 1000, &parcel); + } + + if ((parcel.dataSize() > 0)) { + notifyListener(MEDIA_TIMED_TEXT, 0, 0, &parcel); + } else { // send an empty timed text + notifyListener(MEDIA_TIMED_TEXT, 0, 0); + } +} //////////////////////////////////////////////////////////////////////////////// void NuPlayer::Source::notifyFlagsChanged(uint32_t flags) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index c04e277..8bcf10e 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -136,6 +136,7 @@ private: int32_t mScanSourcesGeneration; int32_t mPollDurationGeneration; + int32_t mTimedTextGeneration; enum FlushStatus { NONE, @@ -198,6 +199,7 @@ private: bool audio, bool video, const sp &reply); void sendSubtitleData(const sp &buffer, int32_t baseIndex); + void sendTimedTextData(const sp &buffer); void writeTrackInfo(Parcel* reply, const sp format) const; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index 259925f..0ec017e 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -47,6 +47,7 @@ struct NuPlayer::Source : public AHandler { kWhatBufferingStart, kWhatBufferingEnd, kWhatSubtitleData, + kWhatTimedTextData, kWhatQueueDecoderShutdown, }; -- cgit v1.1 From ca73159becc0fc0098530929e467a3d92e470571 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Fri, 25 Jul 2014 18:05:46 -0700 Subject: DNG: Clean up logging. Change-Id: Ie34d5a22c89a726215d740fef359d53e5a1a360b --- media/img_utils/src/TiffEntry.cpp | 10 ++++++++-- media/img_utils/src/TiffWriter.cpp | 8 +++----- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/img_utils/src/TiffEntry.cpp b/media/img_utils/src/TiffEntry.cpp index 9cea721..1b20e36 100644 --- a/media/img_utils/src/TiffEntry.cpp +++ b/media/img_utils/src/TiffEntry.cpp @@ -203,14 +203,20 @@ String8 TiffEntry::toString() const { } break; } - case FLOAT: - case DOUBLE: { + case FLOAT: { const float* typed_data = getData(); for (size_t i = 0; i < cappedCount; ++i) { output.appendFormat("%f ", typed_data[i]); } break; } + case DOUBLE: { + const double* typed_data = getData(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%f ", typed_data[i]); + } + break; + } default: { output.append("unknown type "); break; diff --git a/media/img_utils/src/TiffWriter.cpp b/media/img_utils/src/TiffWriter.cpp index d85289e..ac41734 100644 --- a/media/img_utils/src/TiffWriter.cpp +++ b/media/img_utils/src/TiffWriter.cpp @@ -66,10 +66,6 @@ status_t TiffWriter::write(Output* out, StripSource** sources, size_t sourcesCou return BAD_VALUE; } - if (LOG_NDEBUG == 0) { - log(); - } - uint32_t totalSize = getTotalSize(); KeyedVector offsetVector; @@ -104,7 +100,9 @@ status_t TiffWriter::write(Output* out, StripSource** sources, size_t sourcesCou ifd = ifd->getNextIfd(); } - log(); + if (LOG_NDEBUG == 0) { + log(); + } for (size_t i = 0; i < offVecSize; ++i) { uint32_t ifdKey = offsetVector.keyAt(i); -- cgit v1.1 From eb1735e343a93830df259ae8882160bb0d79dcb5 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 23 Jul 2014 15:53:14 -0700 Subject: GenericSource: timed text support Bug: 16385674 Change-Id: I954cc463b55af4b93c6a6e714115db4fda729dc8 --- .../nuplayer/GenericSource.cpp | 255 +++++++++++++++------ .../libmediaplayerservice/nuplayer/GenericSource.h | 13 ++ 2 files changed, 195 insertions(+), 73 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 63a907c..4c6a59c 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -42,6 +42,7 @@ NuPlayer::GenericSource::GenericSource( uid_t uid) : Source(notify), mFetchSubtitleDataGeneration(0), + mFetchTimedTextDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false), mIsWidevine(isWidevine), @@ -61,6 +62,7 @@ NuPlayer::GenericSource::GenericSource( int fd, int64_t offset, int64_t length) : Source(notify), mFetchSubtitleDataGeneration(0), + mFetchTimedTextDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false) { DataSource::RegisterDefaultSniffers(); @@ -204,66 +206,29 @@ void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { switch (msg->what()) { case kWhatFetchSubtitleData: { - int32_t generation; - CHECK(msg->findInt32("generation", &generation)); - if (generation != mFetchSubtitleDataGeneration) { - // stale - break; - } - - int32_t avail; - if (mSubtitleTrack.mPackets->hasBufferAvailable(&avail)) { - break; - } - - int64_t timeUs; - CHECK(msg->findInt64("timeUs", &timeUs)); - - int64_t subTimeUs; - readBuffer(MEDIA_TRACK_TYPE_SUBTITLE, timeUs, &subTimeUs); - - const int64_t oneSecUs = 1000000ll; - const int64_t delayUs = subTimeUs - timeUs - oneSecUs; - sp msg2 = new AMessage(kWhatSendSubtitleData, id()); - msg2->setInt32("generation", generation); - msg2->post(delayUs < 0 ? 0 : delayUs); - ALOGV("kWhatFetchSubtitleData generation %d, delayUs %lld", - mFetchSubtitleDataGeneration, delayUs); + fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, + mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); + break; + } + case kWhatFetchTimedTextData: + { + fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, + mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); break; } case kWhatSendSubtitleData: { - int32_t generation; - CHECK(msg->findInt32("generation", &generation)); - if (generation != mFetchSubtitleDataGeneration) { - // stale - break; - } - - int64_t subTimeUs; - if (mSubtitleTrack.mPackets->nextBufferTime(&subTimeUs) != OK) { - break; - } - - int64_t nextSubTimeUs; - readBuffer(MEDIA_TRACK_TYPE_SUBTITLE, -1, &nextSubTimeUs); - - sp buffer; - status_t dequeueStatus = mSubtitleTrack.mPackets->dequeueAccessUnit(&buffer); - if (dequeueStatus != OK) { - ALOGE("kWhatSendSubtitleData dequeueAccessUnit: %d", dequeueStatus); - } else { - sp notify = dupNotify(); - notify->setInt32("what", kWhatSubtitleData); - notify->setBuffer("buffer", buffer); - notify->post(); - - const int64_t delayUs = nextSubTimeUs - subTimeUs; - msg->post(delayUs < 0 ? 0 : delayUs); - } + sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, + mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); + break; + } + case kWhatSendTimedTextData: + { + sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, + mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); break; } @@ -317,6 +282,74 @@ void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { } } +void NuPlayer::GenericSource::fetchTextData( + uint32_t sendWhat, + media_track_type type, + int32_t curGen, + sp packets, + sp msg) { + int32_t msgGeneration; + CHECK(msg->findInt32("generation", &msgGeneration)); + if (msgGeneration != curGen) { + // stale + return; + } + + int32_t avail; + if (packets->hasBufferAvailable(&avail)) { + return; + } + + int64_t timeUs; + CHECK(msg->findInt64("timeUs", &timeUs)); + + int64_t subTimeUs; + readBuffer(type, timeUs, &subTimeUs); + + int64_t delayUs = subTimeUs - timeUs; + if (msg->what() == kWhatFetchSubtitleData) { + const int64_t oneSecUs = 1000000ll; + delayUs -= oneSecUs; + } + sp msg2 = new AMessage(sendWhat, id()); + msg2->setInt32("generation", msgGeneration); + msg2->post(delayUs < 0 ? 0 : delayUs); +} + +void NuPlayer::GenericSource::sendTextData( + uint32_t what, + media_track_type type, + int32_t curGen, + sp packets, + sp msg) { + int32_t msgGeneration; + CHECK(msg->findInt32("generation", &msgGeneration)); + if (msgGeneration != curGen) { + // stale + return; + } + + int64_t subTimeUs; + if (packets->nextBufferTime(&subTimeUs) != OK) { + return; + } + + int64_t nextSubTimeUs; + readBuffer(type, -1, &nextSubTimeUs); + + sp buffer; + status_t dequeueStatus = packets->dequeueAccessUnit(&buffer); + if (dequeueStatus == OK) { + sp notify = dupNotify(); + notify->setInt32("what", what); + notify->setBuffer("buffer", buffer); + notify->post(); + + const int64_t delayUs = nextSubTimeUs - subTimeUs; + msg->post(delayUs < 0 ? 0 : delayUs); + } +} + sp NuPlayer::GenericSource::getFormatMeta(bool audio) { sp source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; @@ -351,27 +384,49 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll); } - if (mSubtitleTrack.mSource == NULL) { + if (mSubtitleTrack.mSource == NULL && mTimedTextTrack.mSource == NULL) { return result; } - CHECK(mSubtitleTrack.mPackets != NULL); + if (mSubtitleTrack.mSource != NULL) { + CHECK(mSubtitleTrack.mPackets != NULL); + } + if (mTimedTextTrack.mSource != NULL) { + CHECK(mTimedTextTrack.mPackets != NULL); + } + if (result != OK) { - mSubtitleTrack.mPackets->clear(); - mFetchSubtitleDataGeneration++; + if (mSubtitleTrack.mSource != NULL) { + mSubtitleTrack.mPackets->clear(); + mFetchSubtitleDataGeneration++; + } + if (mTimedTextTrack.mSource != NULL) { + mTimedTextTrack.mPackets->clear(); + mFetchTimedTextDataGeneration++; + } return result; } int64_t timeUs; status_t eosResult; // ignored CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); - if (!mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { + + if (mSubtitleTrack.mSource != NULL + && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { sp msg = new AMessage(kWhatFetchSubtitleData, id()); msg->setInt64("timeUs", timeUs); msg->setInt32("generation", mFetchSubtitleDataGeneration); msg->post(); } + if (mTimedTextTrack.mSource != NULL + && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { + sp msg = new AMessage(kWhatFetchTimedTextData, id()); + msg->setInt64("timeUs", timeUs); + msg->setInt32("generation", mFetchTimedTextDataGeneration); + msg->post(); + } + return result; } @@ -430,19 +485,52 @@ sp NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { return format; } +ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { + const Track *track = NULL; + switch (type) { + case MEDIA_TRACK_TYPE_VIDEO: + track = &mVideoTrack; + break; + case MEDIA_TRACK_TYPE_AUDIO: + track = &mAudioTrack; + break; + case MEDIA_TRACK_TYPE_TIMEDTEXT: + track = &mTimedTextTrack; + break; + case MEDIA_TRACK_TYPE_SUBTITLE: + track = &mSubtitleTrack; + break; + default: + break; + } + + if (track != NULL && track->mSource != NULL) { + return track->mIndex; + } + + return -1; +} + status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { - ALOGV("selectTrack: %zu", trackIndex); + ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); if (trackIndex >= mSources.size()) { return BAD_INDEX; } if (!select) { - if (mSubtitleTrack.mSource == NULL || trackIndex != mSubtitleTrack.mIndex) { + Track* track = NULL; + if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) { + track = &mSubtitleTrack; + mFetchSubtitleDataGeneration++; + } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) { + track = &mTimedTextTrack; + mFetchTimedTextDataGeneration++; + } + if (track == NULL) { return INVALID_OPERATION; } - mSubtitleTrack.mSource = NULL; - mSubtitleTrack.mPackets->clear(); - mFetchSubtitleDataGeneration++; + track->mSource = NULL; + track->mPackets->clear(); return OK; } @@ -451,18 +539,27 @@ status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); if (!strncasecmp(mime, "text/", 5)) { - if (mSubtitleTrack.mSource != NULL && mSubtitleTrack.mIndex == trackIndex) { + bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP); + Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack; + if (track->mSource != NULL && track->mIndex == trackIndex) { return OK; } - mSubtitleTrack.mIndex = trackIndex; - mSubtitleTrack.mSource = mSources.itemAt(trackIndex); - if (mSubtitleTrack.mPackets == NULL) { - mSubtitleTrack.mPackets = new AnotherPacketSource(mSubtitleTrack.mSource->getFormat()); + track->mIndex = trackIndex; + track->mSource = mSources.itemAt(trackIndex); + if (track->mPackets == NULL) { + track->mPackets = new AnotherPacketSource(track->mSource->getFormat()); } else { - mSubtitleTrack.mPackets->clear(); + track->mPackets->clear(); + track->mPackets->setFormat(track->mSource->getFormat()); } - mFetchSubtitleDataGeneration++; + + if (isSubtitle) { + mFetchSubtitleDataGeneration++; + } else { + mFetchTimedTextDataGeneration++; + } + return OK; } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { bool audio = !strncasecmp(mime, "audio/", 6); @@ -529,12 +626,19 @@ sp NuPlayer::GenericSource::mediaBufferToABuffer( memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); } + sp meta = ab->meta(); + int64_t timeUs; CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); - - sp meta = ab->meta(); meta->setInt64("timeUs", timeUs); + if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { + const char *mime; + CHECK(mTimedTextTrack.mSource != NULL + && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime)); + meta->setString("mime", mime); + } + int64_t durationUs; if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { meta->setInt64("durationUs", durationUs); @@ -567,6 +671,9 @@ void NuPlayer::GenericSource::readBuffer( case MEDIA_TRACK_TYPE_SUBTITLE: track = &mSubtitleTrack; break; + case MEDIA_TRACK_TYPE_TIMEDTEXT: + track = &mTimedTextTrack; + break; default: TRESPASS(); } @@ -602,7 +709,9 @@ void NuPlayer::GenericSource::readBuffer( // formatChange && seeking: track whose source is changed during selection // formatChange && !seeking: track whose source is not changed during selection // !formatChange: normal seek - if ((seeking || formatChange) && trackType != MEDIA_TRACK_TYPE_SUBTITLE) { + if ((seeking || formatChange) + && (trackType == MEDIA_TRACK_TYPE_AUDIO + || trackType == MEDIA_TRACK_TYPE_VIDEO)) { ATSParser::DiscontinuityType type = formatChange ? (seeking ? ATSParser::DISCONTINUITY_FORMATCHANGE diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 4e25d55..3c5f55c 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -58,6 +58,7 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual status_t getDuration(int64_t *durationUs); virtual size_t getTrackCount() const; virtual sp getTrackInfo(size_t trackIndex) const; + virtual ssize_t getSelectedTrack(media_track_type type) const; virtual status_t selectTrack(size_t trackIndex, bool select); virtual status_t seekTo(int64_t seekTimeUs); @@ -73,7 +74,9 @@ protected: private: enum { kWhatFetchSubtitleData, + kWhatFetchTimedTextData, kWhatSendSubtitleData, + kWhatSendTimedTextData, kWhatChangeAVSource, }; @@ -88,8 +91,10 @@ private: Track mAudioTrack; Track mVideoTrack; Track mSubtitleTrack; + Track mTimedTextTrack; int32_t mFetchSubtitleDataGeneration; + int32_t mFetchTimedTextDataGeneration; int64_t mDurationUs; bool mAudioIsVorbis; bool mIsWidevine; @@ -98,6 +103,14 @@ private: void initFromDataSource(const sp &dataSource); + void fetchTextData( + uint32_t what, media_track_type type, + int32_t curGen, sp packets, sp msg); + + void sendTextData( + uint32_t what, media_track_type type, + int32_t curGen, sp packets, sp msg); + sp mediaBufferToABuffer( MediaBuffer *mbuf, media_track_type trackType, -- cgit v1.1 From cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bf Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 25 Jul 2014 16:20:43 -0700 Subject: AudioFlinger: update openInput() and openOutput() Add parameters to openInput() and openOutput(): device address, input source. Allow caller to specify a given I/O handle Group parameters in a struct audio_config. Bug: 12378680. Change-Id: I7e9af74c0d996561cc13cbee7d9012d2daf33025 --- media/libmedia/IAudioFlinger.cpp | 201 ++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 119 deletions(-) (limited to 'media') diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index bd7ea46..0f4e632 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -434,61 +434,40 @@ public: return reply.readInt64(); } - virtual audio_io_handle_t openOutput(audio_module_handle_t module, - audio_devices_t *pDevices, - uint32_t *pSamplingRate, - audio_format_t *pFormat, - audio_channel_mask_t *pChannelMask, - uint32_t *pLatencyMs, - audio_output_flags_t flags, - const audio_offload_info_t *offloadInfo) + virtual status_t openOutput(audio_module_handle_t module, + audio_io_handle_t *output, + audio_config_t *config, + audio_devices_t *devices, + const String8& address, + uint32_t *latencyMs, + audio_output_flags_t flags) { + if (output == NULL || config == NULL || devices == NULL || latencyMs == NULL) { + return BAD_VALUE; + } Parcel data, reply; - audio_devices_t devices = pDevices != NULL ? *pDevices : AUDIO_DEVICE_NONE; - uint32_t samplingRate = pSamplingRate != NULL ? *pSamplingRate : 0; - audio_format_t format = pFormat != NULL ? *pFormat : AUDIO_FORMAT_DEFAULT; - audio_channel_mask_t channelMask = pChannelMask != NULL ? - *pChannelMask : (audio_channel_mask_t)0; - uint32_t latency = pLatencyMs != NULL ? *pLatencyMs : 0; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInt32(module); - data.writeInt32(devices); - data.writeInt32(samplingRate); - data.writeInt32(format); - data.writeInt32(channelMask); - data.writeInt32(latency); + data.write(config, sizeof(audio_config_t)); + data.writeInt32(*devices); + data.writeString8(address); data.writeInt32((int32_t) flags); - // hasOffloadInfo - if (offloadInfo == NULL) { - data.writeInt32(0); - } else { - data.writeInt32(1); - data.write(offloadInfo, sizeof(audio_offload_info_t)); - } - remote()->transact(OPEN_OUTPUT, data, &reply); - audio_io_handle_t output = (audio_io_handle_t) reply.readInt32(); - ALOGV("openOutput() returned output, %d", output); - devices = (audio_devices_t)reply.readInt32(); - if (pDevices != NULL) { - *pDevices = devices; - } - samplingRate = reply.readInt32(); - if (pSamplingRate != NULL) { - *pSamplingRate = samplingRate; - } - format = (audio_format_t) reply.readInt32(); - if (pFormat != NULL) { - *pFormat = format; - } - channelMask = (audio_channel_mask_t)reply.readInt32(); - if (pChannelMask != NULL) { - *pChannelMask = channelMask; + status_t status = remote()->transact(OPEN_OUTPUT, data, &reply); + if (status != NO_ERROR) { + *output = AUDIO_IO_HANDLE_NONE; + return status; } - latency = reply.readInt32(); - if (pLatencyMs != NULL) { - *pLatencyMs = latency; + status = (status_t)reply.readInt32(); + if (status != NO_ERROR) { + *output = AUDIO_IO_HANDLE_NONE; + return status; } - return output; + *output = (audio_io_handle_t)reply.readInt32(); + ALOGV("openOutput() returned output, %d", *output); + reply.read(config, sizeof(audio_config_t)); + *devices = (audio_devices_t)reply.readInt32(); + *latencyMs = reply.readInt32(); + return NO_ERROR; } virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, @@ -529,46 +508,40 @@ public: return reply.readInt32(); } - virtual audio_io_handle_t openInput(audio_module_handle_t module, - audio_devices_t *pDevices, - uint32_t *pSamplingRate, - audio_format_t *pFormat, - audio_channel_mask_t *pChannelMask, - audio_input_flags_t flags) + virtual status_t openInput(audio_module_handle_t module, + audio_io_handle_t *input, + audio_config_t *config, + audio_devices_t *device, + const String8& address, + audio_source_t source, + audio_input_flags_t flags) { + if (input == NULL || config == NULL || device == NULL) { + return BAD_VALUE; + } Parcel data, reply; - audio_devices_t devices = pDevices != NULL ? *pDevices : AUDIO_DEVICE_NONE; - uint32_t samplingRate = pSamplingRate != NULL ? *pSamplingRate : 0; - audio_format_t format = pFormat != NULL ? *pFormat : AUDIO_FORMAT_DEFAULT; - audio_channel_mask_t channelMask = pChannelMask != NULL ? - *pChannelMask : (audio_channel_mask_t)0; - data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInt32(module); - data.writeInt32(devices); - data.writeInt32(samplingRate); - data.writeInt32(format); - data.writeInt32(channelMask); + data.writeInt32(*input); + data.write(config, sizeof(audio_config_t)); + data.writeInt32(*device); + data.writeString8(address); + data.writeInt32(source); data.writeInt32(flags); - remote()->transact(OPEN_INPUT, data, &reply); - audio_io_handle_t input = (audio_io_handle_t) reply.readInt32(); - devices = (audio_devices_t)reply.readInt32(); - if (pDevices != NULL) { - *pDevices = devices; - } - samplingRate = reply.readInt32(); - if (pSamplingRate != NULL) { - *pSamplingRate = samplingRate; - } - format = (audio_format_t) reply.readInt32(); - if (pFormat != NULL) { - *pFormat = format; + status_t status = remote()->transact(OPEN_INPUT, data, &reply); + if (status != NO_ERROR) { + *input = AUDIO_IO_HANDLE_NONE; + return status; } - channelMask = (audio_channel_mask_t)reply.readInt32(); - if (pChannelMask != NULL) { - *pChannelMask = channelMask; + status = (status_t)reply.readInt32(); + if (status != NO_ERROR) { + *input = AUDIO_IO_HANDLE_NONE; + return status; } - return input; + *input = (audio_io_handle_t)reply.readInt32(); + reply.read(config, sizeof(audio_config_t)); + *device = (audio_devices_t)reply.readInt32(); + return NO_ERROR; } virtual status_t closeInput(int input) @@ -1103,32 +1076,23 @@ status_t BnAudioFlinger::onTransact( case OPEN_OUTPUT: { CHECK_INTERFACE(IAudioFlinger, data, reply); audio_module_handle_t module = (audio_module_handle_t)data.readInt32(); + audio_config_t config; + data.read(&config, sizeof(audio_config_t)); audio_devices_t devices = (audio_devices_t)data.readInt32(); - uint32_t samplingRate = data.readInt32(); - audio_format_t format = (audio_format_t) data.readInt32(); - audio_channel_mask_t channelMask = (audio_channel_mask_t)data.readInt32(); - uint32_t latency = data.readInt32(); + String8 address(data.readString8()); audio_output_flags_t flags = (audio_output_flags_t) data.readInt32(); - bool hasOffloadInfo = data.readInt32() != 0; - audio_offload_info_t offloadInfo; - if (hasOffloadInfo) { - data.read(&offloadInfo, sizeof(audio_offload_info_t)); - } - audio_io_handle_t output = openOutput(module, - &devices, - &samplingRate, - &format, - &channelMask, - &latency, - flags, - hasOffloadInfo ? &offloadInfo : NULL); + uint32_t latencyMs; + audio_io_handle_t output; + status_t status = openOutput(module, &output, &config, + &devices, address, &latencyMs, flags); ALOGV("OPEN_OUTPUT output, %d", output); - reply->writeInt32((int32_t) output); - reply->writeInt32(devices); - reply->writeInt32(samplingRate); - reply->writeInt32(format); - reply->writeInt32(channelMask); - reply->writeInt32(latency); + reply->writeInt32((int32_t)status); + if (status == NO_ERROR) { + reply->writeInt32((int32_t)output); + reply->write(&config, sizeof(audio_config_t)); + reply->writeInt32(devices); + reply->writeInt32(latencyMs); + } return NO_ERROR; } break; case OPEN_DUPLICATE_OUTPUT: { @@ -1156,23 +1120,22 @@ status_t BnAudioFlinger::onTransact( case OPEN_INPUT: { CHECK_INTERFACE(IAudioFlinger, data, reply); audio_module_handle_t module = (audio_module_handle_t)data.readInt32(); - audio_devices_t devices = (audio_devices_t)data.readInt32(); - uint32_t samplingRate = data.readInt32(); - audio_format_t format = (audio_format_t) data.readInt32(); - audio_channel_mask_t channelMask = (audio_channel_mask_t)data.readInt32(); + audio_io_handle_t input = (audio_io_handle_t)data.readInt32(); + audio_config_t config; + data.read(&config, sizeof(audio_config_t)); + audio_devices_t device = (audio_devices_t)data.readInt32(); + String8 address(data.readString8()); + audio_source_t source = (audio_source_t)data.readInt32(); audio_input_flags_t flags = (audio_input_flags_t) data.readInt32(); - audio_io_handle_t input = openInput(module, - &devices, - &samplingRate, - &format, - &channelMask, - flags); - reply->writeInt32((int32_t) input); - reply->writeInt32(devices); - reply->writeInt32(samplingRate); - reply->writeInt32(format); - reply->writeInt32(channelMask); + status_t status = openInput(module, &input, &config, + &device, address, source, flags); + reply->writeInt32((int32_t) status); + if (status == NO_ERROR) { + reply->writeInt32((int32_t) input); + reply->write(&config, sizeof(audio_config_t)); + reply->writeInt32(device); + } return NO_ERROR; } break; case CLOSE_INPUT: { -- cgit v1.1 From edd4a76eb4747bd19ed122df46fa46b452c12a0d Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Mon, 28 Jul 2014 09:54:57 -0700 Subject: SampleTable: check integer overflow during table alloc Bug: 15328708 Bug: 15342615 Bug: 15342751 Change-Id: I6bb110a1eba46506799c73be8ff9a4f71c7e7053 --- media/libstagefright/SampleTable.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'media') diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index bad43f2..bdd6d56 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -330,6 +330,10 @@ status_t SampleTable::setTimeToSampleParams( } mTimeToSampleCount = U32_AT(&header[4]); + uint64_t allocSize = mTimeToSampleCount * 2 * sizeof(uint32_t); + if (allocSize > SIZE_MAX) { + return ERROR_OUT_OF_RANGE; + } mTimeToSample = new uint32_t[mTimeToSampleCount * 2]; size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2; @@ -372,6 +376,11 @@ status_t SampleTable::setCompositionTimeToSampleParams( } mNumCompositionTimeDeltaEntries = numEntries; + uint64_t allocSize = numEntries * 2 * sizeof(uint32_t); + if (allocSize > SIZE_MAX) { + return ERROR_OUT_OF_RANGE; + } + mCompositionTimeDeltaEntries = new uint32_t[2 * numEntries]; if (mDataSource->readAt( @@ -417,6 +426,11 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) ALOGV("Table of sync samples is empty or has only a single entry!"); } + uint64_t allocSize = mNumSyncSamples * sizeof(uint32_t); + if (allocSize > SIZE_MAX) { + return ERROR_OUT_OF_RANGE; + } + mSyncSamples = new uint32_t[mNumSyncSamples]; size_t size = mNumSyncSamples * sizeof(uint32_t); if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size) -- cgit v1.1 From 9bf32f06e8971c1d3eb4fc5edd74b69557f97212 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 30 Jul 2014 15:40:31 -0700 Subject: ATSParser: treat stream type 0x83 as TrueHD AC3 Bug: 16668055 Change-Id: I11fd3f795bbb50113e1a1e28e682edd76f11e146 --- media/libstagefright/MediaCodecList.cpp | 4 ++-- media/libstagefright/mpeg2ts/ATSParser.cpp | 8 ++------ media/libstagefright/mpeg2ts/ATSParser.h | 4 +++- 3 files changed, 7 insertions(+), 9 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index 8f54343..d021533 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -803,7 +803,7 @@ const char *MediaCodecList::getCodecName(size_t index) const { bool MediaCodecList::isEncoder(size_t index) const { if (index >= mCodecInfos.size()) { - return NULL; + return false; } const CodecInfo &info = mCodecInfos.itemAt(index); @@ -813,7 +813,7 @@ bool MediaCodecList::isEncoder(size_t index) const { bool MediaCodecList::codecHasQuirk( size_t index, const char *quirkName) const { if (index >= mCodecInfos.size()) { - return NULL; + return false; } const CodecInfo &info = mCodecInfos.itemAt(index); diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index 3d241e0..eda6387 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -503,11 +503,7 @@ ATSParser::Stream::Stream( ElementaryStreamQueue::MPEG4_VIDEO); break; - case STREAMTYPE_PCM_AUDIO: - mQueue = new ElementaryStreamQueue( - ElementaryStreamQueue::PCM_AUDIO); - break; - + case STREAMTYPE_LPCM_AC3: case STREAMTYPE_AC3: mQueue = new ElementaryStreamQueue( ElementaryStreamQueue::AC3); @@ -622,7 +618,7 @@ bool ATSParser::Stream::isAudio() const { case STREAMTYPE_MPEG1_AUDIO: case STREAMTYPE_MPEG2_AUDIO: case STREAMTYPE_MPEG2_AUDIO_ADTS: - case STREAMTYPE_PCM_AUDIO: + case STREAMTYPE_LPCM_AC3: case STREAMTYPE_AC3: return true; diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h index 86b025f..8986a22 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.h +++ b/media/libstagefright/mpeg2ts/ATSParser.h @@ -93,7 +93,9 @@ struct ATSParser : public RefBase { // From ATSC A/53 Part 3:2009, 6.7.1 STREAMTYPE_AC3 = 0x81, - STREAMTYPE_PCM_AUDIO = 0x83, + // Stream type 0x83 is non-standard, + // it could be LPCM or TrueHD AC3 + STREAMTYPE_LPCM_AC3 = 0x83, }; protected: -- cgit v1.1 From e9e63bcf6c36351f1129b0bdc5e93f17f0f9f0b4 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 30 Jul 2014 17:25:06 -0700 Subject: handle rotation in NuPlayer Bug: 16653284 Change-Id: I54165041da5a13498d627eee1b3ec59ef3c923b0 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 19 +++++++++++++-- media/libstagefright/ACodec.cpp | 29 +++++++++++++++++++++++ media/libstagefright/Utils.cpp | 5 ++++ 3 files changed, 51 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index d144af1..adc5f33 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -860,8 +860,23 @@ void NuPlayer::onMessageReceived(const sp &msg) { displayWidth, displayHeight); } - notifyListener( - MEDIA_SET_VIDEO_SIZE, displayWidth, displayHeight); + int32_t rotationDegrees; + if (!videoInputFormat->findInt32( + "rotation-degrees", &rotationDegrees)) { + rotationDegrees = 0; + } + + if (rotationDegrees == 90 || rotationDegrees == 270) { + notifyListener( + MEDIA_SET_VIDEO_SIZE, + displayHeight, + displayWidth); + } else { + notifyListener( + MEDIA_SET_VIDEO_SIZE, + displayWidth, + displayHeight); + } } } else if (what == Decoder::kWhatShutdownCompleted) { ALOGV("%s shutdown completed", audio ? "audio" : "video"); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 1b1d7a9..3fb174d 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -368,6 +368,7 @@ ACodec::ACodec() mExplicitShutdown(false), mEncoderDelay(0), mEncoderPadding(0), + mRotationDegrees(0), mChannelMaskPresent(false), mChannelMask(0), mDequeueCounter(0), @@ -591,6 +592,27 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( return err; } + if (mRotationDegrees != 0) { + uint32_t transform = 0; + switch (mRotationDegrees) { + case 0: transform = 0; break; + case 90: transform = HAL_TRANSFORM_ROT_90; break; + case 180: transform = HAL_TRANSFORM_ROT_180; break; + case 270: transform = HAL_TRANSFORM_ROT_270; break; + default: transform = 0; break; + } + + if (transform > 0) { + err = native_window_set_buffers_transform( + mNativeWindow.get(), transform); + if (err != 0) { + ALOGE("native_window_set_buffers_transform failed: %s (%d)", + strerror(-err), -err); + return err; + } + } + } + // Set up the native window. OMX_U32 usage = 0; err = mOMX->getGraphicBufferUsage(mNode, kPortIndexOutput, &usage); @@ -1232,6 +1254,13 @@ status_t ACodec::configureCodec( && push != 0) { mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown; } + + int32_t rotationDegrees; + if (msg->findInt32("rotation-degrees", &rotationDegrees)) { + mRotationDegrees = rotationDegrees; + } else { + mRotationDegrees = 0; + } } if (video) { diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 750bff0..587e264 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -142,6 +142,11 @@ status_t convertMetaDataToMessage( msg->setInt32("max-input-size", maxInputSize); } + int32_t rotationDegrees; + if (meta->findInt32(kKeyRotation, &rotationDegrees)) { + msg->setInt32("rotation-degrees", rotationDegrees); + } + uint32_t type; const void *data; size_t size; -- cgit v1.1 From 90b16fbdef406d95a6fb2f9395719dd7b7ca6adb Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 25 Jul 2014 07:53:14 -0700 Subject: stagefright: add ABuffer.CreateAsCopy Bug: 10706245 Change-Id: I8c4e96a2581a039e9e8237c3e09e2c22226da055 --- media/libstagefright/foundation/ABuffer.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'media') diff --git a/media/libstagefright/foundation/ABuffer.cpp b/media/libstagefright/foundation/ABuffer.cpp index 6173db4..c93c7e8 100644 --- a/media/libstagefright/foundation/ABuffer.cpp +++ b/media/libstagefright/foundation/ABuffer.cpp @@ -40,6 +40,14 @@ ABuffer::ABuffer(void *data, size_t capacity) mOwnsData(false) { } +// static +sp ABuffer::CreateAsCopy(const void *data, size_t capacity) +{ + sp res = new ABuffer(capacity); + memcpy(res->data(), data, capacity); + return res; +} + ABuffer::~ABuffer() { if (mOwnsData) { if (mData != NULL) { -- cgit v1.1 From 03c556ae1eb409ad088c49037e185946c54e1d25 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 25 Jul 2014 07:53:14 -0700 Subject: stagefright: add flexible YUV support Bug: 10706245 Change-Id: Icd246f22edfc67ed5240d59f5a5bde3e5f749465 --- media/libstagefright/ACodec.cpp | 104 ++++++++++++++++++++++++++++++++++++ media/libstagefright/MediaCodec.cpp | 12 +++++ 2 files changed, 116 insertions(+) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index b6cc742..1b1d7a9 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -2709,6 +2709,83 @@ void ACodec::processDeferredMessages() { } } +// static +void ACodec::describeDefaultColorFormat(DescribeColorFormatParams ¶ms) { + MediaImage &image = params.sMediaImage; + memset(&image, 0, sizeof(image)); + + image.mType = MediaImage::MEDIA_IMAGE_TYPE_UNKNOWN; + image.mNumPlanes = 0; + + const OMX_COLOR_FORMATTYPE fmt = params.eColorFormat; + // we need stride and slice-height to be non-zero + if (params.nStride == 0 || params.nSliceHeight == 0) { + ALOGW("cannot describe color format 0x%x = %d with stride=%u and sliceHeight=%u", + fmt, fmt, params.nStride, params.nSliceHeight); + return; + } + + image.mWidth = params.nFrameWidth; + image.mHeight = params.nFrameHeight; + + // only supporting YUV420 + if (fmt != OMX_COLOR_FormatYUV420Planar && + fmt != OMX_COLOR_FormatYUV420PackedPlanar && + fmt != OMX_COLOR_FormatYUV420SemiPlanar && + fmt != OMX_COLOR_FormatYUV420PackedSemiPlanar) { + ALOGW("do not know color format 0x%x = %d", fmt, fmt); + return; + } + + // set-up YUV format + image.mType = MediaImage::MEDIA_IMAGE_TYPE_YUV; + image.mNumPlanes = 3; + image.mBitDepth = 8; + image.mPlane[image.Y].mOffset = 0; + image.mPlane[image.Y].mColInc = 1; + image.mPlane[image.Y].mRowInc = params.nStride; + image.mPlane[image.Y].mHorizSubsampling = 1; + image.mPlane[image.Y].mVertSubsampling = 1; + + switch (fmt) { + case OMX_COLOR_FormatYUV420Planar: // used for YV12 + case OMX_COLOR_FormatYUV420PackedPlanar: + image.mPlane[image.U].mOffset = params.nStride * params.nSliceHeight; + image.mPlane[image.U].mColInc = 1; + image.mPlane[image.U].mRowInc = params.nStride / 2; + image.mPlane[image.U].mHorizSubsampling = 2; + image.mPlane[image.U].mVertSubsampling = 2; + + image.mPlane[image.V].mOffset = image.mPlane[image.U].mOffset + + (params.nStride * params.nSliceHeight / 4); + image.mPlane[image.V].mColInc = 1; + image.mPlane[image.V].mRowInc = params.nStride / 2; + image.mPlane[image.V].mHorizSubsampling = 2; + image.mPlane[image.V].mVertSubsampling = 2; + break; + + case OMX_COLOR_FormatYUV420SemiPlanar: + // FIXME: NV21 for sw-encoder, NV12 for decoder and hw-encoder + case OMX_COLOR_FormatYUV420PackedSemiPlanar: + // NV12 + image.mPlane[image.U].mOffset = params.nStride * params.nSliceHeight; + image.mPlane[image.U].mColInc = 2; + image.mPlane[image.U].mRowInc = params.nStride; + image.mPlane[image.U].mHorizSubsampling = 2; + image.mPlane[image.U].mVertSubsampling = 2; + + image.mPlane[image.V].mOffset = image.mPlane[image.U].mOffset + 1; + image.mPlane[image.V].mColInc = 2; + image.mPlane[image.V].mRowInc = params.nStride; + image.mPlane[image.V].mHorizSubsampling = 2; + image.mPlane[image.V].mVertSubsampling = 2; + break; + + default: + TRESPASS(); + } +} + status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { // TODO: catch errors an return them instead of using CHECK OMX_PARAM_PORTDEFINITIONTYPE def; @@ -2736,6 +2813,33 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { notify->setInt32("slice-height", videoDef->nSliceHeight); notify->setInt32("color-format", videoDef->eColorFormat); + + DescribeColorFormatParams describeParams; + InitOMXParams(&describeParams); + describeParams.eColorFormat = videoDef->eColorFormat; + describeParams.nFrameWidth = videoDef->nFrameWidth; + describeParams.nFrameHeight = videoDef->nFrameHeight; + describeParams.nStride = videoDef->nStride; + describeParams.nSliceHeight = videoDef->nSliceHeight; + + OMX_INDEXTYPE describeColorFormatIndex; + if (mOMX->getExtensionIndex( + mNode, "OMX.google.android.index.describeColorFormat", + &describeColorFormatIndex) || + mOMX->getParameter( + mNode, describeColorFormatIndex, + &describeParams, sizeof(describeParams))) { + describeDefaultColorFormat(describeParams); + } + + if (describeParams.sMediaImage.mType != MediaImage::MEDIA_IMAGE_TYPE_UNKNOWN) { + notify->setBuffer( + "image-data", + ABuffer::CreateAsCopy( + &describeParams.sMediaImage, + sizeof(describeParams.sMediaImage))); + } + OMX_CONFIG_RECTTYPE rect; InitOMXParams(&rect); rect.nPortIndex = kPortIndexOutput; diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 15e062e..e944766 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -1948,6 +1948,18 @@ ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) { Mutex::Autolock al(mBufferLock); info->mFormat = portIndex == kPortIndexInput ? mInputFormat : mOutputFormat; info->mOwnedByClient = true; + + // set image-data + if (info->mFormat != NULL) { + sp imageData; + if (info->mFormat->findBuffer("image-data", &imageData)) { + info->mData->meta()->setBuffer("image-data", imageData); + } + int32_t left, top, right, bottom; + if (info->mFormat->findRect("crop", &left, &top, &right, &bottom)) { + info->mData->meta()->setRect("crop-rect", left, top, right, bottom); + } + } } return index; -- cgit v1.1 From f5bdd770d509373cc4174a55d0b81b223ecc4d81 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Sun, 27 Jul 2014 21:22:11 -0700 Subject: mediaplayer: make nuplayer the default player Bug: 11784824 Change-Id: I60d215d0348adcd589da5bd479d5921dcf076ee4 --- media/libmediaplayerservice/MediaPlayerFactory.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp index e9c5e8e..dacb144 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.cpp +++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp @@ -62,18 +62,18 @@ status_t MediaPlayerFactory::registerFactory_l(IFactory* factory, player_type MediaPlayerFactory::getDefaultPlayerType() { char value[PROPERTY_VALUE_MAX]; - if (property_get("media.stagefright.use-nuplayer", value, NULL) + if (property_get("media.stagefright.use-awesome", value, NULL) && (!strcmp("1", value) || !strcasecmp("true", value))) { - return NU_PLAYER; + return STAGEFRIGHT_PLAYER; } // TODO: remove this EXPERIMENTAL developer settings property - if (property_get("persist.sys.media.use-nuplayer", value, NULL) + if (property_get("persist.sys.media.use-awesome", value, NULL) && !strcasecmp("true", value)) { - return NU_PLAYER; + return STAGEFRIGHT_PLAYER; } - return STAGEFRIGHT_PLAYER; + return NU_PLAYER; } status_t MediaPlayerFactory::registerFactory(IFactory* factory, -- cgit v1.1 From bace25b0fbcd5101d2db288b0c70c4a239f0e815 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 25 Jul 2014 14:14:34 -0700 Subject: GenericSource: start/stop tracks correctly on selection Change-Id: I10343151f930a4ab778a6d2574ab5165af2013ba --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 4c6a59c..0b09f58 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -137,7 +137,6 @@ void NuPlayer::GenericSource::initFromDataSource( } if (track != NULL) { - CHECK_EQ(track->start(), (status_t)OK); mSources.push(track); int64_t durationUs; if (meta->findInt64(kKeyDuration, &durationUs)) { @@ -184,6 +183,7 @@ void NuPlayer::GenericSource::start() { ALOGI("start"); if (mAudioTrack.mSource != NULL) { + CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); mAudioTrack.mPackets = new AnotherPacketSource(mAudioTrack.mSource->getFormat()); @@ -191,6 +191,7 @@ void NuPlayer::GenericSource::start() { } if (mVideoTrack.mSource != NULL) { + CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); mVideoTrack.mPackets = new AnotherPacketSource(mVideoTrack.mSource->getFormat()); @@ -255,7 +256,11 @@ void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { } + if (track->mSource != NULL) { + track->mSource->stop(); + } track->mSource = source; + track->mSource->start(); track->mIndex = trackIndex; status_t avail; @@ -529,6 +534,7 @@ status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { if (track == NULL) { return INVALID_OPERATION; } + track->mSource->stop(); track->mSource = NULL; track->mPackets->clear(); return OK; @@ -545,7 +551,11 @@ status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { return OK; } track->mIndex = trackIndex; + if (track->mSource != NULL) { + track->mSource->stop(); + } track->mSource = mSources.itemAt(trackIndex); + track->mSource->start(); if (track->mPackets == NULL) { track->mPackets = new AnotherPacketSource(track->mSource->getFormat()); } else { -- cgit v1.1 From de3f8392fbf380ba6f09d009b00d7172477389a2 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Sun, 27 Jul 2014 18:38:22 -0700 Subject: rename AudioSystem::newAudioSessionId() Rename AudioSystem::newAudioSessionId() to AudioSystem::newAudioUniqueId() as it can be used also for I/O handles. Bug: 12378680. Change-Id: I611ea3b5eb57a4b0774437f477ee87dc4ccc2cc2 --- media/libmedia/AudioRecord.cpp | 2 +- media/libmedia/AudioSystem.cpp | 6 +++--- media/libmedia/IAudioFlinger.cpp | 6 +++--- media/libmedia/mediaplayer.cpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 80c8c5e..299a77c 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -214,7 +214,7 @@ status_t AudioRecord::set( // mNotificationFramesAct is initialized in openRecord_l if (sessionId == AUDIO_SESSION_ALLOCATE) { - mSessionId = AudioSystem::newAudioSessionId(); + mSessionId = AudioSystem::newAudioUniqueId(); } else { mSessionId = sessionId; } diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index fd5824b..0d61885 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -427,11 +427,11 @@ uint32_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) return result; } -int AudioSystem::newAudioSessionId() +audio_unique_id_t AudioSystem::newAudioUniqueId() { const sp& af = AudioSystem::get_audio_flinger(); - if (af == 0) return AUDIO_SESSION_ALLOCATE; - return af->newAudioSessionId(); + if (af == 0) return AUDIO_UNIQUE_ID_ALLOCATE; + return af->newAudioUniqueId(); } void AudioSystem::acquireAudioSessionId(int audioSession, pid_t pid) diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 0f4e632..5331fce 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -604,12 +604,12 @@ public: return (uint32_t) reply.readInt32(); } - virtual int newAudioSessionId() + virtual audio_unique_id_t newAudioUniqueId() { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); status_t status = remote()->transact(NEW_AUDIO_SESSION_ID, data, &reply); - int id = AUDIO_SESSION_ALLOCATE; + audio_unique_id_t id = AUDIO_SESSION_ALLOCATE; if (status == NO_ERROR) { id = reply.readInt32(); } @@ -1176,7 +1176,7 @@ status_t BnAudioFlinger::onTransact( } break; case NEW_AUDIO_SESSION_ID: { CHECK_INTERFACE(IAudioFlinger, data, reply); - reply->writeInt32(newAudioSessionId()); + reply->writeInt32(newAudioUniqueId()); return NO_ERROR; } break; case ACQUIRE_AUDIO_SESSION_ID: { diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 2b7ea97..6cd377a 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -59,7 +59,7 @@ MediaPlayer::MediaPlayer() mLeftVolume = mRightVolume = 1.0; mVideoWidth = mVideoHeight = 0; mLockThreadId = 0; - mAudioSessionId = AudioSystem::newAudioSessionId(); + mAudioSessionId = AudioSystem::newAudioUniqueId(); AudioSystem::acquireAudioSessionId(mAudioSessionId, -1); mSendLevel = 0; mRetransmitEndpointValid = false; -- cgit v1.1 From 4dc680607181e6a76f4e91a39366c4f5dfb7b03e Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Mon, 28 Jul 2014 17:26:49 -0700 Subject: audio policy: pass session ID to capture activity methods Indicate the audio session ID when calling getInput(), startInput(), stopInput(), releaseInput(). Bug: 12378680. Change-Id: I763793752f93e2f4e1445a5ab217c895af011038 --- media/libmedia/AudioRecord.cpp | 2 +- media/libmedia/AudioSystem.cpp | 15 +++++++++------ media/libmedia/IAudioPolicyService.cpp | 21 +++++++++++++++------ 3 files changed, 25 insertions(+), 13 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 299a77c..9e7ba88 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -572,7 +572,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) } release: - AudioSystem::releaseInput(input); + AudioSystem::releaseInput(input, (audio_session_t)mSessionId); if (status == NO_ERROR) { status = NO_INIT; } diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 0d61885..365a594 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -696,25 +696,28 @@ audio_io_handle_t AudioSystem::getInput(audio_source_t inputSource, return aps->getInput(inputSource, samplingRate, format, channelMask, sessionId, flags); } -status_t AudioSystem::startInput(audio_io_handle_t input) +status_t AudioSystem::startInput(audio_io_handle_t input, + audio_session_t session) { const sp& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; - return aps->startInput(input); + return aps->startInput(input, session); } -status_t AudioSystem::stopInput(audio_io_handle_t input) +status_t AudioSystem::stopInput(audio_io_handle_t input, + audio_session_t session) { const sp& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; - return aps->stopInput(input); + return aps->stopInput(input, session); } -void AudioSystem::releaseInput(audio_io_handle_t input) +void AudioSystem::releaseInput(audio_io_handle_t input, + audio_session_t session) { const sp& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return; - aps->releaseInput(input); + aps->releaseInput(input, session); } status_t AudioSystem::initStreamVolume(audio_stream_type_t stream, diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 40dfb58..1593b17 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -240,29 +240,35 @@ public: return static_cast (reply.readInt32()); } - virtual status_t startInput(audio_io_handle_t input) + virtual status_t startInput(audio_io_handle_t input, + audio_session_t session) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(input); + data.writeInt32(session); remote()->transact(START_INPUT, data, &reply); return static_cast (reply.readInt32()); } - virtual status_t stopInput(audio_io_handle_t input) + virtual status_t stopInput(audio_io_handle_t input, + audio_session_t session) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(input); + data.writeInt32(session); remote()->transact(STOP_INPUT, data, &reply); return static_cast (reply.readInt32()); } - virtual void releaseInput(audio_io_handle_t input) + virtual void releaseInput(audio_io_handle_t input, + audio_session_t session) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(input); + data.writeInt32(session); remote()->transact(RELEASE_INPUT, data, &reply); } @@ -723,21 +729,24 @@ status_t BnAudioPolicyService::onTransact( case START_INPUT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_io_handle_t input = static_cast (data.readInt32()); - reply->writeInt32(static_cast (startInput(input))); + audio_session_t session = static_cast (data.readInt32()); + reply->writeInt32(static_cast (startInput(input, session))); return NO_ERROR; } break; case STOP_INPUT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_io_handle_t input = static_cast (data.readInt32()); - reply->writeInt32(static_cast (stopInput(input))); + audio_session_t session = static_cast (data.readInt32()); + reply->writeInt32(static_cast (stopInput(input, session))); return NO_ERROR; } break; case RELEASE_INPUT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_io_handle_t input = static_cast (data.readInt32()); - releaseInput(input); + audio_session_t session = static_cast (data.readInt32()); + releaseInput(input, session); return NO_ERROR; } break; -- cgit v1.1 From cb48eacb6f8857c7857bb28d6a13d4a0d417f2bd Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 30 Jul 2014 13:40:49 -0700 Subject: Revert GenericSource track selection changes This reverts commit bace25b0fbcd5101d2db288b0c70c4a239f0e815. This reverts commit eb1735e343a93830df259ae8882160bb0d79dcb5. This reverts commit 05312bc7478feec11d9ae88e951c0857a7a3f28d. Bug: 16660839 --- .../nuplayer/GenericSource.cpp | 468 +++------------------ .../libmediaplayerservice/nuplayer/GenericSource.h | 36 +- .../libstagefright/mpeg2ts/AnotherPacketSource.cpp | 12 +- media/libstagefright/mpeg2ts/AnotherPacketSource.h | 1 - 4 files changed, 65 insertions(+), 452 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 0b09f58..d75408d 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -41,8 +41,6 @@ NuPlayer::GenericSource::GenericSource( bool uidValid, uid_t uid) : Source(notify), - mFetchSubtitleDataGeneration(0), - mFetchTimedTextDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false), mIsWidevine(isWidevine), @@ -61,8 +59,6 @@ NuPlayer::GenericSource::GenericSource( const sp ¬ify, int fd, int64_t offset, int64_t length) : Source(notify), - mFetchSubtitleDataGeneration(0), - mFetchTimedTextDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false) { DataSource::RegisterDefaultSniffers(); @@ -184,18 +180,20 @@ void NuPlayer::GenericSource::start() { if (mAudioTrack.mSource != NULL) { CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); + mAudioTrack.mPackets = new AnotherPacketSource(mAudioTrack.mSource->getFormat()); - readBuffer(MEDIA_TRACK_TYPE_AUDIO); + readBuffer(true /* audio */); } if (mVideoTrack.mSource != NULL) { CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); + mVideoTrack.mPackets = new AnotherPacketSource(mVideoTrack.mSource->getFormat()); - readBuffer(MEDIA_TRACK_TYPE_VIDEO); + readBuffer(false /* audio */); } } @@ -203,158 +201,6 @@ status_t NuPlayer::GenericSource::feedMoreTSData() { return OK; } -void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { - switch (msg->what()) { - case kWhatFetchSubtitleData: - { - fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, - mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); - break; - } - - case kWhatFetchTimedTextData: - { - fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, - mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); - break; - } - - case kWhatSendSubtitleData: - { - sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, - mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); - break; - } - - case kWhatSendTimedTextData: - { - sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, - mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); - break; - } - - case kWhatChangeAVSource: - { - int32_t trackIndex; - CHECK(msg->findInt32("trackIndex", &trackIndex)); - const sp source = mSources.itemAt(trackIndex); - - Track* track; - const char *mime; - media_track_type trackType, counterpartType; - sp meta = source->getFormat(); - meta->findCString(kKeyMIMEType, &mime); - if (!strncasecmp(mime, "audio/", 6)) { - track = &mAudioTrack; - trackType = MEDIA_TRACK_TYPE_AUDIO; - counterpartType = MEDIA_TRACK_TYPE_VIDEO;; - } else { - CHECK(!strncasecmp(mime, "video/", 6)); - track = &mVideoTrack; - trackType = MEDIA_TRACK_TYPE_VIDEO; - counterpartType = MEDIA_TRACK_TYPE_AUDIO;; - } - - - if (track->mSource != NULL) { - track->mSource->stop(); - } - track->mSource = source; - track->mSource->start(); - track->mIndex = trackIndex; - - status_t avail; - if (!track->mPackets->hasBufferAvailable(&avail)) { - // sync from other source - TRESPASS(); - break; - } - - int64_t timeUs, actualTimeUs; - const bool formatChange = true; - sp latestMeta = track->mPackets->getLatestMeta(); - CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs)); - readBuffer(trackType, timeUs, &actualTimeUs, formatChange); - readBuffer(counterpartType, -1, NULL, formatChange); - ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs); - - break; - } - - default: - Source::onMessageReceived(msg); - break; - } -} - -void NuPlayer::GenericSource::fetchTextData( - uint32_t sendWhat, - media_track_type type, - int32_t curGen, - sp packets, - sp msg) { - int32_t msgGeneration; - CHECK(msg->findInt32("generation", &msgGeneration)); - if (msgGeneration != curGen) { - // stale - return; - } - - int32_t avail; - if (packets->hasBufferAvailable(&avail)) { - return; - } - - int64_t timeUs; - CHECK(msg->findInt64("timeUs", &timeUs)); - - int64_t subTimeUs; - readBuffer(type, timeUs, &subTimeUs); - - int64_t delayUs = subTimeUs - timeUs; - if (msg->what() == kWhatFetchSubtitleData) { - const int64_t oneSecUs = 1000000ll; - delayUs -= oneSecUs; - } - sp msg2 = new AMessage(sendWhat, id()); - msg2->setInt32("generation", msgGeneration); - msg2->post(delayUs < 0 ? 0 : delayUs); -} - -void NuPlayer::GenericSource::sendTextData( - uint32_t what, - media_track_type type, - int32_t curGen, - sp packets, - sp msg) { - int32_t msgGeneration; - CHECK(msg->findInt32("generation", &msgGeneration)); - if (msgGeneration != curGen) { - // stale - return; - } - - int64_t subTimeUs; - if (packets->nextBufferTime(&subTimeUs) != OK) { - return; - } - - int64_t nextSubTimeUs; - readBuffer(type, -1, &nextSubTimeUs); - - sp buffer; - status_t dequeueStatus = packets->dequeueAccessUnit(&buffer); - if (dequeueStatus == OK) { - sp notify = dupNotify(); - notify->setInt32("what", what); - notify->setBuffer("buffer", buffer); - notify->post(); - - const int64_t delayUs = nextSubTimeUs - subTimeUs; - msg->post(delayUs < 0 ? 0 : delayUs); - } -} - sp NuPlayer::GenericSource::getFormatMeta(bool audio) { sp source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; @@ -375,7 +221,7 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( if (mIsWidevine && !audio) { // try to read a buffer as we may not have been able to the last time - readBuffer(MEDIA_TRACK_TYPE_AUDIO, -1ll); + readBuffer(audio, -1ll); } status_t finalResult; @@ -385,52 +231,7 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( status_t result = track->mPackets->dequeueAccessUnit(accessUnit); - if (!track->mPackets->hasBufferAvailable(&finalResult)) { - readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll); - } - - if (mSubtitleTrack.mSource == NULL && mTimedTextTrack.mSource == NULL) { - return result; - } - - if (mSubtitleTrack.mSource != NULL) { - CHECK(mSubtitleTrack.mPackets != NULL); - } - if (mTimedTextTrack.mSource != NULL) { - CHECK(mTimedTextTrack.mPackets != NULL); - } - - if (result != OK) { - if (mSubtitleTrack.mSource != NULL) { - mSubtitleTrack.mPackets->clear(); - mFetchSubtitleDataGeneration++; - } - if (mTimedTextTrack.mSource != NULL) { - mTimedTextTrack.mPackets->clear(); - mFetchTimedTextDataGeneration++; - } - return result; - } - - int64_t timeUs; - status_t eosResult; // ignored - CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); - - if (mSubtitleTrack.mSource != NULL - && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { - sp msg = new AMessage(kWhatFetchSubtitleData, id()); - msg->setInt64("timeUs", timeUs); - msg->setInt32("generation", mFetchSubtitleDataGeneration); - msg->post(); - } - - if (mTimedTextTrack.mSource != NULL - && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { - sp msg = new AMessage(kWhatFetchTimedTextData, id()); - msg->setInt64("timeUs", timeUs); - msg->setInt32("generation", mFetchTimedTextDataGeneration); - msg->post(); - } + readBuffer(audio, -1ll); return result; } @@ -490,207 +291,25 @@ sp NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { return format; } -ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { - const Track *track = NULL; - switch (type) { - case MEDIA_TRACK_TYPE_VIDEO: - track = &mVideoTrack; - break; - case MEDIA_TRACK_TYPE_AUDIO: - track = &mAudioTrack; - break; - case MEDIA_TRACK_TYPE_TIMEDTEXT: - track = &mTimedTextTrack; - break; - case MEDIA_TRACK_TYPE_SUBTITLE: - track = &mSubtitleTrack; - break; - default: - break; - } - - if (track != NULL && track->mSource != NULL) { - return track->mIndex; - } - - return -1; -} - -status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { - ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); - if (trackIndex >= mSources.size()) { - return BAD_INDEX; - } - - if (!select) { - Track* track = NULL; - if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) { - track = &mSubtitleTrack; - mFetchSubtitleDataGeneration++; - } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) { - track = &mTimedTextTrack; - mFetchTimedTextDataGeneration++; - } - if (track == NULL) { - return INVALID_OPERATION; - } - track->mSource->stop(); - track->mSource = NULL; - track->mPackets->clear(); - return OK; - } - - const sp source = mSources.itemAt(trackIndex); - sp meta = source->getFormat(); - const char *mime; - CHECK(meta->findCString(kKeyMIMEType, &mime)); - if (!strncasecmp(mime, "text/", 5)) { - bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP); - Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack; - if (track->mSource != NULL && track->mIndex == trackIndex) { - return OK; - } - track->mIndex = trackIndex; - if (track->mSource != NULL) { - track->mSource->stop(); - } - track->mSource = mSources.itemAt(trackIndex); - track->mSource->start(); - if (track->mPackets == NULL) { - track->mPackets = new AnotherPacketSource(track->mSource->getFormat()); - } else { - track->mPackets->clear(); - track->mPackets->setFormat(track->mSource->getFormat()); - - } - - if (isSubtitle) { - mFetchSubtitleDataGeneration++; - } else { - mFetchTimedTextDataGeneration++; - } - - return OK; - } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { - bool audio = !strncasecmp(mime, "audio/", 6); - Track *track = audio ? &mAudioTrack : &mVideoTrack; - if (track->mSource != NULL && track->mIndex == trackIndex) { - return OK; - } - - sp msg = new AMessage(kWhatChangeAVSource, id()); - msg->setInt32("trackIndex", trackIndex); - msg->post(); - return OK; - } - - return INVALID_OPERATION; -} - status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { if (mVideoTrack.mSource != NULL) { int64_t actualTimeUs; - readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs); + readBuffer(false /* audio */, seekTimeUs, &actualTimeUs); seekTimeUs = actualTimeUs; } if (mAudioTrack.mSource != NULL) { - readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs); + readBuffer(true /* audio */, seekTimeUs); } return OK; } -sp NuPlayer::GenericSource::mediaBufferToABuffer( - MediaBuffer* mb, - media_track_type trackType, - int64_t *actualTimeUs) { - bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO; - size_t outLength = mb->range_length(); - - if (audio && mAudioIsVorbis) { - outLength += sizeof(int32_t); - } - - sp ab; - if (mIsWidevine && !audio) { - // data is already provided in the buffer - ab = new ABuffer(NULL, mb->range_length()); - ab->meta()->setPointer("mediaBuffer", mb); - mb->add_ref(); - } else { - ab = new ABuffer(outLength); - memcpy(ab->data(), - (const uint8_t *)mb->data() + mb->range_offset(), - mb->range_length()); - } - - if (audio && mAudioIsVorbis) { - int32_t numPageSamples; - if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) { - numPageSamples = -1; - } - - uint8_t* abEnd = ab->data() + mb->range_length(); - memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); - } - - sp meta = ab->meta(); - - int64_t timeUs; - CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); - meta->setInt64("timeUs", timeUs); - - if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { - const char *mime; - CHECK(mTimedTextTrack.mSource != NULL - && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime)); - meta->setString("mime", mime); - } - - int64_t durationUs; - if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { - meta->setInt64("durationUs", durationUs); - } - - if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { - meta->setInt32("trackIndex", mSubtitleTrack.mIndex); - } - - if (actualTimeUs) { - *actualTimeUs = timeUs; - } - - mb->release(); - mb = NULL; - - return ab; -} - void NuPlayer::GenericSource::readBuffer( - media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) { - Track *track; - switch (trackType) { - case MEDIA_TRACK_TYPE_VIDEO: - track = &mVideoTrack; - break; - case MEDIA_TRACK_TYPE_AUDIO: - track = &mAudioTrack; - break; - case MEDIA_TRACK_TYPE_SUBTITLE: - track = &mSubtitleTrack; - break; - case MEDIA_TRACK_TYPE_TIMEDTEXT: - track = &mTimedTextTrack; - break; - default: - TRESPASS(); - } - - if (track->mSource == NULL) { - return; - } + bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) { + Track *track = audio ? &mAudioTrack : &mVideoTrack; + CHECK(track->mSource != NULL); if (actualTimeUs) { *actualTimeUs = seekTimeUs; @@ -701,11 +320,11 @@ void NuPlayer::GenericSource::readBuffer( bool seeking = false; if (seekTimeUs >= 0) { - options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); + options.setSeekTo(seekTimeUs); seeking = true; } - if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) { + if (mIsWidevine && !audio) { options.setNonBlocking(); } @@ -716,21 +335,56 @@ void NuPlayer::GenericSource::readBuffer( options.clearSeekTo(); if (err == OK) { - // formatChange && seeking: track whose source is changed during selection - // formatChange && !seeking: track whose source is not changed during selection - // !formatChange: normal seek - if ((seeking || formatChange) - && (trackType == MEDIA_TRACK_TYPE_AUDIO - || trackType == MEDIA_TRACK_TYPE_VIDEO)) { - ATSParser::DiscontinuityType type = formatChange - ? (seeking - ? ATSParser::DISCONTINUITY_FORMATCHANGE - : ATSParser::DISCONTINUITY_NONE) - : ATSParser::DISCONTINUITY_SEEK; - track->mPackets->queueDiscontinuity( type, NULL, true /* discard */); + size_t outLength = mbuf->range_length(); + + if (audio && mAudioIsVorbis) { + outLength += sizeof(int32_t); + } + + sp buffer; + if (mIsWidevine && !audio) { + // data is already provided in the buffer + buffer = new ABuffer(NULL, mbuf->range_length()); + buffer->meta()->setPointer("mediaBuffer", mbuf); + mbuf->add_ref(); + } else { + buffer = new ABuffer(outLength); + memcpy(buffer->data(), + (const uint8_t *)mbuf->data() + mbuf->range_offset(), + mbuf->range_length()); + } + + if (audio && mAudioIsVorbis) { + int32_t numPageSamples; + if (!mbuf->meta_data()->findInt32( + kKeyValidSamples, &numPageSamples)) { + numPageSamples = -1; + } + + memcpy(buffer->data() + mbuf->range_length(), + &numPageSamples, + sizeof(numPageSamples)); + } + + int64_t timeUs; + CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); + + buffer->meta()->setInt64("timeUs", timeUs); + + if (actualTimeUs) { + *actualTimeUs = timeUs; + } + + mbuf->release(); + mbuf = NULL; + + if (seeking) { + track->mPackets->queueDiscontinuity( + ATSParser::DISCONTINUITY_SEEK, + NULL, + true /* discard */); } - sp buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs); track->mPackets->queueAccessUnit(buffer); break; } else if (err == WOULD_BLOCK) { diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 3c5f55c..8e0209d 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -23,15 +23,12 @@ #include "ATSParser.h" -#include - namespace android { struct AnotherPacketSource; struct ARTSPController; struct DataSource; struct MediaSource; -class MediaBuffer; struct NuPlayer::GenericSource : public NuPlayer::Source { GenericSource( @@ -58,8 +55,6 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual status_t getDuration(int64_t *durationUs); virtual size_t getTrackCount() const; virtual sp getTrackInfo(size_t trackIndex) const; - virtual ssize_t getSelectedTrack(media_track_type type) const; - virtual status_t selectTrack(size_t trackIndex, bool select); virtual status_t seekTo(int64_t seekTimeUs); virtual status_t setBuffers(bool audio, Vector &buffers); @@ -67,19 +62,9 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { protected: virtual ~GenericSource(); - virtual void onMessageReceived(const sp &msg); - virtual sp getFormatMeta(bool audio); private: - enum { - kWhatFetchSubtitleData, - kWhatFetchTimedTextData, - kWhatSendSubtitleData, - kWhatSendTimedTextData, - kWhatChangeAVSource, - }; - Vector > mSources; struct Track { @@ -90,11 +75,7 @@ private: Track mAudioTrack; Track mVideoTrack; - Track mSubtitleTrack; - Track mTimedTextTrack; - int32_t mFetchSubtitleDataGeneration; - int32_t mFetchTimedTextDataGeneration; int64_t mDurationUs; bool mAudioIsVorbis; bool mIsWidevine; @@ -103,22 +84,9 @@ private: void initFromDataSource(const sp &dataSource); - void fetchTextData( - uint32_t what, media_track_type type, - int32_t curGen, sp packets, sp msg); - - void sendTextData( - uint32_t what, media_track_type type, - int32_t curGen, sp packets, sp msg); - - sp mediaBufferToABuffer( - MediaBuffer *mbuf, - media_track_type trackType, - int64_t *actualTimeUs = NULL); - void readBuffer( - media_track_type trackType, - int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL, bool formatChange = false); + bool audio, + int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL); DISALLOW_EVIL_CONSTRUCTORS(GenericSource); }; diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index 72c9dae..a0319ab 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -34,7 +34,6 @@ const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs AnotherPacketSource::AnotherPacketSource(const sp &meta) : mIsAudio(false), - mIsVideo(false), mFormat(NULL), mLastQueuedTimeUs(0), mEOSResult(OK), @@ -46,7 +45,6 @@ void AnotherPacketSource::setFormat(const sp &meta) { CHECK(mFormat == NULL); mIsAudio = false; - mIsVideo = false; if (meta == NULL) { return; @@ -58,10 +56,8 @@ void AnotherPacketSource::setFormat(const sp &meta) { if (!strncasecmp("audio/", mime, 6)) { mIsAudio = true; - } else if (!strncasecmp("video/", mime, 6)) { - mIsVideo = true; } else { - CHECK(!strncasecmp("text/", mime, 5)); + CHECK(!strncasecmp("video/", mime, 6)); } } @@ -179,11 +175,7 @@ bool AnotherPacketSource::wasFormatChange( return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0; } - if (mIsVideo) { - return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0; - } - - return false; + return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0; } void AnotherPacketSource::queueAccessUnit(const sp &buffer) { diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h index f38f9dc..06c49bd 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h @@ -74,7 +74,6 @@ private: Condition mCondition; bool mIsAudio; - bool mIsVideo; sp mFormat; int64_t mLastQueuedTimeUs; List > mBuffers; -- cgit v1.1 From 0e8cfc36044ba97545e7c9e129b0b3e98eec5089 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 30 Jul 2014 18:54:08 -0700 Subject: stagefright: MediaCodec async operations. In async mode: - codec must be restarted after flush - dequeueIn/OutputBuffers fail - getIn/OutputBuffers fail Bug: 11990118 Change-Id: If2d6a76ab499ee9ed4a11486fb537acbc52e66f6 --- media/libstagefright/MediaCodec.cpp | 50 ++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 17 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index e944766..7c02959 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -550,6 +550,10 @@ status_t MediaCodec::getInputBuffer(size_t index, sp *buffer) { return getBufferAndFormat(kPortIndexInput, index, buffer, &format); } +bool MediaCodec::isExecuting() const { + return mState == STARTED || mState == FLUSHED; +} + status_t MediaCodec::getBufferAndFormat( size_t portIndex, size_t index, sp *buffer, sp *format) { @@ -557,7 +561,7 @@ status_t MediaCodec::getBufferAndFormat( buffer->clear(); format->clear(); - if (mState != STARTED) { + if (!isExecuting()) { return INVALID_OPERATION; } @@ -615,7 +619,7 @@ void MediaCodec::cancelPendingDequeueOperations() { } bool MediaCodec::handleDequeueInputBuffer(uint32_t replyID, bool newRequest) { - if (mState != STARTED + if (!isExecuting() || (mFlags & kFlagIsAsync) || (mFlags & kFlagStickyError) || (newRequest && (mFlags & kFlagDequeueInputPending))) { PostReplyWithError(replyID, INVALID_OPERATION); @@ -639,7 +643,7 @@ bool MediaCodec::handleDequeueInputBuffer(uint32_t replyID, bool newRequest) { bool MediaCodec::handleDequeueOutputBuffer(uint32_t replyID, bool newRequest) { sp response = new AMessage; - if (mState != STARTED + if (!isExecuting() || (mFlags & kFlagIsAsync) || (mFlags & kFlagStickyError) || (newRequest && (mFlags & kFlagDequeueOutputPending))) { response->setInt32("err", INVALID_OPERATION); @@ -760,10 +764,12 @@ void MediaCodec::onMessageReceived(const sp &msg) { case FLUSHING: { - setState(STARTED); + setState( + (mFlags & kFlagIsAsync) ? FLUSHED : STARTED); break; } + case FLUSHED: case STARTED: { sendErrorReponse = false; @@ -1105,9 +1111,13 @@ void MediaCodec::onMessageReceived(const sp &msg) { case CodecBase::kWhatFlushCompleted: { CHECK_EQ(mState, FLUSHING); - setState(STARTED); - mCodec->signalResume(); + if (mFlags & kFlagIsAsync) { + setState(FLUSHED); + } else { + setState(STARTED); + mCodec->signalResume(); + } (new AMessage)->postReply(mReplyID); break; @@ -1162,8 +1172,8 @@ void MediaCodec::onMessageReceived(const sp &msg) { if (mState == UNINITIALIZED || mState == INITIALIZING - || mState == STARTED) { - // callback can't be set after codec is started, + || isExecuting()) { + // callback can't be set after codec is executing, // or before it's initialized (as the callback // will be cleared when it goes to INITIALIZED) PostReplyWithError(replyID, INVALID_OPERATION); @@ -1265,7 +1275,10 @@ void MediaCodec::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (mState != CONFIGURED) { + if (mState == FLUSHED) { + mCodec->signalResume(); + PostReplyWithError(replyID, OK); + } else if (mState != CONFIGURED) { PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1287,7 +1300,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->senderAwaitsResponse(&replyID)); if (mState != INITIALIZED - && mState != CONFIGURED && mState != STARTED) { + && mState != CONFIGURED && !isExecuting()) { // We may be in "UNINITIALIZED" state already without the // client being aware of this if media server died while // we were being stopped. The client would assume that @@ -1388,7 +1401,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (mState != STARTED || (mFlags & kFlagStickyError)) { + if (!isExecuting() || (mFlags & kFlagStickyError)) { PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1459,7 +1472,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (mState != STARTED || (mFlags & kFlagStickyError)) { + if (!isExecuting() || (mFlags & kFlagStickyError)) { PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1475,7 +1488,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (mState != STARTED || (mFlags & kFlagStickyError)) { + if (!isExecuting() || (mFlags & kFlagStickyError)) { PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1490,7 +1503,8 @@ void MediaCodec::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (mState != STARTED || (mFlags & kFlagStickyError)) { + if (!isExecuting() || (mFlags & kFlagIsAsync) + || (mFlags & kFlagStickyError)) { PostReplyWithError(replyID, INVALID_OPERATION); break; } @@ -1521,12 +1535,13 @@ void MediaCodec::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (mState != STARTED || (mFlags & kFlagStickyError)) { + if (!isExecuting() || (mFlags & kFlagStickyError)) { PostReplyWithError(replyID, INVALID_OPERATION); break; } mReplyID = replyID; + // TODO: skip flushing if already FLUSHED setState(FLUSHING); mCodec->signalFlush(); @@ -1544,7 +1559,8 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->senderAwaitsResponse(&replyID)); if ((mState != CONFIGURED && mState != STARTING && - mState != STARTED && mState != FLUSHING) + mState != STARTED && mState != FLUSHING && + mState != FLUSHED) || (mFlags & kFlagStickyError) || format == NULL) { PostReplyWithError(replyID, INVALID_OPERATION); @@ -1879,7 +1895,7 @@ status_t MediaCodec::onReleaseOutputBuffer(const sp &msg) { render = 0; } - if (mState != STARTED) { + if (!isExecuting()) { return -EINVAL; } -- cgit v1.1 From 4ff2a0dbb178c4ea652f30aa4f1d3deb9fdbc832 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 31 Jul 2014 12:09:37 -0700 Subject: stagefright: propagate error in MPEG4Extractor::readMetaData Bug: 16641557 Change-Id: I252825bd767a4581b9fca560f2cabfb37c18e137 --- media/libstagefright/MPEG4Extractor.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 19da6ee..0064293 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -489,7 +489,9 @@ status_t MPEG4Extractor::readMetaData() { off64_t orig_offset = offset; err = parseChunk(&offset, 0); - if (offset <= orig_offset) { + if (err != OK && err != UNKNOWN_ERROR) { + break; + } else if (offset <= orig_offset) { // only continue parsing if the offset was advanced, // otherwise we might end up in an infinite loop ALOGE("did not advance: 0x%lld->0x%lld", orig_offset, offset); @@ -497,9 +499,8 @@ status_t MPEG4Extractor::readMetaData() { break; } else if (err == OK) { continue; - } else if (err != UNKNOWN_ERROR) { - break; } + uint32_t hdr[2]; if (mDataSource->readAt(offset, hdr, 8) < 8) { break; -- cgit v1.1 From 89869f692c35d0ca914c7de4a1f5ff63c9920634 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Sun, 27 Jul 2014 21:21:32 -0700 Subject: stagefright: enable decoder color format selection Bug: 10706245 Change-Id: I9a77631bfae0358be229b079228c1fcae0e77faf --- media/libstagefright/ACodec.cpp | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 3fb174d..5b6e59e 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -1267,13 +1267,7 @@ status_t ACodec::configureCodec( if (encoder) { err = setupVideoEncoder(mime, msg); } else { - int32_t width, height; - if (!msg->findInt32("width", &width) - || !msg->findInt32("height", &height)) { - err = INVALID_OPERATION; - } else { - err = setupVideoDecoder(mime, width, height); - } + err = setupVideoDecoder(mime, msg); } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) { int32_t numChannels, sampleRate; @@ -1883,7 +1877,13 @@ static status_t GetMimeTypeForVideoCoding( } status_t ACodec::setupVideoDecoder( - const char *mime, int32_t width, int32_t height) { + const char *mime, const sp &msg) { + int32_t width, height; + if (!msg->findInt32("width", &width) + || !msg->findInt32("height", &height)) { + return INVALID_OPERATION; + } + OMX_VIDEO_CODINGTYPE compressionFormat; status_t err = GetVideoCodingTypeFromMime(mime, &compressionFormat); @@ -1898,7 +1898,20 @@ status_t ACodec::setupVideoDecoder( return err; } - err = setSupportedOutputFormat(); + int32_t tmp; + if (msg->findInt32("color-format", &tmp)) { + OMX_COLOR_FORMATTYPE colorFormat = + static_cast(tmp); + err = setVideoPortFormatType( + kPortIndexOutput, OMX_VIDEO_CodingUnused, colorFormat); + if (err != OK) { + ALOGW("[%s] does not support color format %d", + mComponentName.c_str(), colorFormat); + err = setSupportedOutputFormat(); + } + } else { + err = setSupportedOutputFormat(); + } if (err != OK) { return err; -- cgit v1.1 From 63c0ce7ab7bd99d51414dcb4f765bc6faabf367d Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 31 Jul 2014 07:13:32 -0700 Subject: mediaplayerservice: initialize mIsWidevine Bug: 16641557 Change-Id: I77aad6e710117a16093726bf3b36360904fbe148 --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index d75408d..752dfab 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -60,7 +60,8 @@ NuPlayer::GenericSource::GenericSource( int fd, int64_t offset, int64_t length) : Source(notify), mDurationUs(0ll), - mAudioIsVorbis(false) { + mAudioIsVorbis(false), + mIsWidevine(false) { DataSource::RegisterDefaultSniffers(); sp dataSource = new FileSource(dup(fd), offset, length); -- cgit v1.1 From e26940f11c3f2040bced09f06a8f374b50c985fb Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 31 Jul 2014 10:31:26 -0700 Subject: GenericSource: timed text support Bug: 16385674 Change-Id: Ib322cc13488dcadf2409921272cd469304b0af37 --- .../nuplayer/GenericSource.cpp | 263 +++++++++++++++------ .../libmediaplayerservice/nuplayer/GenericSource.h | 13 + 2 files changed, 199 insertions(+), 77 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 2f5b0f1..a3e84df 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -42,6 +42,7 @@ NuPlayer::GenericSource::GenericSource( uid_t uid) : Source(notify), mFetchSubtitleDataGeneration(0), + mFetchTimedTextDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false), mIsWidevine(isWidevine), @@ -61,6 +62,7 @@ NuPlayer::GenericSource::GenericSource( int fd, int64_t offset, int64_t length) : Source(notify), mFetchSubtitleDataGeneration(0), + mFetchTimedTextDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false), mIsWidevine(false) { @@ -206,66 +208,29 @@ void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { switch (msg->what()) { case kWhatFetchSubtitleData: { - int32_t generation; - CHECK(msg->findInt32("generation", &generation)); - if (generation != mFetchSubtitleDataGeneration) { - // stale - break; - } - - int32_t avail; - if (mSubtitleTrack.mPackets->hasBufferAvailable(&avail)) { - break; - } - - int64_t timeUs; - CHECK(msg->findInt64("timeUs", &timeUs)); - - int64_t subTimeUs; - readBuffer(MEDIA_TRACK_TYPE_SUBTITLE, timeUs, &subTimeUs); - - const int64_t oneSecUs = 1000000ll; - const int64_t delayUs = subTimeUs - timeUs - oneSecUs; - sp msg2 = new AMessage(kWhatSendSubtitleData, id()); - msg2->setInt32("generation", generation); - msg2->post(delayUs < 0 ? 0 : delayUs); - ALOGV("kWhatFetchSubtitleData generation %d, delayUs %lld", - mFetchSubtitleDataGeneration, delayUs); + fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, + mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); + break; + } + case kWhatFetchTimedTextData: + { + fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, + mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); break; } case kWhatSendSubtitleData: { - int32_t generation; - CHECK(msg->findInt32("generation", &generation)); - if (generation != mFetchSubtitleDataGeneration) { - // stale - break; - } - - int64_t subTimeUs; - if (mSubtitleTrack.mPackets->nextBufferTime(&subTimeUs) != OK) { - break; - } - - int64_t nextSubTimeUs; - readBuffer(MEDIA_TRACK_TYPE_SUBTITLE, -1, &nextSubTimeUs); - - sp buffer; - status_t dequeueStatus = mSubtitleTrack.mPackets->dequeueAccessUnit(&buffer); - if (dequeueStatus != OK) { - ALOGE("kWhatSendSubtitleData dequeueAccessUnit: %d", dequeueStatus); - } else { - sp notify = dupNotify(); - notify->setInt32("what", kWhatSubtitleData); - notify->setBuffer("buffer", buffer); - notify->post(); - - const int64_t delayUs = nextSubTimeUs - subTimeUs; - msg->post(delayUs < 0 ? 0 : delayUs); - } + sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, + mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); + break; + } + case kWhatSendTimedTextData: + { + sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, + mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); break; } @@ -323,6 +288,74 @@ void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { } } +void NuPlayer::GenericSource::fetchTextData( + uint32_t sendWhat, + media_track_type type, + int32_t curGen, + sp packets, + sp msg) { + int32_t msgGeneration; + CHECK(msg->findInt32("generation", &msgGeneration)); + if (msgGeneration != curGen) { + // stale + return; + } + + int32_t avail; + if (packets->hasBufferAvailable(&avail)) { + return; + } + + int64_t timeUs; + CHECK(msg->findInt64("timeUs", &timeUs)); + + int64_t subTimeUs; + readBuffer(type, timeUs, &subTimeUs); + + int64_t delayUs = subTimeUs - timeUs; + if (msg->what() == kWhatFetchSubtitleData) { + const int64_t oneSecUs = 1000000ll; + delayUs -= oneSecUs; + } + sp msg2 = new AMessage(sendWhat, id()); + msg2->setInt32("generation", msgGeneration); + msg2->post(delayUs < 0 ? 0 : delayUs); +} + +void NuPlayer::GenericSource::sendTextData( + uint32_t what, + media_track_type type, + int32_t curGen, + sp packets, + sp msg) { + int32_t msgGeneration; + CHECK(msg->findInt32("generation", &msgGeneration)); + if (msgGeneration != curGen) { + // stale + return; + } + + int64_t subTimeUs; + if (packets->nextBufferTime(&subTimeUs) != OK) { + return; + } + + int64_t nextSubTimeUs; + readBuffer(type, -1, &nextSubTimeUs); + + sp buffer; + status_t dequeueStatus = packets->dequeueAccessUnit(&buffer); + if (dequeueStatus == OK) { + sp notify = dupNotify(); + notify->setInt32("what", what); + notify->setBuffer("buffer", buffer); + notify->post(); + + const int64_t delayUs = nextSubTimeUs - subTimeUs; + msg->post(delayUs < 0 ? 0 : delayUs); + } +} + sp NuPlayer::GenericSource::getFormatMeta(bool audio) { sp source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; @@ -357,27 +390,49 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll); } - if (mSubtitleTrack.mSource == NULL) { + if (mSubtitleTrack.mSource == NULL && mTimedTextTrack.mSource == NULL) { return result; } - CHECK(mSubtitleTrack.mPackets != NULL); + if (mSubtitleTrack.mSource != NULL) { + CHECK(mSubtitleTrack.mPackets != NULL); + } + if (mTimedTextTrack.mSource != NULL) { + CHECK(mTimedTextTrack.mPackets != NULL); + } + if (result != OK) { - mSubtitleTrack.mPackets->clear(); - mFetchSubtitleDataGeneration++; + if (mSubtitleTrack.mSource != NULL) { + mSubtitleTrack.mPackets->clear(); + mFetchSubtitleDataGeneration++; + } + if (mTimedTextTrack.mSource != NULL) { + mTimedTextTrack.mPackets->clear(); + mFetchTimedTextDataGeneration++; + } return result; } int64_t timeUs; status_t eosResult; // ignored CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); - if (!mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { + + if (mSubtitleTrack.mSource != NULL + && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { sp msg = new AMessage(kWhatFetchSubtitleData, id()); msg->setInt64("timeUs", timeUs); msg->setInt32("generation", mFetchSubtitleDataGeneration); msg->post(); } + if (mTimedTextTrack.mSource != NULL + && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { + sp msg = new AMessage(kWhatFetchTimedTextData, id()); + msg->setInt64("timeUs", timeUs); + msg->setInt32("generation", mFetchTimedTextDataGeneration); + msg->post(); + } + return result; } @@ -436,20 +491,53 @@ sp NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { return format; } +ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { + const Track *track = NULL; + switch (type) { + case MEDIA_TRACK_TYPE_VIDEO: + track = &mVideoTrack; + break; + case MEDIA_TRACK_TYPE_AUDIO: + track = &mAudioTrack; + break; + case MEDIA_TRACK_TYPE_TIMEDTEXT: + track = &mTimedTextTrack; + break; + case MEDIA_TRACK_TYPE_SUBTITLE: + track = &mSubtitleTrack; + break; + default: + break; + } + + if (track != NULL && track->mSource != NULL) { + return track->mIndex; + } + + return -1; +} + status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { - ALOGV("selectTrack: %zu", trackIndex); + ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); if (trackIndex >= mSources.size()) { return BAD_INDEX; } if (!select) { - if (mSubtitleTrack.mSource == NULL || trackIndex != mSubtitleTrack.mIndex) { + Track* track = NULL; + if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) { + track = &mSubtitleTrack; + mFetchSubtitleDataGeneration++; + } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) { + track = &mTimedTextTrack; + mFetchTimedTextDataGeneration++; + } + if (track == NULL) { return INVALID_OPERATION; } - mSubtitleTrack.mSource->stop(); - mSubtitleTrack.mSource = NULL; - mSubtitleTrack.mPackets->clear(); - mFetchSubtitleDataGeneration++; + track->mSource->stop(); + track->mSource = NULL; + track->mPackets->clear(); return OK; } @@ -458,22 +546,31 @@ status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); if (!strncasecmp(mime, "text/", 5)) { - if (mSubtitleTrack.mSource != NULL && mSubtitleTrack.mIndex == trackIndex) { + bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP); + Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack; + if (track->mSource != NULL && track->mIndex == trackIndex) { return OK; } - mSubtitleTrack.mIndex = trackIndex; - if (mSubtitleTrack.mSource != NULL) { - mSubtitleTrack.mSource->stop(); + track->mIndex = trackIndex; + if (track->mSource != NULL) { + track->mSource->stop(); } - mSubtitleTrack.mSource = mSources.itemAt(trackIndex); - mSubtitleTrack.mSource->start(); - if (mSubtitleTrack.mPackets == NULL) { - mSubtitleTrack.mPackets = new AnotherPacketSource(mSubtitleTrack.mSource->getFormat()); + track->mSource = mSources.itemAt(trackIndex); + track->mSource->start(); + if (track->mPackets == NULL) { + track->mPackets = new AnotherPacketSource(track->mSource->getFormat()); } else { - mSubtitleTrack.mPackets->clear(); + track->mPackets->clear(); + track->mPackets->setFormat(track->mSource->getFormat()); } - mFetchSubtitleDataGeneration++; + + if (isSubtitle) { + mFetchSubtitleDataGeneration++; + } else { + mFetchTimedTextDataGeneration++; + } + return OK; } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { bool audio = !strncasecmp(mime, "audio/", 6); @@ -540,12 +637,19 @@ sp NuPlayer::GenericSource::mediaBufferToABuffer( memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); } + sp meta = ab->meta(); + int64_t timeUs; CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); - - sp meta = ab->meta(); meta->setInt64("timeUs", timeUs); + if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { + const char *mime; + CHECK(mTimedTextTrack.mSource != NULL + && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime)); + meta->setString("mime", mime); + } + int64_t durationUs; if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { meta->setInt64("durationUs", durationUs); @@ -578,6 +682,9 @@ void NuPlayer::GenericSource::readBuffer( case MEDIA_TRACK_TYPE_SUBTITLE: track = &mSubtitleTrack; break; + case MEDIA_TRACK_TYPE_TIMEDTEXT: + track = &mTimedTextTrack; + break; default: TRESPASS(); } @@ -613,7 +720,9 @@ void NuPlayer::GenericSource::readBuffer( // formatChange && seeking: track whose source is changed during selection // formatChange && !seeking: track whose source is not changed during selection // !formatChange: normal seek - if ((seeking || formatChange) && trackType != MEDIA_TRACK_TYPE_SUBTITLE) { + if ((seeking || formatChange) + && (trackType == MEDIA_TRACK_TYPE_AUDIO + || trackType == MEDIA_TRACK_TYPE_VIDEO)) { ATSParser::DiscontinuityType type = formatChange ? (seeking ? ATSParser::DISCONTINUITY_FORMATCHANGE diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 4e25d55..3c5f55c 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -58,6 +58,7 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual status_t getDuration(int64_t *durationUs); virtual size_t getTrackCount() const; virtual sp getTrackInfo(size_t trackIndex) const; + virtual ssize_t getSelectedTrack(media_track_type type) const; virtual status_t selectTrack(size_t trackIndex, bool select); virtual status_t seekTo(int64_t seekTimeUs); @@ -73,7 +74,9 @@ protected: private: enum { kWhatFetchSubtitleData, + kWhatFetchTimedTextData, kWhatSendSubtitleData, + kWhatSendTimedTextData, kWhatChangeAVSource, }; @@ -88,8 +91,10 @@ private: Track mAudioTrack; Track mVideoTrack; Track mSubtitleTrack; + Track mTimedTextTrack; int32_t mFetchSubtitleDataGeneration; + int32_t mFetchTimedTextDataGeneration; int64_t mDurationUs; bool mAudioIsVorbis; bool mIsWidevine; @@ -98,6 +103,14 @@ private: void initFromDataSource(const sp &dataSource); + void fetchTextData( + uint32_t what, media_track_type type, + int32_t curGen, sp packets, sp msg); + + void sendTextData( + uint32_t what, media_track_type type, + int32_t curGen, sp packets, sp msg); + sp mediaBufferToABuffer( MediaBuffer *mbuf, media_track_type trackType, -- cgit v1.1 From 3423bbdb05f843a64356fa24e8657f03ecbb7d65 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 16 Jul 2014 15:47:09 -0700 Subject: GenericSource: support track (de)selection Bug: 15153976 Change-Id: Idfce856b4ca5fa7853da857757490798bc3ffe1e --- .../nuplayer/GenericSource.cpp | 359 +++++++++++++++++---- .../libmediaplayerservice/nuplayer/GenericSource.h | 23 +- .../libstagefright/mpeg2ts/AnotherPacketSource.cpp | 12 +- media/libstagefright/mpeg2ts/AnotherPacketSource.h | 1 + 4 files changed, 330 insertions(+), 65 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 752dfab..2f5b0f1 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -41,6 +41,7 @@ NuPlayer::GenericSource::GenericSource( bool uidValid, uid_t uid) : Source(notify), + mFetchSubtitleDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false), mIsWidevine(isWidevine), @@ -59,6 +60,7 @@ NuPlayer::GenericSource::GenericSource( const sp ¬ify, int fd, int64_t offset, int64_t length) : Source(notify), + mFetchSubtitleDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false), mIsWidevine(false) { @@ -181,20 +183,18 @@ void NuPlayer::GenericSource::start() { if (mAudioTrack.mSource != NULL) { CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); - mAudioTrack.mPackets = new AnotherPacketSource(mAudioTrack.mSource->getFormat()); - readBuffer(true /* audio */); + readBuffer(MEDIA_TRACK_TYPE_AUDIO); } if (mVideoTrack.mSource != NULL) { CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); - mVideoTrack.mPackets = new AnotherPacketSource(mVideoTrack.mSource->getFormat()); - readBuffer(false /* audio */); + readBuffer(MEDIA_TRACK_TYPE_VIDEO); } } @@ -202,6 +202,127 @@ status_t NuPlayer::GenericSource::feedMoreTSData() { return OK; } +void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { + switch (msg->what()) { + case kWhatFetchSubtitleData: + { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + if (generation != mFetchSubtitleDataGeneration) { + // stale + break; + } + + int32_t avail; + if (mSubtitleTrack.mPackets->hasBufferAvailable(&avail)) { + break; + } + + int64_t timeUs; + CHECK(msg->findInt64("timeUs", &timeUs)); + + int64_t subTimeUs; + readBuffer(MEDIA_TRACK_TYPE_SUBTITLE, timeUs, &subTimeUs); + + const int64_t oneSecUs = 1000000ll; + const int64_t delayUs = subTimeUs - timeUs - oneSecUs; + sp msg2 = new AMessage(kWhatSendSubtitleData, id()); + msg2->setInt32("generation", generation); + msg2->post(delayUs < 0 ? 0 : delayUs); + ALOGV("kWhatFetchSubtitleData generation %d, delayUs %lld", + mFetchSubtitleDataGeneration, delayUs); + + break; + } + + case kWhatSendSubtitleData: + { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + if (generation != mFetchSubtitleDataGeneration) { + // stale + break; + } + + int64_t subTimeUs; + if (mSubtitleTrack.mPackets->nextBufferTime(&subTimeUs) != OK) { + break; + } + + int64_t nextSubTimeUs; + readBuffer(MEDIA_TRACK_TYPE_SUBTITLE, -1, &nextSubTimeUs); + + sp buffer; + status_t dequeueStatus = mSubtitleTrack.mPackets->dequeueAccessUnit(&buffer); + if (dequeueStatus != OK) { + ALOGE("kWhatSendSubtitleData dequeueAccessUnit: %d", dequeueStatus); + } else { + sp notify = dupNotify(); + notify->setInt32("what", kWhatSubtitleData); + notify->setBuffer("buffer", buffer); + notify->post(); + + const int64_t delayUs = nextSubTimeUs - subTimeUs; + msg->post(delayUs < 0 ? 0 : delayUs); + } + + break; + } + + case kWhatChangeAVSource: + { + int32_t trackIndex; + CHECK(msg->findInt32("trackIndex", &trackIndex)); + const sp source = mSources.itemAt(trackIndex); + + Track* track; + const char *mime; + media_track_type trackType, counterpartType; + sp meta = source->getFormat(); + meta->findCString(kKeyMIMEType, &mime); + if (!strncasecmp(mime, "audio/", 6)) { + track = &mAudioTrack; + trackType = MEDIA_TRACK_TYPE_AUDIO; + counterpartType = MEDIA_TRACK_TYPE_VIDEO;; + } else { + CHECK(!strncasecmp(mime, "video/", 6)); + track = &mVideoTrack; + trackType = MEDIA_TRACK_TYPE_VIDEO; + counterpartType = MEDIA_TRACK_TYPE_AUDIO;; + } + + + if (track->mSource != NULL) { + track->mSource->stop(); + } + track->mSource = source; + track->mSource->start(); + track->mIndex = trackIndex; + + status_t avail; + if (!track->mPackets->hasBufferAvailable(&avail)) { + // sync from other source + TRESPASS(); + break; + } + + int64_t timeUs, actualTimeUs; + const bool formatChange = true; + sp latestMeta = track->mPackets->getLatestMeta(); + CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs)); + readBuffer(trackType, timeUs, &actualTimeUs, formatChange); + readBuffer(counterpartType, -1, NULL, formatChange); + ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs); + + break; + } + + default: + Source::onMessageReceived(msg); + break; + } +} + sp NuPlayer::GenericSource::getFormatMeta(bool audio) { sp source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; @@ -222,7 +343,7 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( if (mIsWidevine && !audio) { // try to read a buffer as we may not have been able to the last time - readBuffer(audio, -1ll); + readBuffer(MEDIA_TRACK_TYPE_VIDEO, -1ll); } status_t finalResult; @@ -232,7 +353,30 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( status_t result = track->mPackets->dequeueAccessUnit(accessUnit); - readBuffer(audio, -1ll); + if (!track->mPackets->hasBufferAvailable(&finalResult)) { + readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll); + } + + if (mSubtitleTrack.mSource == NULL) { + return result; + } + + CHECK(mSubtitleTrack.mPackets != NULL); + if (result != OK) { + mSubtitleTrack.mPackets->clear(); + mFetchSubtitleDataGeneration++; + return result; + } + + int64_t timeUs; + status_t eosResult; // ignored + CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); + if (!mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { + sp msg = new AMessage(kWhatFetchSubtitleData, id()); + msg->setInt64("timeUs", timeUs); + msg->setInt32("generation", mFetchSubtitleDataGeneration); + msg->post(); + } return result; } @@ -292,25 +436,155 @@ sp NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { return format; } +status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { + ALOGV("selectTrack: %zu", trackIndex); + if (trackIndex >= mSources.size()) { + return BAD_INDEX; + } + + if (!select) { + if (mSubtitleTrack.mSource == NULL || trackIndex != mSubtitleTrack.mIndex) { + return INVALID_OPERATION; + } + mSubtitleTrack.mSource->stop(); + mSubtitleTrack.mSource = NULL; + mSubtitleTrack.mPackets->clear(); + mFetchSubtitleDataGeneration++; + return OK; + } + + const sp source = mSources.itemAt(trackIndex); + sp meta = source->getFormat(); + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + if (!strncasecmp(mime, "text/", 5)) { + if (mSubtitleTrack.mSource != NULL && mSubtitleTrack.mIndex == trackIndex) { + return OK; + } + mSubtitleTrack.mIndex = trackIndex; + if (mSubtitleTrack.mSource != NULL) { + mSubtitleTrack.mSource->stop(); + } + mSubtitleTrack.mSource = mSources.itemAt(trackIndex); + mSubtitleTrack.mSource->start(); + if (mSubtitleTrack.mPackets == NULL) { + mSubtitleTrack.mPackets = new AnotherPacketSource(mSubtitleTrack.mSource->getFormat()); + } else { + mSubtitleTrack.mPackets->clear(); + + } + mFetchSubtitleDataGeneration++; + return OK; + } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { + bool audio = !strncasecmp(mime, "audio/", 6); + Track *track = audio ? &mAudioTrack : &mVideoTrack; + if (track->mSource != NULL && track->mIndex == trackIndex) { + return OK; + } + + sp msg = new AMessage(kWhatChangeAVSource, id()); + msg->setInt32("trackIndex", trackIndex); + msg->post(); + return OK; + } + + return INVALID_OPERATION; +} + status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { if (mVideoTrack.mSource != NULL) { int64_t actualTimeUs; - readBuffer(false /* audio */, seekTimeUs, &actualTimeUs); + readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs); seekTimeUs = actualTimeUs; } if (mAudioTrack.mSource != NULL) { - readBuffer(true /* audio */, seekTimeUs); + readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs); } return OK; } +sp NuPlayer::GenericSource::mediaBufferToABuffer( + MediaBuffer* mb, + media_track_type trackType, + int64_t *actualTimeUs) { + bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO; + size_t outLength = mb->range_length(); + + if (audio && mAudioIsVorbis) { + outLength += sizeof(int32_t); + } + + sp ab; + if (mIsWidevine && !audio) { + // data is already provided in the buffer + ab = new ABuffer(NULL, mb->range_length()); + ab->meta()->setPointer("mediaBuffer", mb); + mb->add_ref(); + } else { + ab = new ABuffer(outLength); + memcpy(ab->data(), + (const uint8_t *)mb->data() + mb->range_offset(), + mb->range_length()); + } + + if (audio && mAudioIsVorbis) { + int32_t numPageSamples; + if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) { + numPageSamples = -1; + } + + uint8_t* abEnd = ab->data() + mb->range_length(); + memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); + } + + int64_t timeUs; + CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); + + sp meta = ab->meta(); + meta->setInt64("timeUs", timeUs); + + int64_t durationUs; + if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { + meta->setInt64("durationUs", durationUs); + } + + if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { + meta->setInt32("trackIndex", mSubtitleTrack.mIndex); + } + + if (actualTimeUs) { + *actualTimeUs = timeUs; + } + + mb->release(); + mb = NULL; + + return ab; +} + void NuPlayer::GenericSource::readBuffer( - bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) { - Track *track = audio ? &mAudioTrack : &mVideoTrack; - CHECK(track->mSource != NULL); + media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) { + Track *track; + switch (trackType) { + case MEDIA_TRACK_TYPE_VIDEO: + track = &mVideoTrack; + break; + case MEDIA_TRACK_TYPE_AUDIO: + track = &mAudioTrack; + break; + case MEDIA_TRACK_TYPE_SUBTITLE: + track = &mSubtitleTrack; + break; + default: + TRESPASS(); + } + + if (track->mSource == NULL) { + return; + } if (actualTimeUs) { *actualTimeUs = seekTimeUs; @@ -321,11 +595,11 @@ void NuPlayer::GenericSource::readBuffer( bool seeking = false; if (seekTimeUs >= 0) { - options.setSeekTo(seekTimeUs); + options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); seeking = true; } - if (mIsWidevine && !audio) { + if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) { options.setNonBlocking(); } @@ -336,56 +610,19 @@ void NuPlayer::GenericSource::readBuffer( options.clearSeekTo(); if (err == OK) { - size_t outLength = mbuf->range_length(); - - if (audio && mAudioIsVorbis) { - outLength += sizeof(int32_t); - } - - sp buffer; - if (mIsWidevine && !audio) { - // data is already provided in the buffer - buffer = new ABuffer(NULL, mbuf->range_length()); - buffer->meta()->setPointer("mediaBuffer", mbuf); - mbuf->add_ref(); - } else { - buffer = new ABuffer(outLength); - memcpy(buffer->data(), - (const uint8_t *)mbuf->data() + mbuf->range_offset(), - mbuf->range_length()); - } - - if (audio && mAudioIsVorbis) { - int32_t numPageSamples; - if (!mbuf->meta_data()->findInt32( - kKeyValidSamples, &numPageSamples)) { - numPageSamples = -1; - } - - memcpy(buffer->data() + mbuf->range_length(), - &numPageSamples, - sizeof(numPageSamples)); - } - - int64_t timeUs; - CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); - - buffer->meta()->setInt64("timeUs", timeUs); - - if (actualTimeUs) { - *actualTimeUs = timeUs; - } - - mbuf->release(); - mbuf = NULL; - - if (seeking) { - track->mPackets->queueDiscontinuity( - ATSParser::DISCONTINUITY_SEEK, - NULL, - true /* discard */); + // formatChange && seeking: track whose source is changed during selection + // formatChange && !seeking: track whose source is not changed during selection + // !formatChange: normal seek + if ((seeking || formatChange) && trackType != MEDIA_TRACK_TYPE_SUBTITLE) { + ATSParser::DiscontinuityType type = formatChange + ? (seeking + ? ATSParser::DISCONTINUITY_FORMATCHANGE + : ATSParser::DISCONTINUITY_NONE) + : ATSParser::DISCONTINUITY_SEEK; + track->mPackets->queueDiscontinuity( type, NULL, true /* discard */); } + sp buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs); track->mPackets->queueAccessUnit(buffer); break; } else if (err == WOULD_BLOCK) { diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 8e0209d..4e25d55 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -23,12 +23,15 @@ #include "ATSParser.h" +#include + namespace android { struct AnotherPacketSource; struct ARTSPController; struct DataSource; struct MediaSource; +class MediaBuffer; struct NuPlayer::GenericSource : public NuPlayer::Source { GenericSource( @@ -55,6 +58,7 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual status_t getDuration(int64_t *durationUs); virtual size_t getTrackCount() const; virtual sp getTrackInfo(size_t trackIndex) const; + virtual status_t selectTrack(size_t trackIndex, bool select); virtual status_t seekTo(int64_t seekTimeUs); virtual status_t setBuffers(bool audio, Vector &buffers); @@ -62,9 +66,17 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { protected: virtual ~GenericSource(); + virtual void onMessageReceived(const sp &msg); + virtual sp getFormatMeta(bool audio); private: + enum { + kWhatFetchSubtitleData, + kWhatSendSubtitleData, + kWhatChangeAVSource, + }; + Vector > mSources; struct Track { @@ -75,7 +87,9 @@ private: Track mAudioTrack; Track mVideoTrack; + Track mSubtitleTrack; + int32_t mFetchSubtitleDataGeneration; int64_t mDurationUs; bool mAudioIsVorbis; bool mIsWidevine; @@ -84,9 +98,14 @@ private: void initFromDataSource(const sp &dataSource); + sp mediaBufferToABuffer( + MediaBuffer *mbuf, + media_track_type trackType, + int64_t *actualTimeUs = NULL); + void readBuffer( - bool audio, - int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL); + media_track_type trackType, + int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL, bool formatChange = false); DISALLOW_EVIL_CONSTRUCTORS(GenericSource); }; diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index a0319ab..72c9dae 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -34,6 +34,7 @@ const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs AnotherPacketSource::AnotherPacketSource(const sp &meta) : mIsAudio(false), + mIsVideo(false), mFormat(NULL), mLastQueuedTimeUs(0), mEOSResult(OK), @@ -45,6 +46,7 @@ void AnotherPacketSource::setFormat(const sp &meta) { CHECK(mFormat == NULL); mIsAudio = false; + mIsVideo = false; if (meta == NULL) { return; @@ -56,8 +58,10 @@ void AnotherPacketSource::setFormat(const sp &meta) { if (!strncasecmp("audio/", mime, 6)) { mIsAudio = true; + } else if (!strncasecmp("video/", mime, 6)) { + mIsVideo = true; } else { - CHECK(!strncasecmp("video/", mime, 6)); + CHECK(!strncasecmp("text/", mime, 5)); } } @@ -175,7 +179,11 @@ bool AnotherPacketSource::wasFormatChange( return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0; } - return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0; + if (mIsVideo) { + return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0; + } + + return false; } void AnotherPacketSource::queueAccessUnit(const sp &buffer) { diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h index 06c49bd..f38f9dc 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h @@ -74,6 +74,7 @@ private: Condition mCondition; bool mIsAudio; + bool mIsVideo; sp mFormat; int64_t mLastQueuedTimeUs; List > mBuffers; -- cgit v1.1 From a298101317e5472f6b6a12e6ddeafdc4064bd5b2 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 30 Jul 2014 17:41:24 -0700 Subject: NuPlayer: fix av discontinuity race Assumption: NuPlayer must see both (a/v) discontinuities before resuming. Example issue: Suppose we're changing the video track, so the video source queues a DISCONTINUITY_FORMATCHANGE, and the audio source queues a DISCONTINUITY_NONE. Consider this sequence of events without this change: 1. audio discontinuity seen by player 2. mFlushingAudio = FLUSHED 3. video discontinuity seen by player 4. mFlushingAudio != NONE so no performScanSources is queued 5. video decoding shuts down without being restarted Bug: 15153976 Change-Id: I659550d9c0f883828103142abead857f576f25b1 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index adc5f33..58d0138 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1230,14 +1230,15 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { mTimeDiscontinuityPending = mTimeDiscontinuityPending || timeChange; + if (mFlushingAudio == NONE && mFlushingVideo == NONE) { + // And we'll resume scanning sources once we're done + // flushing. + mDeferredActions.push_front( + new SimpleAction( + &NuPlayer::performScanSources)); + } + if (formatChange || timeChange) { - if (mFlushingAudio == NONE && mFlushingVideo == NONE) { - // And we'll resume scanning sources once we're done - // flushing. - mDeferredActions.push_front( - new SimpleAction( - &NuPlayer::performScanSources)); - } sp newFormat = mSource->getFormat(audio); sp &decoder = audio ? mAudioDecoder : mVideoDecoder; -- cgit v1.1 From a2e14302d4b5ca5443611d0c05218b9da4cc64a6 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 31 Jul 2014 12:07:58 -0700 Subject: mediaplayer: add looping support to NuPlayer Bug: 16641557 Change-Id: I433158e6e585b4714cfd6d89562ecd0587a07ae2 --- .../nuplayer/NuPlayerDriver.cpp | 30 +++++++++++++++++++--- .../nuplayer/NuPlayerDriver.h | 1 + 2 files changed, 27 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 280b5af..4748546 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -42,6 +42,7 @@ NuPlayerDriver::NuPlayerDriver() mLooper(new ALooper), mPlayerFlags(0), mAtEOS(false), + mLooping(false), mStartupSeekTimeUs(-1) { mLooper->setName("NuPlayerDriver Looper"); @@ -76,6 +77,7 @@ status_t NuPlayerDriver::setDataSource( const KeyedVector *headers) { Mutex::Autolock autoLock(mLock); + ALOGV("setDataSource: url=%s", url); if (mState != STATE_IDLE) { return INVALID_OPERATION; } @@ -94,6 +96,7 @@ status_t NuPlayerDriver::setDataSource( status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) { Mutex::Autolock autoLock(mLock); + ALOGV("setDataSource: fd=%d", fd); if (mState != STATE_IDLE) { return INVALID_OPERATION; } @@ -112,6 +115,7 @@ status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) { status_t NuPlayerDriver::setDataSource(const sp &source) { Mutex::Autolock autoLock(mLock); + ALOGV("setDataSource: stream source"); if (mState != STATE_IDLE) { return INVALID_OPERATION; } @@ -367,12 +371,14 @@ status_t NuPlayerDriver::reset() { mDurationUs = -1; mPositionUs = -1; mStartupSeekTimeUs = -1; + mLooping = false; return OK; } -status_t NuPlayerDriver::setLooping(int /* loop */) { - return INVALID_OPERATION; +status_t NuPlayerDriver::setLooping(int loop) { + mLooping = loop != 0; + return OK; } player_type NuPlayerDriver::playerType() { @@ -523,8 +529,24 @@ status_t NuPlayerDriver::dump( void NuPlayerDriver::notifyListener( int msg, int ext1, int ext2, const Parcel *in) { - if (msg == MEDIA_PLAYBACK_COMPLETE || msg == MEDIA_ERROR) { - mAtEOS = true; + switch (msg) { + case MEDIA_PLAYBACK_COMPLETE: + { + if (mLooping) { + mPlayer->seekToAsync(0); + break; + } + // fall through + } + + case MEDIA_ERROR: + { + mAtEOS = true; + break; + } + + default: + break; } sendEvent(msg, ext1, ext2, in); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index 0148fb1..9424aae 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -111,6 +111,7 @@ private: uint32_t mPlayerFlags; bool mAtEOS; + bool mLooping; int64_t mStartupSeekTimeUs; -- cgit v1.1 From 16e79115e497386eaf010af388627f94314a55a3 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Fri, 1 Aug 2014 10:30:26 -0700 Subject: MediaCodecSource: stop puller from caller's thread instead of looper Currently CameraSource/AudioSource's stop() and read() are both called from the puller's looper. This works if source operates normally (i.e. read() returns regularly before source is stopped), as the stop() will eventually be handled by the looper. However, if for some reason the source hang, it will get stuck in read(), and the stop() will never be processed, which could lead to ANR (in addition to the source hang). We need to move the source's stop out of the puller's looper. It also can't be on MediaCodecSource's looper, because the source's stop synchrounously waits for all outstanding buffers to return, these are only returned when MediaCodecSource's looper processes the buffer. This change moves the stop to MediaCodecSource::stop, after encoder is shutdown. Bug: 16522726 Change-Id: Ie91f563c5d8a98ab091bf1945af4e51f662b9403 --- media/libstagefright/AudioSource.cpp | 4 +- media/libstagefright/MediaCodecSource.cpp | 74 ++++++++++++++++++------------- 2 files changed, 44 insertions(+), 34 deletions(-) (limited to 'media') diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index a67fabe..804f131 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -155,12 +155,12 @@ status_t AudioSource::reset() { } mStarted = false; + mFrameAvailableCondition.signal(); + mRecord->stop(); waitOutstandingEncodingFrames_l(); releaseQueuedFrames_l(); - mFrameAvailableCondition.signal(); - return OK; } diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index 9868ecf..1a80dcc 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -54,7 +54,7 @@ struct MediaCodecSource::Puller : public AHandler { Puller(const sp &source); status_t start(const sp &meta, const sp ¬ify); - void stopAsync(); + void stop(); void pause(); void resume(); @@ -139,8 +139,17 @@ status_t MediaCodecSource::Puller::start(const sp &meta, return postSynchronouslyAndReturnError(msg); } -void MediaCodecSource::Puller::stopAsync() { - ALOGV("puller (%s) stopAsync", mIsAudio ? "audio" : "video"); +void MediaCodecSource::Puller::stop() { + // Stop source from caller's thread instead of puller's looper. + // mSource->stop() is thread-safe, doing it outside the puller's + // looper allows us to at least stop if source gets stuck. + // If source gets stuck in read(), the looper would never + // be able to process the stop(), which could lead to ANR. + + ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video"); + mSource->stop(); + ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video"); + (new AMessage(kWhatStop, id()))->post(); } @@ -194,9 +203,6 @@ void MediaCodecSource::Puller::onMessageReceived(const sp &msg) { case kWhatStop: { - ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video"); - mSource->stop(); - ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video"); ++mPullGeneration; handleEOS(); @@ -283,7 +289,21 @@ status_t MediaCodecSource::start(MetaData* params) { status_t MediaCodecSource::stop() { sp msg = new AMessage(kWhatStop, mReflector->id()); - return postSynchronouslyAndReturnError(msg); + status_t err = postSynchronouslyAndReturnError(msg); + + // mPuller->stop() needs to be done outside MediaCodecSource's looper, + // as it contains a synchronous call to stop the underlying MediaSource, + // which often waits for all outstanding MediaBuffers to return, but + // MediaBuffers are only returned when MediaCodecSource looper gets + // to process them. + + if (mPuller != NULL) { + ALOGI("puller (%s) stopping", mIsVideo ? "video" : "audio"); + mPuller->stop(); + ALOGI("puller (%s) stopped", mIsVideo ? "video" : "audio"); + } + + return err; } status_t MediaCodecSource::pause() { @@ -301,10 +321,10 @@ status_t MediaCodecSource::read( Mutex::Autolock autolock(mOutputBufferLock); *buffer = NULL; - while (mOutputBufferQueue.size() == 0 && !mEncodedReachedEOS) { + while (mOutputBufferQueue.size() == 0 && !mEncoderReachedEOS) { mOutputBufferCond.wait(mOutputBufferLock); } - if (!mEncodedReachedEOS) { + if (!mEncoderReachedEOS) { *buffer = *mOutputBufferQueue.begin(); mOutputBufferQueue.erase(mOutputBufferQueue.begin()); return OK; @@ -330,9 +350,8 @@ MediaCodecSource::MediaCodecSource( mStarted(false), mStopping(false), mDoMoreWorkPending(false), - mPullerReachedEOS(false), mFirstSampleTimeUs(-1ll), - mEncodedReachedEOS(false), + mEncoderReachedEOS(false), mErrorCode(OK) { CHECK(mLooper != NULL); @@ -434,7 +453,7 @@ status_t MediaCodecSource::initEncoder() { return err; } - mEncodedReachedEOS = false; + mEncoderReachedEOS = false; mErrorCode = OK; return OK; @@ -465,10 +484,6 @@ void MediaCodecSource::releaseEncoder() { mEncoderOutputBuffers.clear(); } -bool MediaCodecSource::reachedEOS() { - return mEncodedReachedEOS && ((mPuller == NULL) || mPullerReachedEOS); -} - status_t MediaCodecSource::postSynchronouslyAndReturnError( const sp &msg) { sp response; @@ -486,8 +501,8 @@ status_t MediaCodecSource::postSynchronouslyAndReturnError( } void MediaCodecSource::signalEOS(status_t err) { - if (!mEncodedReachedEOS) { - ALOGI("encoder (%s) reached EOS", mIsVideo ? "video" : "audio"); + if (!mEncoderReachedEOS) { + ALOGV("encoder (%s) reached EOS", mIsVideo ? "video" : "audio"); { Mutex::Autolock autoLock(mOutputBufferLock); // release all unread media buffers @@ -496,16 +511,15 @@ void MediaCodecSource::signalEOS(status_t err) { (*it)->release(); } mOutputBufferQueue.clear(); - mEncodedReachedEOS = true; + mEncoderReachedEOS = true; mErrorCode = err; mOutputBufferCond.signal(); } releaseEncoder(); } - if (mStopping && reachedEOS()) { - ALOGI("MediaCodecSource (%s) fully stopped", - mIsVideo ? "video" : "audio"); + if (mStopping && mEncoderReachedEOS) { + ALOGI("encoder (%s) stopped", mIsVideo ? "video" : "audio"); // posting reply to everyone that's waiting List::iterator it; for (it = mStopReplyIDQueue.begin(); @@ -755,7 +769,6 @@ status_t MediaCodecSource::onStart(MetaData *params) { kWhatPullerNotify, mReflector->id()); err = mPuller->start(params, notify); if (err != OK) { - mPullerReachedEOS = true; return err; } } @@ -774,9 +787,9 @@ void MediaCodecSource::onMessageReceived(const sp &msg) { CHECK(msg->findPointer("accessUnit", (void**)&mbuf)); if (mbuf == NULL) { - ALOGI("puller (%s) reached EOS", + ALOGV("puller (%s) reached EOS", mIsVideo ? "video" : "audio"); - mPullerReachedEOS = true; + signalEOS(); } if (mEncoder == NULL) { @@ -785,9 +798,8 @@ void MediaCodecSource::onMessageReceived(const sp &msg) { if (mbuf != NULL) { mbuf->release(); - } else { - signalEOS(); } + break; } @@ -833,14 +845,14 @@ void MediaCodecSource::onMessageReceived(const sp &msg) { } case kWhatStop: { - ALOGI("MediaCodecSource (%s) stopping", mIsVideo ? "video" : "audio"); + ALOGI("encoder (%s) stopping", mIsVideo ? "video" : "audio"); uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (reachedEOS()) { + if (mEncoderReachedEOS) { // if we already reached EOS, reply and return now - ALOGI("MediaCodecSource (%s) already stopped", + ALOGI("encoder (%s) already stopped", mIsVideo ? "video" : "audio"); (new AMessage)->postReply(replyID); break; @@ -860,8 +872,6 @@ void MediaCodecSource::onMessageReceived(const sp &msg) { if (mFlags & FLAG_USE_SURFACE_INPUT) { mEncoder->signalEndOfInputStream(); } else { - CHECK(mPuller != NULL); - mPuller->stopAsync(); signalEOS(); } break; -- cgit v1.1 From 68b15554f6dca3b056eac517fe5fa2fd4ee80a33 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Wed, 30 Apr 2014 10:19:03 -0700 Subject: Allow device to be unprovisioned bug: 12247651 Change-Id: I564ac8de3da2430342a028f4058e2c5ac2d85d5e --- media/libmedia/IDrm.cpp | 20 +++++++++++++++++++- media/libmediaplayerservice/Drm.cpp | 17 +++++++++++++++++ media/libmediaplayerservice/Drm.h | 2 ++ 3 files changed, 38 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp index f1a6a9f..1904839 100644 --- a/media/libmedia/IDrm.cpp +++ b/media/libmedia/IDrm.cpp @@ -53,7 +53,8 @@ enum { SIGN, SIGN_RSA, VERIFY, - SET_LISTENER + SET_LISTENER, + UNPROVISION_DEVICE }; struct BpDrm : public BpInterface { @@ -229,6 +230,15 @@ struct BpDrm : public BpInterface { return reply.readInt32(); } + virtual status_t unprovisionDevice() { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + remote()->transact(UNPROVISION_DEVICE, data, &reply); + + return reply.readInt32(); + } + virtual status_t getSecureStops(List > &secureStops) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); @@ -619,6 +629,14 @@ status_t BnDrm::onTransact( return OK; } + case UNPROVISION_DEVICE: + { + CHECK_INTERFACE(IDrm, data, reply); + status_t result = unprovisionDevice(); + reply->writeInt32(result); + return OK; + } + case GET_SECURE_STOPS: { CHECK_INTERFACE(IDrm, data, reply); diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp index d50037f..d222316 100644 --- a/media/libmediaplayerservice/Drm.cpp +++ b/media/libmediaplayerservice/Drm.cpp @@ -417,6 +417,23 @@ status_t Drm::provideProvisionResponse(Vector const &response, return mPlugin->provideProvisionResponse(response, certificate, wrappedKey); } +status_t Drm::unprovisionDevice() { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + if (!checkPermission("android.permission.REMOVE_DRM_CERTIFICATES")) { + return -EPERM; + } + + return mPlugin->unprovisionDevice(); +} status_t Drm::getSecureStops(List > &secureStops) { Mutex::Autolock autoLock(mLock); diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h index 3d4b0fc..9e23e2e 100644 --- a/media/libmediaplayerservice/Drm.h +++ b/media/libmediaplayerservice/Drm.h @@ -75,6 +75,8 @@ struct Drm : public BnDrm, Vector &certificate, Vector &wrappedKey); + virtual status_t unprovisionDevice(); + virtual status_t getSecureStops(List > &secureStops); virtual status_t releaseSecureStops(Vector const &ssRelease); -- cgit v1.1 From 7e892180f3992c088dc0d44f0b0e54ace4dabe3c Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 5 Aug 2014 11:58:21 -0700 Subject: set secure flag for secure file playback Bug: 16786456 Change-Id: I06f18b0e9c3f65e3e127369baa1f9ea8c9307762 --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 13 ++++++++++++- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 4 +++- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index a3e84df..32842bb 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "GenericSource" + #include "GenericSource.h" #include "AnotherPacketSource.h" @@ -65,7 +68,9 @@ NuPlayer::GenericSource::GenericSource( mFetchTimedTextDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false), - mIsWidevine(false) { + mIsWidevine(false), + mUIDValid(false), + mUID(0) { DataSource::RegisterDefaultSniffers(); sp dataSource = new FileSource(dup(fd), offset, length); @@ -134,6 +139,12 @@ void NuPlayer::GenericSource::initFromDataSource( if (mVideoTrack.mSource == NULL) { mVideoTrack.mIndex = i; mVideoTrack.mSource = track; + + // check if the source requires secure buffers + int32_t secure; + if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) && secure) { + mIsWidevine = true; + } } } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 58d0138..71857c3 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -227,7 +227,9 @@ void NuPlayer::setDataSourceAsync( } else if ((!strncasecmp(url, "widevine://", 11))) { source = new GenericSource(notify, httpService, url, headers, true /* isWidevine */, mUIDValid, mUID); - mSourceFlags |= Source::FLAG_SECURE; + // Don't set FLAG_SECURE on mSourceFlags here, the correct flags + // will be updated in Source::kWhatFlagsChanged handler when + // GenericSource is prepared. } else { source = new GenericSource(notify, httpService, url, headers); } -- cgit v1.1 From ccad786f3497f223cbc5af981b08b460433ee622 Mon Sep 17 00:00:00 2001 From: aarti jadhav-gaikwad Date: Sat, 2 Aug 2014 16:21:32 +0530 Subject: stagefright: Pass audio aac subformats in offloadinfo Pass audio aac sub formats in offloadinfo according to aac profile. Audio HAL can take decision about offload using DSP capabilities Change-Id: Ice277e8b6561b7a7db92c474f23f8041ebb35e8c --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 9 +++++++++ media/libstagefright/Utils.cpp | 5 +++++ 2 files changed, 14 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 58d0138..29f57d6 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -749,6 +749,15 @@ void NuPlayer::onMessageReceived(const sp &msg) { ALOGV("Mime \"%s\" mapped to audio_format 0x%x", mime.c_str(), audioFormat); + int32_t aacProfile = -1; + if (audioFormat == AUDIO_FORMAT_AAC + && format->findInt32("aac-profile", &aacProfile)) { + // Redefine AAC format as per aac profile + mapAACProfileToAudioFormat( + audioFormat, + aacProfile); + } + flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; offloadInfo.duration_us = -1; diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 587e264..5f1d1c6 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -135,6 +135,11 @@ status_t convertMetaDataToMessage( if (meta->findInt32(kKeyIsADTS, &isADTS)) { msg->setInt32("is-adts", true); } + + int32_t aacProfile = -1; + if (meta->findInt32(kKeyAACAOT, &aacProfile)) { + msg->setInt32("aac-profile", aacProfile); + } } int32_t maxInputSize; -- cgit v1.1 From df3dc7e2fe6c639529b70e3f3a7d2bf0f4c6e871 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Sun, 27 Jul 2014 18:39:40 -0700 Subject: Add sound trigger control by audio policy Audio policy: - Added active capture indication to sound trigger service: recognition stops if concurrent capture is not supported. - Added generation of reserved I/O handle and session ID for utterance capture. Sound trigger service - Added sound model update callback handling. - Added service state callback - Simplified callback shared memory allocation. Bug: 12378680. Change-Id: Ib0292c2733e6df90fdae480633dd9953d0016ef1 --- media/libmedia/AudioSystem.cpp | 15 ++++++++ media/libmedia/IAudioPolicyService.cpp | 67 +++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 365a594..172b056 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -913,6 +913,21 @@ void AudioSystem::setAudioPortCallback(sp callBack) gAudioPortCallback = callBack; } +status_t AudioSystem::acquireSoundTriggerSession(audio_session_t *session, + audio_io_handle_t *ioHandle, + audio_devices_t *device) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->acquireSoundTriggerSession(session, ioHandle, device); +} + +status_t AudioSystem::releaseSoundTriggerSession(audio_session_t session) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->releaseSoundTriggerSession(session); +} // --------------------------------------------------------------------------- void AudioSystem::AudioPolicyServiceClient::binderDied(const wp& who __unused) diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 1593b17..b57f747 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -65,7 +65,9 @@ enum { LIST_AUDIO_PATCHES, SET_AUDIO_PORT_CONFIG, REGISTER_CLIENT, - GET_OUTPUT_FOR_ATTR + GET_OUTPUT_FOR_ATTR, + ACQUIRE_SOUNDTRIGGER_SESSION, + RELEASE_SOUNDTRIGGER_SESSION }; class BpAudioPolicyService : public BpInterface @@ -563,6 +565,7 @@ public: } return status; } + virtual void registerClient(const sp& client) { Parcel data, reply; @@ -570,6 +573,40 @@ public: data.writeStrongBinder(client->asBinder()); remote()->transact(REGISTER_CLIENT, data, &reply); } + + virtual status_t acquireSoundTriggerSession(audio_session_t *session, + audio_io_handle_t *ioHandle, + audio_devices_t *device) + { + if (session == NULL || ioHandle == NULL || device == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + status_t status = remote()->transact(ACQUIRE_SOUNDTRIGGER_SESSION, data, &reply); + if (status != NO_ERROR) { + return status; + } + status = (status_t)reply.readInt32(); + if (status == NO_ERROR) { + *session = (audio_session_t)reply.readInt32(); + *ioHandle = (audio_io_handle_t)reply.readInt32(); + *device = (audio_devices_t)reply.readInt32(); + } + return status; + } + + virtual status_t releaseSoundTriggerSession(audio_session_t session) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32(session); + status_t status = remote()->transact(RELEASE_SOUNDTRIGGER_SESSION, data, &reply); + if (status != NO_ERROR) { + return status; + } + return (status_t)reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -984,6 +1021,7 @@ status_t BnAudioPolicyService::onTransact( reply->writeInt32(status); return NO_ERROR; } + case REGISTER_CLIENT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); sp client = interface_cast( @@ -992,6 +1030,33 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } break; + case ACQUIRE_SOUNDTRIGGER_SESSION: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + sp client = interface_cast( + data.readStrongBinder()); + audio_session_t session; + audio_io_handle_t ioHandle; + audio_devices_t device; + status_t status = acquireSoundTriggerSession(&session, &ioHandle, &device); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->writeInt32(session); + reply->writeInt32(ioHandle); + reply->writeInt32(device); + } + return NO_ERROR; + } break; + + case RELEASE_SOUNDTRIGGER_SESSION: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + sp client = interface_cast( + data.readStrongBinder()); + audio_session_t session = (audio_session_t)data.readInt32(); + status_t status = releaseSoundTriggerSession(session); + reply->writeInt32(status); + return NO_ERROR; + } break; + default: return BBinder::onTransact(code, data, reply, flags); } -- cgit v1.1 From b97cc6a9a3c81215e365c61b071a932073b56ff2 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Fri, 1 Aug 2014 15:14:14 -0700 Subject: AAC encoder: add support for SBR mode selection Change-Id: Ibc07bff7710398929c135f38324dd29857fa0ea6 --- media/libstagefright/ACodec.cpp | 34 +++++++++- .../codecs/aacenc/SoftAACEncoder2.cpp | 79 +++++++++++++++++++++- .../libstagefright/codecs/aacenc/SoftAACEncoder2.h | 2 + 3 files changed, 110 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 5b6e59e..b81674d 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -1289,16 +1289,20 @@ status_t ACodec::configureCodec( err = INVALID_OPERATION; } else { int32_t isADTS, aacProfile; + int32_t sbrMode; if (!msg->findInt32("is-adts", &isADTS)) { isADTS = 0; } if (!msg->findInt32("aac-profile", &aacProfile)) { aacProfile = OMX_AUDIO_AACObjectNull; } + if (!msg->findInt32("aac-sbr-mode", &sbrMode)) { + sbrMode = -1; + } err = setupAACCodec( encoder, numChannels, sampleRate, bitRate, aacProfile, - isADTS != 0); + isADTS != 0, sbrMode); } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) { err = setupAMRCodec(encoder, false /* isWAMR */, bitRate); @@ -1460,7 +1464,7 @@ status_t ACodec::selectAudioPortFormat( status_t ACodec::setupAACCodec( bool encoder, int32_t numChannels, int32_t sampleRate, - int32_t bitRate, int32_t aacProfile, bool isADTS) { + int32_t bitRate, int32_t aacProfile, bool isADTS, int32_t sbrMode) { if (encoder && isADTS) { return -EINVAL; } @@ -1527,6 +1531,32 @@ status_t ACodec::setupAACCodec( profile.nAACERtools = OMX_AUDIO_AACERNone; profile.eAACProfile = (OMX_AUDIO_AACPROFILETYPE) aacProfile; profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF; + switch (sbrMode) { + case 0: + // disable sbr + profile.nAACtools &= ~OMX_AUDIO_AACToolAndroidSSBR; + profile.nAACtools &= ~OMX_AUDIO_AACToolAndroidDSBR; + break; + case 1: + // enable single-rate sbr + profile.nAACtools |= OMX_AUDIO_AACToolAndroidSSBR; + profile.nAACtools &= ~OMX_AUDIO_AACToolAndroidDSBR; + break; + case 2: + // enable dual-rate sbr + profile.nAACtools &= ~OMX_AUDIO_AACToolAndroidSSBR; + profile.nAACtools |= OMX_AUDIO_AACToolAndroidDSBR; + break; + case -1: + // enable both modes -> the codec will decide which mode should be used + profile.nAACtools |= OMX_AUDIO_AACToolAndroidSSBR; + profile.nAACtools |= OMX_AUDIO_AACToolAndroidDSBR; + break; + default: + // unsupported sbr mode + return BAD_VALUE; + } + err = mOMX->setParameter( mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp index 6093621..35aa883 100644 --- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp +++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp @@ -19,6 +19,7 @@ #include #include "SoftAACEncoder2.h" +#include #include #include @@ -44,6 +45,8 @@ SoftAACEncoder2::SoftAACEncoder2( mNumChannels(1), mSampleRate(44100), mBitRate(0), + mSBRMode(-1), + mSBRRatio(0), mAACProfile(OMX_AUDIO_AACObjectLC), mSentCodecSpecificData(false), mInputSize(0), @@ -156,6 +159,41 @@ OMX_ERRORTYPE SoftAACEncoder2::internalGetParameter( aacParams->nSampleRate = mSampleRate; aacParams->nFrameLength = 0; + switch (mSBRMode) { + case 1: // sbr on + switch (mSBRRatio) { + case 0: + // set both OMX AAC tool flags + aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidSSBR; + aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidDSBR; + break; + case 1: + // set single-rate SBR active + aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidSSBR; + aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidDSBR; + break; + case 2: + // set dual-rate SBR active + aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidSSBR; + aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidDSBR; + break; + default: + ALOGE("invalid SBR ratio %d", mSBRRatio); + TRESPASS(); + } + break; + case 0: // sbr off + case -1: // sbr undefined + aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidSSBR; + aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidDSBR; + break; + default: + ALOGE("invalid SBR mode %d", mSBRMode); + TRESPASS(); + } + + + return OMX_ErrorNone; } @@ -243,6 +281,23 @@ OMX_ERRORTYPE SoftAACEncoder2::internalSetParameter( mAACProfile = aacParams->eAACProfile; } + if (!(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidSSBR) + && !(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidDSBR)) { + mSBRMode = 0; + mSBRRatio = 0; + } else if ((aacParams->nAACtools & OMX_AUDIO_AACToolAndroidSSBR) + && !(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidDSBR)) { + mSBRMode = 1; + mSBRRatio = 1; + } else if (!(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidSSBR) + && (aacParams->nAACtools & OMX_AUDIO_AACToolAndroidDSBR)) { + mSBRMode = 1; + mSBRRatio = 2; + } else { + mSBRMode = -1; // codec default sbr mode + mSBRRatio = 0; + } + if (setAudioParams() != OK) { return OMX_ErrorUndefined; } @@ -305,11 +360,11 @@ static AUDIO_OBJECT_TYPE getAOTFromProfile(OMX_U32 profile) { } status_t SoftAACEncoder2::setAudioParams() { - // We call this whenever sample rate, number of channels or bitrate change + // We call this whenever sample rate, number of channels, bitrate or SBR mode change // in reponse to setParameter calls. - ALOGV("setAudioParams: %u Hz, %u channels, %u bps", - mSampleRate, mNumChannels, mBitRate); + ALOGV("setAudioParams: %u Hz, %u channels, %u bps, %i sbr mode, %i sbr ratio", + mSampleRate, mNumChannels, mBitRate, mSBRMode, mSBRRatio); if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_AOT, getAOTFromProfile(mAACProfile))) { @@ -335,6 +390,24 @@ status_t SoftAACEncoder2::setAudioParams() { return UNKNOWN_ERROR; } + if (mSBRMode != -1 && mAACProfile == OMX_AUDIO_AACObjectELD) { + if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_MODE, mSBRMode)) { + ALOGE("Failed to set AAC encoder parameters"); + return UNKNOWN_ERROR; + } + } + + /* SBR ratio parameter configurations: + 0: Default configuration wherein SBR ratio is configured depending on audio object type by + the FDK. + 1: Downsampled SBR (default for ELD) + 2: Dualrate SBR (default for HE-AAC) + */ + if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_RATIO, mSBRRatio)) { + ALOGE("Failed to set AAC encoder parameters"); + return UNKNOWN_ERROR; + } + return OK; } diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h index 2603f4f..bce9c24 100644 --- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h +++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h @@ -53,6 +53,8 @@ private: OMX_U32 mNumChannels; OMX_U32 mSampleRate; OMX_U32 mBitRate; + OMX_S32 mSBRMode; + OMX_S32 mSBRRatio; OMX_U32 mAACProfile; bool mSentCodecSpecificData; -- cgit v1.1 From 69a85b792c31033a99c8858e3b1a3c2ea68b6278 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Mon, 4 Aug 2014 18:32:43 -0700 Subject: NuPlayer: don't feed decoder input data during flushing. Bug: 14955925 Bug: 16303659 Bug: 16467066 Change-Id: I7c258b986ae711357bd7e636b79853f8f3959d32 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 58d0138..0e015b0 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1169,11 +1169,11 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { sp reply; CHECK(msg->findMessage("reply", &reply)); - if ((audio && IsFlushingState(mFlushingAudio)) - || (!audio && IsFlushingState(mFlushingVideo))) { - reply->setInt32("err", INFO_DISCONTINUITY); - reply->post(); - return OK; + if ((audio && mFlushingAudio != NONE + && mFlushingAudio != AWAITING_DISCONTINUITY) + || (!audio && mFlushingVideo != NONE + && mFlushingVideo != AWAITING_DISCONTINUITY)) { + return -EWOULDBLOCK; } sp accessUnit; -- cgit v1.1 From 93c3d41bdb15e39dac0faea9c5b60f1637cd477c Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 1 Aug 2014 14:48:35 -0700 Subject: AudioSystem: add API to query audio HW sync source Add a method to query from the audio HAL the HW sync source used for a given audio session. Modify audio policy to select a direct output with HW sync when requested. Bug: 16132368. Change-Id: I03038f9188f2d389f8a5fd76a671854013a4513e --- media/libmedia/AudioSystem.cpp | 7 +++++++ media/libmedia/IAudioFlinger.cpp | 19 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 172b056..3486d21 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -450,6 +450,13 @@ void AudioSystem::releaseAudioSessionId(int audioSession, pid_t pid) } } +audio_hw_sync_t AudioSystem::getAudioHwSyncForSession(audio_session_t sessionId) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return AUDIO_HW_SYNC_INVALID; + return af->getAudioHwSyncForSession(sessionId); +} + // --------------------------------------------------------------------------- void AudioSystem::AudioFlingerClient::binderDied(const wp& who __unused) diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 5331fce..346a192 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -79,7 +79,8 @@ enum { CREATE_AUDIO_PATCH, RELEASE_AUDIO_PATCH, LIST_AUDIO_PATCHES, - SET_AUDIO_PORT_CONFIG + SET_AUDIO_PORT_CONFIG, + GET_AUDIO_HW_SYNC }; class BpAudioFlinger : public BpInterface @@ -883,6 +884,17 @@ public: } return status; } + virtual audio_hw_sync_t getAudioHwSyncForSession(audio_session_t sessionId) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(sessionId); + status_t status = remote()->transact(GET_AUDIO_HW_SYNC, data, &reply); + if (status != NO_ERROR) { + return AUDIO_HW_SYNC_INVALID; + } + return (audio_hw_sync_t)reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger"); @@ -1345,6 +1357,11 @@ status_t BnAudioFlinger::onTransact( reply->writeInt32(status); return NO_ERROR; } break; + case GET_AUDIO_HW_SYNC: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32(getAudioHwSyncForSession((audio_session_t)data.readInt32())); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } -- cgit v1.1 From 309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Tue, 29 Jul 2014 18:34:36 -0700 Subject: httplive: timestamp reporting, track selection Bug: 15153976 Bug: 15763638 Bug: 16351654 Change-Id: I4462276d4b7342647286a0ca4be11692ce52ff6d --- .../nuplayer/GenericSource.cpp | 2 +- media/libstagefright/httplive/LiveSession.cpp | 279 ++++++++++++++---- media/libstagefright/httplive/LiveSession.h | 24 +- media/libstagefright/httplive/M3UParser.cpp | 39 ++- media/libstagefright/httplive/M3UParser.h | 4 + media/libstagefright/httplive/PlaylistFetcher.cpp | 322 ++++++++++++++------- media/libstagefright/httplive/PlaylistFetcher.h | 25 +- media/libstagefright/mpeg2ts/ATSParser.cpp | 6 + .../libstagefright/mpeg2ts/AnotherPacketSource.cpp | 21 +- media/libstagefright/mpeg2ts/AnotherPacketSource.h | 4 +- 10 files changed, 546 insertions(+), 180 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 2f5b0f1..ebc3d08 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -308,7 +308,7 @@ void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { int64_t timeUs, actualTimeUs; const bool formatChange = true; - sp latestMeta = track->mPackets->getLatestMeta(); + sp latestMeta = track->mPackets->getLatestEnqueuedMeta(); CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs)); readBuffer(trackType, timeUs, &actualTimeUs, formatChange); readBuffer(counterpartType, -1, NULL, formatChange); diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 10cdde2..8667a6b 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -57,7 +57,7 @@ LiveSession::LiveSession( mHTTPService(httpService), mInPreparationPhase(true), mHTTPDataSource(new MediaHTTP(mHTTPService->makeHTTPConnection())), - mPrevBandwidthIndex(-1), + mCurBandwidthIndex(-1), mStreamMask(0), mNewStreamMask(0), mSwapMask(0), @@ -68,13 +68,17 @@ LiveSession::LiveSession( mReconfigurationInProgress(false), mSwitchInProgress(false), mDisconnectReplyID(0), - mSeekReplyID(0) { + mSeekReplyID(0), + mFirstTimeUsValid(false), + mFirstTimeUs(0), + mLastSeekTimeUs(0) { mStreams[kAudioIndex] = StreamItem("audio"); mStreams[kVideoIndex] = StreamItem("video"); mStreams[kSubtitleIndex] = StreamItem("subtitles"); for (size_t i = 0; i < kMaxStreams; ++i) { + mDiscontinuities.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); mPacketSources.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); mPacketSources2.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); } @@ -109,31 +113,65 @@ status_t LiveSession::dequeueAccessUnit( return -EWOULDBLOCK; } + status_t finalResult; + sp discontinuityQueue = mDiscontinuities.valueFor(stream); + if (discontinuityQueue->hasBufferAvailable(&finalResult)) { + discontinuityQueue->dequeueAccessUnit(accessUnit); + // seeking, track switching + sp extra; + int64_t timeUs; + if ((*accessUnit)->meta()->findMessage("extra", &extra) + && extra != NULL + && extra->findInt64("timeUs", &timeUs)) { + // seeking only + mLastSeekTimeUs = timeUs; + mDiscontinuityOffsetTimesUs.clear(); + mDiscontinuityAbsStartTimesUs.clear(); + } + return INFO_DISCONTINUITY; + } + sp packetSource = mPacketSources.valueFor(stream); - status_t finalResult; if (!packetSource->hasBufferAvailable(&finalResult)) { return finalResult == OK ? -EAGAIN : finalResult; } + // wait for counterpart + sp otherSource; + if (stream == STREAMTYPE_AUDIO && (mStreamMask & STREAMTYPE_VIDEO)) { + otherSource = mPacketSources.valueFor(STREAMTYPE_VIDEO); + } else if (stream == STREAMTYPE_VIDEO && (mStreamMask & STREAMTYPE_AUDIO)) { + otherSource = mPacketSources.valueFor(STREAMTYPE_AUDIO); + } + if (otherSource != NULL && !otherSource->hasBufferAvailable(&finalResult)) { + return finalResult == OK ? -EAGAIN : finalResult; + } + status_t err = packetSource->dequeueAccessUnit(accessUnit); + size_t streamIdx; const char *streamStr; switch (stream) { case STREAMTYPE_AUDIO: + streamIdx = kAudioIndex; streamStr = "audio"; break; case STREAMTYPE_VIDEO: + streamIdx = kVideoIndex; streamStr = "video"; break; case STREAMTYPE_SUBTITLES: + streamIdx = kSubtitleIndex; streamStr = "subs"; break; default: TRESPASS(); } + StreamItem& strm = mStreams[streamIdx]; if (err == INFO_DISCONTINUITY) { + // adaptive streaming, discontinuities in the playlist int32_t type; CHECK((*accessUnit)->meta()->findInt32("discontinuity", &type)); @@ -148,10 +186,7 @@ status_t LiveSession::dequeueAccessUnit( extra == NULL ? "NULL" : extra->debugString().c_str()); int32_t swap; - if (type == ATSParser::DISCONTINUITY_FORMATCHANGE - && (*accessUnit)->meta()->findInt32("swapPacketSource", &swap) - && swap) { - + if ((*accessUnit)->meta()->findInt32("swapPacketSource", &swap) && swap) { int32_t switchGeneration; CHECK((*accessUnit)->meta()->findInt32("switchGeneration", &switchGeneration)); { @@ -164,13 +199,67 @@ status_t LiveSession::dequeueAccessUnit( msg->post(); } } + } else { + size_t seq = strm.mCurDiscontinuitySeq; + int64_t offsetTimeUs; + if (mDiscontinuityOffsetTimesUs.indexOfKey(seq) >= 0) { + offsetTimeUs = mDiscontinuityOffsetTimesUs.valueFor(seq); + } else { + offsetTimeUs = 0; + } + + seq += 1; + if (mDiscontinuityAbsStartTimesUs.indexOfKey(strm.mCurDiscontinuitySeq) >= 0) { + int64_t firstTimeUs; + firstTimeUs = mDiscontinuityAbsStartTimesUs.valueFor(strm.mCurDiscontinuitySeq); + offsetTimeUs += strm.mLastDequeuedTimeUs - firstTimeUs; + offsetTimeUs += strm.mLastSampleDurationUs; + } else { + offsetTimeUs += strm.mLastSampleDurationUs; + } + + mDiscontinuityOffsetTimesUs.add(seq, offsetTimeUs); } } else if (err == OK) { + if (stream == STREAMTYPE_AUDIO || stream == STREAMTYPE_VIDEO) { int64_t timeUs; + int32_t discontinuitySeq = 0; CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); - ALOGV("[%s] read buffer at time %" PRId64 " us", streamStr, timeUs); + (*accessUnit)->meta()->findInt32("discontinuitySeq", &discontinuitySeq); + strm.mCurDiscontinuitySeq = discontinuitySeq; + + int32_t discard = 0; + int64_t firstTimeUs; + if (mDiscontinuityAbsStartTimesUs.indexOfKey(strm.mCurDiscontinuitySeq) >= 0) { + int64_t durUs; // approximate sample duration + if (timeUs > strm.mLastDequeuedTimeUs) { + durUs = timeUs - strm.mLastDequeuedTimeUs; + } else { + durUs = strm.mLastDequeuedTimeUs - timeUs; + } + strm.mLastSampleDurationUs = durUs; + firstTimeUs = mDiscontinuityAbsStartTimesUs.valueFor(strm.mCurDiscontinuitySeq); + } else if ((*accessUnit)->meta()->findInt32("discard", &discard) && discard) { + firstTimeUs = timeUs; + } else { + mDiscontinuityAbsStartTimesUs.add(strm.mCurDiscontinuitySeq, timeUs); + firstTimeUs = timeUs; + } + + strm.mLastDequeuedTimeUs = timeUs; + if (timeUs >= firstTimeUs) { + timeUs -= firstTimeUs; + } else { + timeUs = 0; + } + timeUs += mLastSeekTimeUs; + if (mDiscontinuityOffsetTimesUs.indexOfKey(discontinuitySeq) >= 0) { + timeUs += mDiscontinuityOffsetTimesUs.valueFor(discontinuitySeq); + } + ALOGV("[%s] read buffer at time %" PRId64 " us", streamStr, timeUs); + (*accessUnit)->meta()->setInt64("timeUs", timeUs); mLastDequeuedTimeUs = timeUs; mRealTimeBaseUs = ALooper::GetNowUs() - timeUs; } else if (stream == STREAMTYPE_SUBTITLES) { @@ -289,7 +378,9 @@ void LiveSession::onMessageReceived(const sp &msg) { break; } - tryToFinishBandwidthSwitch(); + if (mSwitchInProgress) { + tryToFinishBandwidthSwitch(); + } } if (mContinuation != NULL) { @@ -538,8 +629,9 @@ void LiveSession::onConnect(const sp &msg) { mBandwidthItems.push(item); } + mPlaylist->pickRandomMediaItems(); changeConfiguration( - 0ll /* timeUs */, initialBandwidthIndex, true /* pickTrack */); + 0ll /* timeUs */, initialBandwidthIndex, false /* pickTrack */); } void LiveSession::finishDisconnect() { @@ -847,20 +939,20 @@ size_t LiveSession::getBandwidthIndex() { // to lowest) const size_t kMinIndex = 0; - static ssize_t mPrevBandwidthIndex = -1; + static ssize_t mCurBandwidthIndex = -1; size_t index; - if (mPrevBandwidthIndex < 0) { + if (mCurBandwidthIndex < 0) { index = kMinIndex; } else if (uniformRand() < 0.5) { - index = (size_t)mPrevBandwidthIndex; + index = (size_t)mCurBandwidthIndex; } else { - index = mPrevBandwidthIndex + 1; + index = mCurBandwidthIndex + 1; if (index == mBandwidthItems.size()) { index = kMinIndex; } } - mPrevBandwidthIndex = index; + mCurBandwidthIndex = index; #elif 0 // Pick the highest bandwidth stream below or equal to 1.2 Mbit/sec @@ -937,7 +1029,10 @@ sp LiveSession::getTrackInfo(size_t trackIndex) const { status_t LiveSession::selectTrack(size_t index, bool select) { status_t err = mPlaylist->selectTrack(index, select); if (err == OK) { - (new AMessage(kWhatChangeConfiguration, id()))->post(); + sp msg = new AMessage(kWhatChangeConfiguration, id()); + msg->setInt32("bandwidthIndex", mCurBandwidthIndex); + msg->setInt32("pickTrack", select); + msg->post(); } return err; } @@ -964,15 +1059,11 @@ void LiveSession::changeConfiguration( CHECK(!mReconfigurationInProgress); mReconfigurationInProgress = true; - mPrevBandwidthIndex = bandwidthIndex; + mCurBandwidthIndex = bandwidthIndex; ALOGV("changeConfiguration => timeUs:%" PRId64 " us, bwIndex:%zu, pickTrack:%d", timeUs, bandwidthIndex, pickTrack); - if (pickTrack) { - mPlaylist->pickRandomMediaItems(); - } - CHECK_LT(bandwidthIndex, mBandwidthItems.size()); const BandwidthItem &item = mBandwidthItems.itemAt(bandwidthIndex); @@ -995,14 +1086,15 @@ void LiveSession::changeConfiguration( // If we're seeking all current fetchers are discarded. if (timeUs < 0ll) { - // delay fetcher removal - discardFetcher = false; + // delay fetcher removal if not picking tracks + discardFetcher = pickTrack; for (size_t j = 0; j < kMaxStreams; ++j) { StreamType type = indexToType(j); if ((streamMask & type) && uri == URIs[j]) { resumeMask |= type; streamMask &= ~type; + discardFetcher = false; } } } @@ -1016,16 +1108,17 @@ void LiveSession::changeConfiguration( sp msg; if (timeUs < 0ll) { - // skip onChangeConfiguration2 (decoder destruction) if switching. + // skip onChangeConfiguration2 (decoder destruction) if not seeking. msg = new AMessage(kWhatChangeConfiguration3, id()); } else { msg = new AMessage(kWhatChangeConfiguration2, id()); } msg->setInt32("streamMask", streamMask); msg->setInt32("resumeMask", resumeMask); + msg->setInt32("pickTrack", pickTrack); msg->setInt64("timeUs", timeUs); for (size_t i = 0; i < kMaxStreams; ++i) { - if (streamMask & indexToType(i)) { + if ((streamMask | resumeMask) & indexToType(i)) { msg->setString(mStreams[i].uriKey().c_str(), URIs[i].c_str()); } } @@ -1049,7 +1142,10 @@ void LiveSession::changeConfiguration( void LiveSession::onChangeConfiguration(const sp &msg) { if (!mReconfigurationInProgress) { - changeConfiguration(-1ll /* timeUs */, getBandwidthIndex()); + int32_t pickTrack = 0, bandwidthIndex = mCurBandwidthIndex; + msg->findInt32("pickTrack", &pickTrack); + msg->findInt32("bandwidthIndex", &bandwidthIndex); + changeConfiguration(-1ll /* timeUs */, bandwidthIndex, pickTrack); } else { msg->post(1000000ll); // retry in 1 sec } @@ -1060,8 +1156,14 @@ void LiveSession::onChangeConfiguration2(const sp &msg) { // All fetchers are either suspended or have been removed now. - uint32_t streamMask; + uint32_t streamMask, resumeMask; CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask)); + CHECK(msg->findInt32("resumeMask", (int32_t *)&resumeMask)); + + // currently onChangeConfiguration2 is only called for seeking; + // remove the following CHECK if using it else where. + CHECK_EQ(resumeMask, 0); + streamMask |= resumeMask; AString URIs[kMaxStreams]; for (size_t i = 0; i < kMaxStreams; ++i) { @@ -1125,16 +1227,21 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { } int64_t timeUs; + int32_t pickTrack; bool switching = false; CHECK(msg->findInt64("timeUs", &timeUs)); + CHECK(msg->findInt32("pickTrack", &pickTrack)); if (timeUs < 0ll) { - timeUs = mLastDequeuedTimeUs; - switching = true; + if (!pickTrack) { + switching = true; + } + mRealTimeBaseUs = ALooper::GetNowUs() - mLastDequeuedTimeUs; + } else { + mRealTimeBaseUs = ALooper::GetNowUs() - timeUs; } - mRealTimeBaseUs = ALooper::GetNowUs() - timeUs; - mNewStreamMask = streamMask; + mNewStreamMask = streamMask | resumeMask; // Of all existing fetchers: // * Resume fetchers that are still needed and assign them original packet sources. @@ -1147,6 +1254,16 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { for (size_t j = 0; j < kMaxStreams; ++j) { if ((resumeMask & indexToType(j)) && uri == mStreams[j].mUri) { sources[j] = mPacketSources.valueFor(indexToType(j)); + + if (j != kSubtitleIndex) { + ALOGV("queueing dummy discontinuity for stream type %d", indexToType(j)); + sp discontinuityQueue; + discontinuityQueue = mDiscontinuities.valueFor(indexToType(j)); + discontinuityQueue->queueDiscontinuity( + ATSParser::DISCONTINUITY_NONE, + NULL, + true); + } } } @@ -1180,7 +1297,9 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { CHECK(fetcher != NULL); int32_t latestSeq = -1; - int64_t latestTimeUs = 0ll; + int64_t startTimeUs = -1; + int64_t segmentStartTimeUs = -1ll; + int32_t discontinuitySeq = -1; sp sources[kMaxStreams]; // TRICKY: looping from i as earlier streams are already removed from streamMask @@ -1188,29 +1307,65 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) { sources[j] = mPacketSources.valueFor(indexToType(j)); - if (!switching) { + if (timeUs >= 0) { sources[j]->clear(); + startTimeUs = timeUs; + + sp discontinuityQueue; + sp extra = new AMessage; + extra->setInt64("timeUs", timeUs); + discontinuityQueue = mDiscontinuities.valueFor(indexToType(j)); + discontinuityQueue->queueDiscontinuity( + ATSParser::DISCONTINUITY_SEEK, extra, true); } else { - int32_t type, seq; - int64_t srcTimeUs; - sp meta = sources[j]->getLatestMeta(); + int32_t type; + int64_t srcSegmentStartTimeUs; + sp meta; + if (pickTrack) { + // selecting + meta = sources[j]->getLatestDequeuedMeta(); + } else { + // adapting + meta = sources[j]->getLatestEnqueuedMeta(); + } if (meta != NULL && !meta->findInt32("discontinuity", &type)) { - CHECK(meta->findInt32("seq", &seq)); - if (seq > latestSeq) { - latestSeq = seq; + int64_t tmpUs; + CHECK(meta->findInt64("timeUs", &tmpUs)); + if (startTimeUs < 0 || tmpUs < startTimeUs) { + startTimeUs = tmpUs; + } + + CHECK(meta->findInt64("segmentStartTimeUs", &tmpUs)); + if (segmentStartTimeUs < 0 || tmpUs < segmentStartTimeUs) { + segmentStartTimeUs = tmpUs; } - CHECK(meta->findInt64("timeUs", &srcTimeUs)); - if (srcTimeUs > latestTimeUs) { - latestTimeUs = srcTimeUs; + + int32_t seq; + CHECK(meta->findInt32("discontinuitySeq", &seq)); + if (discontinuitySeq < 0 || seq < discontinuitySeq) { + discontinuitySeq = seq; } } - sources[j] = mPacketSources2.valueFor(indexToType(j)); - sources[j]->clear(); - uint32_t extraStreams = mNewStreamMask & (~mStreamMask); - if (extraStreams & indexToType(j)) { - sources[j]->queueAccessUnit(createFormatChangeBuffer(/* swap = */ false)); + if (pickTrack) { + // selecting track, queue discontinuities before content + sources[j]->clear(); + if (j == kSubtitleIndex) { + break; + } + sp discontinuityQueue; + discontinuityQueue = mDiscontinuities.valueFor(indexToType(j)); + discontinuityQueue->queueDiscontinuity( + ATSParser::DISCONTINUITY_FORMATCHANGE, NULL, true); + } else { + // adapting, queue discontinuities after resume + sources[j] = mPacketSources2.valueFor(indexToType(j)); + sources[j]->clear(); + uint32_t extraStreams = mNewStreamMask & (~mStreamMask); + if (extraStreams & indexToType(j)) { + sources[j]->queueAccessUnit(createFormatChangeBuffer(/*swap*/ false)); + } } } @@ -1222,9 +1377,10 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { sources[kAudioIndex], sources[kVideoIndex], sources[kSubtitleIndex], - timeUs, - latestTimeUs /* min start time(us) */, - latestSeq >= 0 ? latestSeq + 1 : -1 /* starting sequence number hint */ ); + startTimeUs < 0 ? mLastSeekTimeUs : startTimeUs, + segmentStartTimeUs, + discontinuitySeq, + switching); } // All fetchers have now been started, the configuration change @@ -1236,6 +1392,7 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { mReconfigurationInProgress = false; if (switching) { mSwitchInProgress = true; + mSwapMask = streamMask; } else { mStreamMask = mNewStreamMask; } @@ -1254,8 +1411,8 @@ void LiveSession::onSwapped(const sp &msg) { int32_t stream; CHECK(msg->findInt32("stream", &stream)); - mSwapMask |= stream; - if (mSwapMask != mStreamMask) { + mSwapMask &= ~stream; + if (mSwapMask != 0) { return; } @@ -1271,9 +1428,12 @@ void LiveSession::onSwapped(const sp &msg) { } // Mark switch done when: -// 1. all old buffers are swapped out, AND -// 2. all old fetchers are removed. +// 1. all old buffers are swapped out void LiveSession::tryToFinishBandwidthSwitch() { + if (!mSwitchInProgress) { + return; + } + bool needToRemoveFetchers = false; for (size_t i = 0; i < mFetcherInfos.size(); ++i) { if (mFetcherInfos.valueAt(i).mToBeRemoved) { @@ -1281,10 +1441,11 @@ void LiveSession::tryToFinishBandwidthSwitch() { break; } } - if (!needToRemoveFetchers && mSwapMask == mStreamMask) { + + if (!needToRemoveFetchers && mSwapMask == 0) { + ALOGI("mSwitchInProgress = false"); mStreamMask = mNewStreamMask; mSwitchInProgress = false; - mSwapMask = 0; } } @@ -1310,13 +1471,13 @@ bool LiveSession::canSwitchBandwidthTo(size_t bandwidthIndex) { return false; } - if (mPrevBandwidthIndex < 0) { + if (mCurBandwidthIndex < 0) { return true; } - if (bandwidthIndex == (size_t)mPrevBandwidthIndex) { + if (bandwidthIndex == (size_t)mCurBandwidthIndex) { return false; - } else if (bandwidthIndex > (size_t)mPrevBandwidthIndex) { + } else if (bandwidthIndex > (size_t)mCurBandwidthIndex) { return canSwitchUp(); } else { return true; diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index ed3818f..5423f0f 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -125,8 +125,19 @@ private: struct StreamItem { const char *mType; AString mUri; - StreamItem() : mType("") {} - StreamItem(const char *type) : mType(type) {} + size_t mCurDiscontinuitySeq; + int64_t mLastDequeuedTimeUs; + int64_t mLastSampleDurationUs; + StreamItem() + : mType(""), + mCurDiscontinuitySeq(0), + mLastDequeuedTimeUs(0), + mLastSampleDurationUs(0) {} + StreamItem(const char *type) + : mType(type), + mCurDiscontinuitySeq(0), + mLastDequeuedTimeUs(0), + mLastSampleDurationUs(0) {} AString uriKey() { AString key(mType); key.append("URI"); @@ -147,7 +158,7 @@ private: AString mMasterURL; Vector mBandwidthItems; - ssize_t mPrevBandwidthIndex; + ssize_t mCurBandwidthIndex; sp mPlaylist; @@ -163,6 +174,7 @@ private: // we use this to track reconfiguration progress. uint32_t mSwapMask; + KeyedVector > mDiscontinuities; KeyedVector > mPacketSources; // A second set of packet sources that buffer content for the variant we're switching to. KeyedVector > mPacketSources2; @@ -187,6 +199,12 @@ private: uint32_t mDisconnectReplyID; uint32_t mSeekReplyID; + bool mFirstTimeUsValid; + int64_t mFirstTimeUs; + int64_t mLastSeekTimeUs; + KeyedVector mDiscontinuityAbsStartTimesUs; + KeyedVector mDiscontinuityOffsetTimesUs; + sp addFetcher(const char *uri); void onConnect(const sp &msg); diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index efd852c..1651dee 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -157,8 +157,8 @@ void M3UParser::MediaGroup::pickRandomMediaItems() { } status_t M3UParser::MediaGroup::selectTrack(size_t index, bool select) { - if (mType != TYPE_SUBS) { - ALOGE("only select subtitile tracks for now!"); + if (mType != TYPE_SUBS && mType != TYPE_AUDIO) { + ALOGE("only select subtitile/audio tracks for now!"); return INVALID_OPERATION; } @@ -246,6 +246,7 @@ M3UParser::M3UParser( mIsVariantPlaylist(false), mIsComplete(false), mIsEvent(false), + mDiscontinuitySeq(0), mSelectedIndex(-1) { mInitCheck = parse(data, size); } @@ -273,6 +274,10 @@ bool M3UParser::isEvent() const { return mIsEvent; } +size_t M3UParser::getDiscontinuitySeq() const { + return mDiscontinuitySeq; +} + sp M3UParser::meta() { return mMeta; } @@ -567,6 +572,12 @@ status_t M3UParser::parse(const void *_data, size_t size) { } } else if (line.startsWith("#EXT-X-MEDIA")) { err = parseMedia(line); + } else if (line.startsWith("#EXT-X-DISCONTINUITY-SEQUENCE")) { + size_t seq; + err = parseDiscontinuitySequence(line, &seq); + if (err == OK) { + mDiscontinuitySeq = seq; + } } if (err != OK) { @@ -1110,6 +1121,30 @@ status_t M3UParser::parseMedia(const AString &line) { } // static +status_t M3UParser::parseDiscontinuitySequence(const AString &line, size_t *seq) { + ssize_t colonPos = line.find(":"); + + if (colonPos < 0) { + return ERROR_MALFORMED; + } + + int32_t x; + status_t err = ParseInt32(line.c_str() + colonPos + 1, &x); + if (err != OK) { + return err; + } + + if (x < 0) { + return ERROR_MALFORMED; + } + + if (seq) { + *seq = x; + } + return OK; +} + +// static status_t M3UParser::ParseInt32(const char *s, int32_t *x) { char *end; long lval = strtol(s, &end, 10); diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h index fe9fb9d..d588afe 100644 --- a/media/libstagefright/httplive/M3UParser.h +++ b/media/libstagefright/httplive/M3UParser.h @@ -34,6 +34,7 @@ struct M3UParser : public RefBase { bool isVariantPlaylist() const; bool isComplete() const; bool isEvent() const; + size_t getDiscontinuitySeq() const; sp meta(); @@ -66,6 +67,7 @@ private: bool mIsVariantPlaylist; bool mIsComplete; bool mIsEvent; + size_t mDiscontinuitySeq; sp mMeta; Vector mItems; @@ -94,6 +96,8 @@ private: status_t parseMedia(const AString &line); + static status_t parseDiscontinuitySequence(const AString &line, size_t *seq); + static status_t ParseInt32(const char *s, int32_t *x); static status_t ParseDouble(const char *s, double *x); diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 10437c9..80cb2d0 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -49,7 +49,7 @@ namespace android { // static const int64_t PlaylistFetcher::kMinBufferedDurationUs = 10000000ll; const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll; -const int32_t PlaylistFetcher::kDownloadBlockSize = 192; +const int32_t PlaylistFetcher::kDownloadBlockSize = 2048; const int32_t PlaylistFetcher::kNumSkipFrames = 10; PlaylistFetcher::PlaylistFetcher( @@ -62,19 +62,21 @@ PlaylistFetcher::PlaylistFetcher( mURI(uri), mStreamTypeMask(0), mStartTimeUs(-1ll), - mMinStartTimeUs(0ll), - mStopParams(NULL), + mSegmentStartTimeUs(-1ll), + mDiscontinuitySeq(-1ll), + mStartTimeUsRelative(false), mLastPlaylistFetchTimeUs(-1ll), mSeqNumber(-1), mNumRetries(0), mStartup(true), + mAdaptive(false), mPrepared(false), - mSkipToFirstIDRAfterConnect(false), mNextPTSTimeUs(-1ll), mMonitorQueueGeneration(0), mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY), mFirstPTSValid(false), - mAbsoluteTimeAnchorUs(0ll) { + mAbsoluteTimeAnchorUs(0ll), + mVideoBuffer(new AnotherPacketSource(NULL)) { memset(mPlaylistHash, 0, sizeof(mPlaylistHash)); mStartTimeUsNotify->setInt32("what", kWhatStartedAt); mStartTimeUsNotify->setInt32("streamMask", 0); @@ -335,8 +337,9 @@ void PlaylistFetcher::startAsync( const sp &videoSource, const sp &subtitleSource, int64_t startTimeUs, - int64_t minStartTimeUs, - int32_t startSeqNumberHint) { + int64_t segmentStartTimeUs, + int32_t startDiscontinuitySeq, + bool adaptive) { sp msg = new AMessage(kWhatStart, id()); uint32_t streamTypeMask = 0ul; @@ -358,8 +361,9 @@ void PlaylistFetcher::startAsync( msg->setInt32("streamTypeMask", streamTypeMask); msg->setInt64("startTimeUs", startTimeUs); - msg->setInt64("minStartTimeUs", minStartTimeUs); - msg->setInt32("startSeqNumberHint", startSeqNumberHint); + msg->setInt64("segmentStartTimeUs", segmentStartTimeUs); + msg->setInt32("startDiscontinuitySeq", startDiscontinuitySeq); + msg->setInt32("adaptive", adaptive); msg->post(); } @@ -367,9 +371,9 @@ void PlaylistFetcher::pauseAsync() { (new AMessage(kWhatPause, id()))->post(); } -void PlaylistFetcher::stopAsync(bool selfTriggered) { +void PlaylistFetcher::stopAsync(bool clear) { sp msg = new AMessage(kWhatStop, id()); - msg->setInt32("selfTriggered", selfTriggered); + msg->setInt32("clear", clear); msg->post(); } @@ -449,10 +453,13 @@ status_t PlaylistFetcher::onStart(const sp &msg) { CHECK(msg->findInt32("streamTypeMask", (int32_t *)&streamTypeMask)); int64_t startTimeUs; - int32_t startSeqNumberHint; + int64_t segmentStartTimeUs; + int32_t startDiscontinuitySeq; + int32_t adaptive; CHECK(msg->findInt64("startTimeUs", &startTimeUs)); - CHECK(msg->findInt64("minStartTimeUs", (int64_t *) &mMinStartTimeUs)); - CHECK(msg->findInt32("startSeqNumberHint", &startSeqNumberHint)); + CHECK(msg->findInt64("segmentStartTimeUs", &segmentStartTimeUs)); + CHECK(msg->findInt32("startDiscontinuitySeq", &startDiscontinuitySeq)); + CHECK(msg->findInt32("adaptive", &adaptive)); if (streamTypeMask & LiveSession::STREAMTYPE_AUDIO) { void *ptr; @@ -482,16 +489,16 @@ status_t PlaylistFetcher::onStart(const sp &msg) { } mStreamTypeMask = streamTypeMask; + mStartTimeUs = startTimeUs; + mSegmentStartTimeUs = segmentStartTimeUs; + mDiscontinuitySeq = startDiscontinuitySeq; if (mStartTimeUs >= 0ll) { mSeqNumber = -1; mStartup = true; mPrepared = false; - } - - if (startSeqNumberHint >= 0) { - mSeqNumber = startSeqNumberHint; + mAdaptive = adaptive; } postMonitorQueue(); @@ -506,11 +513,9 @@ void PlaylistFetcher::onPause() { void PlaylistFetcher::onStop(const sp &msg) { cancelMonitorQueue(); - int32_t selfTriggered; - CHECK(msg->findInt32("selfTriggered", &selfTriggered)); - if (!selfTriggered) { - // Self triggered stops only happen during switching, in which case we do not want - // to clear the discontinuities queued at the end of packet sources. + int32_t clear; + CHECK(msg->findInt32("clear", &clear)); + if (clear) { for (size_t i = 0; i < mPacketSources.size(); i++) { sp packetSource = mPacketSources.valueAt(i); packetSource->clear(); @@ -552,15 +557,16 @@ status_t PlaylistFetcher::onResumeUntil(const sp &msg) { } // Don't resume if we would stop within a resume threshold. + int32_t discontinuitySeq; int64_t latestTimeUs = 0, stopTimeUs = 0; - sp latestMeta = packetSource->getLatestMeta(); + sp latestMeta = packetSource->getLatestDequeuedMeta(); if (latestMeta != NULL - && (latestMeta->findInt64("timeUs", &latestTimeUs) - && params->findInt64(stopKey, &stopTimeUs))) { - int64_t diffUs = stopTimeUs - latestTimeUs; - if (diffUs < resumeThreshold(latestMeta)) { - stop = true; - } + && latestMeta->findInt32("discontinuitySeq", &discontinuitySeq) + && discontinuitySeq == mDiscontinuitySeq + && latestMeta->findInt64("timeUs", &latestTimeUs) + && params->findInt64(stopKey, &stopTimeUs) + && stopTimeUs - latestTimeUs < resumeThreshold(latestMeta)) { + stop = true; } } @@ -568,7 +574,7 @@ status_t PlaylistFetcher::onResumeUntil(const sp &msg) { for (size_t i = 0; i < mPacketSources.size(); i++) { mPacketSources.valueAt(i)->queueAccessUnit(mSession->createFormatChangeBuffer()); } - stopAsync(/* selfTriggered = */ true); + stopAsync(/* clear = */ false); return OK; } @@ -737,26 +743,47 @@ void PlaylistFetcher::onDownloadNext() { mSeqNumber = lastSeqNumberInPlaylist; } + if (mDiscontinuitySeq < 0) { + mDiscontinuitySeq = mPlaylist->getDiscontinuitySeq(); + } + if (mSeqNumber < 0) { CHECK_GE(mStartTimeUs, 0ll); - if (mPlaylist->isComplete() || mPlaylist->isEvent()) { - mSeqNumber = getSeqNumberForTime(mStartTimeUs); + if (mSegmentStartTimeUs < 0) { + if (!mPlaylist->isComplete() && !mPlaylist->isEvent()) { + // If this is a live session, start 3 segments from the end on connect + mSeqNumber = lastSeqNumberInPlaylist - 3; + } else { + mSeqNumber = getSeqNumberForTime(mStartTimeUs); + mStartTimeUs -= getSegmentStartTimeUs(mSeqNumber); + } + mStartTimeUsRelative = true; ALOGV("Initial sequence number for time %" PRId64 " is %d from (%d .. %d)", mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist); } else { - // If this is a live session, start 3 segments from the end. - mSeqNumber = lastSeqNumberInPlaylist - 3; + mSeqNumber = getSeqNumberForTime(mSegmentStartTimeUs); + if (mAdaptive) { + // avoid double fetch/decode + mSeqNumber += 1; + } + ssize_t minSeq = getSeqNumberForDiscontinuity(mDiscontinuitySeq); + if (mSeqNumber < minSeq) { + mSeqNumber = minSeq; + } + if (mSeqNumber < firstSeqNumberInPlaylist) { mSeqNumber = firstSeqNumberInPlaylist; } + + if (mSeqNumber > lastSeqNumberInPlaylist) { + mSeqNumber = lastSeqNumberInPlaylist; + } ALOGV("Initial sequence number for live event %d from (%d .. %d)", mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist); } - - mStartTimeUs = -1ll; } if (mSeqNumber < firstSeqNumberInPlaylist @@ -819,6 +846,7 @@ void PlaylistFetcher::onDownloadNext() { int32_t val; if (itemMeta->findInt32("discontinuity", &val) && val != 0) { + mDiscontinuitySeq++; discontinuity = true; } @@ -850,6 +878,7 @@ void PlaylistFetcher::onDownloadNext() { } // block-wise download + bool startup = mStartup; ssize_t bytesRead; do { bytesRead = mSession->fetchFile( @@ -879,7 +908,7 @@ void PlaylistFetcher::onDownloadNext() { return; } - if (mStartup || discontinuity) { + if (startup || discontinuity) { // Signal discontinuity. if (mPlaylist->isComplete() || mPlaylist->isEvent()) { @@ -898,6 +927,8 @@ void PlaylistFetcher::onDownloadNext() { discontinuity = false; } + + startup = false; } err = OK; @@ -917,24 +948,19 @@ void PlaylistFetcher::onDownloadNext() { } if (err == -EAGAIN) { - // bad starting sequence number hint + // starting sequence number too low mTSParser.clear(); postMonitorQueue(); return; - } - - if (err == ERROR_OUT_OF_RANGE) { + } else if (err == ERROR_OUT_OF_RANGE) { // reached stopping point - stopAsync(/* selfTriggered = */ true); + stopAsync(/* clear = */ false); return; - } - - if (err != OK) { + } else if (err != OK) { notifyError(err); return; } - mStartup = false; } while (bytesRead != 0); if (bufferStartsWithTsSyncByte(buffer)) { @@ -994,11 +1020,44 @@ void PlaylistFetcher::onDownloadNext() { return; } + mStartup = false; ++mSeqNumber; postMonitorQueue(); } +int32_t PlaylistFetcher::getSeqNumberForDiscontinuity(size_t discontinuitySeq) const { + int32_t firstSeqNumberInPlaylist; + if (mPlaylist->meta() == NULL + || !mPlaylist->meta()->findInt32("media-sequence", &firstSeqNumberInPlaylist)) { + firstSeqNumberInPlaylist = 0; + } + + size_t curDiscontinuitySeq = mPlaylist->getDiscontinuitySeq(); + if (discontinuitySeq < curDiscontinuitySeq) { + return firstSeqNumberInPlaylist <= 0 ? 0 : (firstSeqNumberInPlaylist - 1); + } + + size_t index = 0; + while (index < mPlaylist->size()) { + sp itemMeta; + CHECK(mPlaylist->itemAt( index, NULL /* uri */, &itemMeta)); + + int64_t discontinuity; + if (itemMeta->findInt64("discontinuity", &discontinuity)) { + curDiscontinuitySeq++; + } + + if (curDiscontinuitySeq == discontinuitySeq) { + return firstSeqNumberInPlaylist + index; + } + + ++index; + } + + return firstSeqNumberInPlaylist + mPlaylist->size(); +} + int32_t PlaylistFetcher::getSeqNumberForTime(int64_t timeUs) const { int32_t firstSeqNumberInPlaylist; if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32( @@ -1031,6 +1090,23 @@ int32_t PlaylistFetcher::getSeqNumberForTime(int64_t timeUs) const { return firstSeqNumberInPlaylist + index; } +const sp &PlaylistFetcher::setAccessUnitProperties( + const sp &accessUnit, const sp &source, bool discard) { + sp format = source->getFormat(); + if (format != NULL) { + // for simplicity, store a reference to the format in each unit + accessUnit->meta()->setObject("format", format); + } + + if (discard) { + accessUnit->meta()->setInt32("discard", discard); + } + + accessUnit->meta()->setInt32("discontinuitySeq", mDiscontinuitySeq); + accessUnit->meta()->setInt64("segmentStartTimeUs", getSegmentStartTimeUs(mSeqNumber)); + return accessUnit; +} + status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &buffer) { if (mTSParser == NULL) { // Use TS_TIMESTAMPS_ARE_ABSOLUTE so pts carry over between fetchers. @@ -1046,7 +1122,9 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu mTSParser->signalDiscontinuity( ATSParser::DISCONTINUITY_SEEK, extra); + mAbsoluteTimeAnchorUs = mNextPTSTimeUs; mNextPTSTimeUs = -1ll; + mFirstPTSValid = false; } size_t offset = 0; @@ -1099,46 +1177,30 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu continue; } - if (stream == LiveSession::STREAMTYPE_VIDEO && mVideoMime.empty()) { - const char *mime; - if (source->getFormat()->findCString(kKeyMIMEType, &mime)) { - mVideoMime.setTo(mime); - if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { - mSkipToFirstIDRAfterConnect = true; - } - } - } - int64_t timeUs; sp accessUnit; status_t finalResult; while (source->hasBufferAvailable(&finalResult) && source->dequeueAccessUnit(&accessUnit) == OK) { - if (stream == LiveSession::STREAMTYPE_VIDEO && mSkipToFirstIDRAfterConnect) { - if (!IsIDR(accessUnit)) { - continue; - } else { - mSkipToFirstIDRAfterConnect = false; - } - } - CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); - if (mMinStartTimeUs > 0) { - if (timeUs < mMinStartTimeUs) { - // TODO untested path - // try a later ts - int32_t targetDuration; - mPlaylist->meta()->findInt32("target-duration", &targetDuration); - int32_t incr = (mMinStartTimeUs - timeUs) / 1000000 / targetDuration; - if (incr == 0) { - // increment mSeqNumber by at least one - incr = 1; + + if (mStartup) { + if (!mFirstPTSValid) { + mFirstTimeUs = timeUs; + mFirstPTSValid = true; + } + if (mStartTimeUsRelative) { + timeUs -= mFirstTimeUs; + if (timeUs < 0) { + timeUs = 0; + } + } else if (mAdaptive && timeUs > mStartTimeUs) { + int32_t seq; + if (mStartTimeUsNotify != NULL + && !mStartTimeUsNotify->findInt32("discontinuitySeq", &seq)) { + mStartTimeUsNotify->setInt32("discontinuitySeq", mDiscontinuitySeq); } - mSeqNumber += incr; - err = -EAGAIN; - break; - } else { int64_t startTimeUs; if (mStartTimeUsNotify != NULL && !mStartTimeUsNotify->findInt64(key, &startTimeUs)) { @@ -1155,12 +1217,51 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu } } } + + if (timeUs < mStartTimeUs) { + if (mAdaptive) { + int32_t targetDuration; + mPlaylist->meta()->findInt32("target-duration", &targetDuration); + int32_t incr = (mStartTimeUs - timeUs) / 1000000 / targetDuration; + if (incr == 0) { + // increment mSeqNumber by at least one + incr = 1; + } + mSeqNumber += incr; + err = -EAGAIN; + break; + } else { + // buffer up to the closest preceding IDR frame + ALOGV("timeUs %" PRId64 " us < mStartTimeUs %" PRId64 " us", + timeUs, mStartTimeUs); + const char *mime; + sp format = source->getFormat(); + bool isAvc = false; + if (format != NULL && format->findCString(kKeyMIMEType, &mime) + && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { + isAvc = true; + } + if (isAvc && IsIDR(accessUnit)) { + mVideoBuffer->clear(); + } + if (isAvc) { + mVideoBuffer->queueAccessUnit(accessUnit); + } + + continue; + } + } } if (mStopParams != NULL) { // Queue discontinuity in original stream. + int32_t discontinuitySeq; int64_t stopTimeUs; - if (!mStopParams->findInt64(key, &stopTimeUs) || timeUs >= stopTimeUs) { + if (!mStopParams->findInt32("discontinuitySeq", &discontinuitySeq) + || discontinuitySeq > mDiscontinuitySeq + || !mStopParams->findInt64(key, &stopTimeUs) + || (discontinuitySeq == mDiscontinuitySeq + && timeUs >= stopTimeUs)) { packetSource->queueAccessUnit(mSession->createFormatChangeBuffer()); mStreamTypeMask &= ~stream; mPacketSources.removeItemsAt(i); @@ -1169,15 +1270,18 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu } // Note that we do NOT dequeue any discontinuities except for format change. - - // for simplicity, store a reference to the format in each unit - sp format = source->getFormat(); - if (format != NULL) { - accessUnit->meta()->setObject("format", format); + if (stream == LiveSession::STREAMTYPE_VIDEO) { + const bool discard = true; + status_t status; + while (mVideoBuffer->hasBufferAvailable(&status)) { + sp videoBuffer; + mVideoBuffer->dequeueAccessUnit(&videoBuffer); + setAccessUnitProperties(videoBuffer, source, discard); + packetSource->queueAccessUnit(videoBuffer); + } } - // Stash the sequence number so we can hint future playlist where to start at. - accessUnit->meta()->setInt32("seq", mSeqNumber); + setAccessUnitProperties(accessUnit, source); packetSource->queueAccessUnit(accessUnit); } @@ -1244,7 +1348,8 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( CHECK(itemMeta->findInt64("durationUs", &durationUs)); buffer->meta()->setInt64("timeUs", getSegmentStartTimeUs(mSeqNumber)); buffer->meta()->setInt64("durationUs", durationUs); - buffer->meta()->setInt32("seq", mSeqNumber); + buffer->meta()->setInt64("segmentStartTimeUs", getSegmentStartTimeUs(mSeqNumber)); + buffer->meta()->setInt32("discontinuitySeq", mDiscontinuitySeq); packetSource->queueAccessUnit(buffer); return OK; @@ -1310,14 +1415,6 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( firstID3Tag = false; } - if (!mFirstPTSValid) { - mFirstPTSValid = true; - mFirstPTS = PTS; - } - PTS -= mFirstPTS; - - int64_t timeUs = (PTS * 100ll) / 9ll + mAbsoluteTimeAnchorUs; - if (mStreamTypeMask != LiveSession::STREAMTYPE_AUDIO) { ALOGW("This stream only contains audio data!"); @@ -1360,6 +1457,12 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( int32_t sampleRate; CHECK(packetSource->getFormat()->findInt32(kKeySampleRate, &sampleRate)); + int64_t timeUs = (PTS * 100ll) / 9ll; + if (!mFirstPTSValid) { + mFirstPTSValid = true; + mFirstTimeUs = timeUs; + } + size_t offset = 0; while (offset < buffer->size()) { const uint8_t *adtsHeader = buffer->data() + offset; @@ -1384,19 +1487,32 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( CHECK_LE(offset + aac_frame_length, buffer->size()); - sp unit = new ABuffer(aac_frame_length); - memcpy(unit->data(), adtsHeader, aac_frame_length); - int64_t unitTimeUs = timeUs + numSamples * 1000000ll / sampleRate; - unit->meta()->setInt64("timeUs", unitTimeUs); + offset += aac_frame_length; // Each AAC frame encodes 1024 samples. numSamples += 1024; - unit->meta()->setInt32("seq", mSeqNumber); - packetSource->queueAccessUnit(unit); + if (mStartup) { + int64_t startTimeUs = unitTimeUs; + if (mStartTimeUsRelative) { + startTimeUs -= mFirstTimeUs; + if (startTimeUs < 0) { + startTimeUs = 0; + } + } + if (startTimeUs < mStartTimeUs) { + continue; + } + } - offset += aac_frame_length; + sp unit = new ABuffer(aac_frame_length); + memcpy(unit->data(), adtsHeader, aac_frame_length); + + unit->meta()->setInt64("timeUs", unitTimeUs); + unit->meta()->setInt64("segmentStartTimeUs", getSegmentStartTimeUs(mSeqNumber)); + unit->meta()->setInt32("discontinuitySeq", mDiscontinuitySeq); + packetSource->queueAccessUnit(unit); } return OK; diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index e4fdbff..daefb26 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -57,13 +57,15 @@ struct PlaylistFetcher : public AHandler { const sp &audioSource, const sp &videoSource, const sp &subtitleSource, - int64_t startTimeUs = -1ll, - int64_t minStartTimeUs = 0ll /* start after this timestamp */, - int32_t startSeqNumberHint = -1 /* try starting at this sequence number */); + int64_t startTimeUs = -1ll, // starting timestamps + int64_t segmentStartTimeUs = -1ll, // starting position within playlist + // startTimeUs!=segmentStartTimeUs only when playlist is live + int32_t startDiscontinuitySeq = 0, + bool adaptive = false); void pauseAsync(); - void stopAsync(bool selfTriggered = false); + void stopAsync(bool clear = true); void resumeUntilAsync(const sp ¶ms); @@ -99,11 +101,12 @@ private: sp mSession; AString mURI; - AString mVideoMime; uint32_t mStreamTypeMask; int64_t mStartTimeUs; - int64_t mMinStartTimeUs; // start fetching no earlier than this value + int64_t mSegmentStartTimeUs; + ssize_t mDiscontinuitySeq; + bool mStartTimeUsRelative; sp mStopParams; // message containing the latest timestamps we should fetch. KeyedVector > @@ -116,8 +119,8 @@ private: int32_t mSeqNumber; int32_t mNumRetries; bool mStartup; + bool mAdaptive; bool mPrepared; - bool mSkipToFirstIDRAfterConnect; int64_t mNextPTSTimeUs; int32_t mMonitorQueueGeneration; @@ -136,7 +139,9 @@ private: bool mFirstPTSValid; uint64_t mFirstPTS; + int64_t mFirstTimeUs; int64_t mAbsoluteTimeAnchorUs; + sp mVideoBuffer; // Stores the initialization vector to decrypt the next block of cipher text, which can // either be derived from the sequence number, read from the manifest, or copied from @@ -175,6 +180,10 @@ private: // Resume a fetcher to continue until the stopping point stored in msg. status_t onResumeUntil(const sp &msg); + const sp &setAccessUnitProperties( + const sp &accessUnit, + const sp &source, + bool discard = false); status_t extractAndQueueAccessUnitsFromTs(const sp &buffer); status_t extractAndQueueAccessUnits( @@ -185,6 +194,8 @@ private: void queueDiscontinuity( ATSParser::DiscontinuityType type, const sp &extra); + int32_t getSeqNumberWithAnchorTime(int64_t anchorTimeUs) const; + int32_t getSeqNumberForDiscontinuity(size_t discontinuitySeq) const; int32_t getSeqNumberForTime(int64_t timeUs) const; void updateDuration(); diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index eda6387..6d8866a 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -894,6 +894,12 @@ void ATSParser::Stream::onPayloadData( ALOGV("Stream PID 0x%08x of type 0x%02x now has data.", mElementaryPID, mStreamType); + const char *mime; + if (meta->findCString(kKeyMIMEType, &mime) + && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) + && !IsIDR(accessUnit)) { + continue; + } mSource = new AnotherPacketSource(meta); mSource->queueAccessUnit(accessUnit); } diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index 72c9dae..010063f 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "AnotherPacketSource" + #include "AnotherPacketSource.h" #include @@ -38,7 +41,8 @@ AnotherPacketSource::AnotherPacketSource(const sp &meta) mFormat(NULL), mLastQueuedTimeUs(0), mEOSResult(OK), - mLatestEnqueuedMeta(NULL) { + mLatestEnqueuedMeta(NULL), + mLatestDequeuedMeta(NULL) { setFormat(meta); } @@ -92,7 +96,7 @@ sp AnotherPacketSource::getFormat() { sp object; if (buffer->meta()->findObject("format", &object)) { - return static_cast(object.get()); + return mFormat = static_cast(object.get()); } ++it; @@ -121,6 +125,8 @@ status_t AnotherPacketSource::dequeueAccessUnit(sp *buffer) { return INFO_DISCONTINUITY; } + mLatestDequeuedMeta = (*buffer)->meta()->dup(); + sp object; if ((*buffer)->meta()->findObject("format", &object)) { mFormat = static_cast(object.get()); @@ -142,8 +148,10 @@ status_t AnotherPacketSource::read( } if (!mBuffers.empty()) { + const sp buffer = *mBuffers.begin(); mBuffers.erase(mBuffers.begin()); + mLatestDequeuedMeta = buffer->meta()->dup(); int32_t discontinuity; if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { @@ -202,7 +210,7 @@ void AnotherPacketSource::queueAccessUnit(const sp &buffer) { mBuffers.push_back(buffer); mCondition.signal(); - if (!mLatestEnqueuedMeta.get()) { + if (mLatestEnqueuedMeta == NULL) { mLatestEnqueuedMeta = buffer->meta(); } else { int64_t latestTimeUs = 0; @@ -341,9 +349,14 @@ bool AnotherPacketSource::isFinished(int64_t duration) const { return (mEOSResult != OK); } -sp AnotherPacketSource::getLatestMeta() { +sp AnotherPacketSource::getLatestEnqueuedMeta() { Mutex::Autolock autoLock(mLock); return mLatestEnqueuedMeta; } +sp AnotherPacketSource::getLatestDequeuedMeta() { + Mutex::Autolock autoLock(mLock); + return mLatestDequeuedMeta; +} + } // namespace android diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h index f38f9dc..0c717d7 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h @@ -64,7 +64,8 @@ struct AnotherPacketSource : public MediaSource { bool isFinished(int64_t duration) const; - sp getLatestMeta(); + sp getLatestEnqueuedMeta(); + sp getLatestDequeuedMeta(); protected: virtual ~AnotherPacketSource(); @@ -80,6 +81,7 @@ private: List > mBuffers; status_t mEOSResult; sp mLatestEnqueuedMeta; + sp mLatestDequeuedMeta; bool wasFormatChange(int32_t discontinuityType) const; -- cgit v1.1 From 3de157dd8f9cd45bf9b0406268f5830887105ae1 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 5 Aug 2014 20:54:44 -0700 Subject: some fixes for crash when extractor creation fails - prefetch data for sniffing - notify error instead of crashing if extractor is NULL Bug: 16818302 Change-Id: I56ff4996d99ac2811d19d141f7ff7acdd7c1da17 --- .../nuplayer/GenericSource.cpp | 60 ++++++++-------- .../libmediaplayerservice/nuplayer/GenericSource.h | 18 +++-- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 46 +++++++++---- media/libstagefright/DataSource.cpp | 80 +++++++++++++++++++++- media/libstagefright/include/WVMExtractor.h | 3 +- 5 files changed, 152 insertions(+), 55 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 32842bb..a18407f 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -37,10 +37,6 @@ namespace android { NuPlayer::GenericSource::GenericSource( const sp ¬ify, - const sp &httpService, - const char *url, - const KeyedVector *headers, - bool isWidevine, bool uidValid, uid_t uid) : Source(notify), @@ -48,38 +44,41 @@ NuPlayer::GenericSource::GenericSource( mFetchTimedTextDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false), - mIsWidevine(isWidevine), + mIsWidevine(false), mUIDValid(uidValid), mUID(uid) { DataSource::RegisterDefaultSniffers(); +} + +status_t NuPlayer::GenericSource::init( + const sp &httpService, + const char *url, + const KeyedVector *headers) { + mIsWidevine = !strncasecmp(url, "widevine://", 11); + + AString sniffedMIME; sp dataSource = - DataSource::CreateFromURI(httpService, url, headers); - CHECK(dataSource != NULL); + DataSource::CreateFromURI(httpService, url, headers, &sniffedMIME); - initFromDataSource(dataSource); -} + if (dataSource == NULL) { + return UNKNOWN_ERROR; + } -NuPlayer::GenericSource::GenericSource( - const sp ¬ify, - int fd, int64_t offset, int64_t length) - : Source(notify), - mFetchSubtitleDataGeneration(0), - mFetchTimedTextDataGeneration(0), - mDurationUs(0ll), - mAudioIsVorbis(false), - mIsWidevine(false), - mUIDValid(false), - mUID(0) { - DataSource::RegisterDefaultSniffers(); + return initFromDataSource( + dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); +} +status_t NuPlayer::GenericSource::init( + int fd, int64_t offset, int64_t length) { sp dataSource = new FileSource(dup(fd), offset, length); - initFromDataSource(dataSource); + return initFromDataSource(dataSource, NULL); } -void NuPlayer::GenericSource::initFromDataSource( - const sp &dataSource) { +status_t NuPlayer::GenericSource::initFromDataSource( + const sp &dataSource, + const char* mime) { sp extractor; if (mIsWidevine) { @@ -93,7 +92,7 @@ void NuPlayer::GenericSource::initFromDataSource( || strcasecmp( mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { ALOGE("unsupported widevine mime: %s", mimeType.string()); - return; + return UNKNOWN_ERROR; } sp wvmExtractor = new WVMExtractor(dataSource); @@ -103,10 +102,12 @@ void NuPlayer::GenericSource::initFromDataSource( } extractor = wvmExtractor; } else { - extractor = MediaExtractor::Create(dataSource); + extractor = MediaExtractor::Create(dataSource, mime); } - CHECK(extractor != NULL); + if (extractor == NULL) { + return UNKNOWN_ERROR; + } sp fileMeta = extractor->getMetaData(); if (fileMeta != NULL) { @@ -144,6 +145,9 @@ void NuPlayer::GenericSource::initFromDataSource( int32_t secure; if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) && secure) { mIsWidevine = true; + if (mUIDValid) { + extractor->setUID(mUID); + } } } } @@ -158,6 +162,8 @@ void NuPlayer::GenericSource::initFromDataSource( } } } + + return OK; } status_t NuPlayer::GenericSource::setBuffers(bool audio, Vector &buffers) { diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 3c5f55c..76e628b 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -34,18 +34,14 @@ struct MediaSource; class MediaBuffer; struct NuPlayer::GenericSource : public NuPlayer::Source { - GenericSource( - const sp ¬ify, + GenericSource(const sp ¬ify, bool uidValid, uid_t uid); + + status_t init( const sp &httpService, const char *url, - const KeyedVector *headers, - bool isWidevine = false, - bool uidValid = false, - uid_t uid = 0); + const KeyedVector *headers); - GenericSource( - const sp ¬ify, - int fd, int64_t offset, int64_t length); + status_t init(int fd, int64_t offset, int64_t length); virtual void prepareAsync(); @@ -101,7 +97,9 @@ private: bool mUIDValid; uid_t mUID; - void initFromDataSource(const sp &dataSource); + status_t initFromDataSource( + const sp &dataSource, + const char *mime); void fetchTextData( uint32_t what, media_track_type type, diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 17038a4..d56b1f0 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -207,6 +207,7 @@ void NuPlayer::setDataSourceAsync( const sp &httpService, const char *url, const KeyedVector *headers) { + sp msg = new AMessage(kWhatSetDataSource, id()); size_t len = strlen(url); @@ -224,16 +225,21 @@ void NuPlayer::setDataSourceAsync( || strstr(url, ".sdp?"))) { source = new RTSPSource( notify, httpService, url, headers, mUIDValid, mUID, true); - } else if ((!strncasecmp(url, "widevine://", 11))) { - source = new GenericSource(notify, httpService, url, headers, - true /* isWidevine */, mUIDValid, mUID); - // Don't set FLAG_SECURE on mSourceFlags here, the correct flags - // will be updated in Source::kWhatFlagsChanged handler when - // GenericSource is prepared. } else { - source = new GenericSource(notify, httpService, url, headers); - } + sp genericSource = + new GenericSource(notify, mUIDValid, mUID); + // Don't set FLAG_SECURE on mSourceFlags here for widevine. + // The correct flags will be updated in Source::kWhatFlagsChanged + // handler when GenericSource is prepared. + status_t err = genericSource->init(httpService, url, headers); + + if (err == OK) { + source = genericSource; + } else { + ALOGE("Failed to initialize generic source!"); + } + } msg->setObject("source", source); msg->post(); } @@ -243,7 +249,16 @@ void NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) { sp notify = new AMessage(kWhatSourceNotify, id()); - sp source = new GenericSource(notify, fd, offset, length); + sp source = + new GenericSource(notify, mUIDValid, mUID); + + status_t err = source->init(fd, offset, length); + + if (err != OK) { + ALOGE("Failed to initialize generic source!"); + source = NULL; + } + msg->setObject("source", source); msg->post(); } @@ -352,17 +367,20 @@ void NuPlayer::onMessageReceived(const sp &msg) { CHECK(mSource == NULL); + status_t err = OK; sp obj; CHECK(msg->findObject("source", &obj)); - - mSource = static_cast(obj.get()); - - looper()->registerHandler(mSource); + if (obj != NULL) { + mSource = static_cast(obj.get()); + looper()->registerHandler(mSource); + } else { + err = UNKNOWN_ERROR; + } CHECK(mDriver != NULL); sp driver = mDriver.promote(); if (driver != NULL) { - driver->notifySetDataSourceCompleted(OK); + driver->notifySetDataSourceCompleted(err); } break; } diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 6e0f37a..908cdca 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "DataSource" #include "include/AMRExtractor.h" @@ -33,6 +35,7 @@ #include #include +#include #include #include #include @@ -182,7 +185,12 @@ void DataSource::RegisterDefaultSniffers() { sp DataSource::CreateFromURI( const sp &httpService, const char *uri, - const KeyedVector *headers) { + const KeyedVector *headers, + AString *sniffedMIME) { + if (sniffedMIME != NULL) { + *sniffedMIME = ""; + } + bool isWidevine = !strncasecmp("widevine://", uri, 11); sp source; @@ -202,6 +210,7 @@ sp DataSource::CreateFromURI( } if (httpSource->connect(uri, headers) != OK) { + ALOGE("Failed to connect http source!"); return NULL; } @@ -214,9 +223,76 @@ sp DataSource::CreateFromURI( ©, &cacheConfig, &disconnectAtHighwatermark); } - source = new NuCachedSource2( + sp cachedSource = new NuCachedSource2( httpSource, cacheConfig.isEmpty() ? NULL : cacheConfig.string()); + + String8 contentType = httpSource->getMIMEType(); + + if (strncasecmp(contentType.string(), "audio/", 6)) { + // We're not doing this for streams that appear to be audio-only + // streams to ensure that even low bandwidth streams start + // playing back fairly instantly. + + // We're going to prefill the cache before trying to instantiate + // the extractor below, as the latter is an operation that otherwise + // could block on the datasource for a significant amount of time. + // During that time we'd be unable to abort the preparation phase + // without this prefill. + + // Initially make sure we have at least 192 KB for the sniff + // to complete without blocking. + static const size_t kMinBytesForSniffing = 192 * 1024; + + off64_t metaDataSize = -1ll; + for (;;) { + status_t finalStatus; + size_t cachedDataRemaining = + cachedSource->approxDataRemaining(&finalStatus); + + if (finalStatus != OK || (metaDataSize >= 0 + && (off64_t)cachedDataRemaining >= metaDataSize)) { + ALOGV("stop caching, status %d, " + "metaDataSize %lld, cachedDataRemaining %zu", + finalStatus, metaDataSize, cachedDataRemaining); + break; + } + + ALOGV("now cached %zu bytes of data", cachedDataRemaining); + + if (metaDataSize < 0 + && cachedDataRemaining >= kMinBytesForSniffing) { + String8 tmp; + float confidence; + sp meta; + if (!cachedSource->sniff(&tmp, &confidence, &meta)) { + return NULL; + } + + // We successfully identified the file's extractor to + // be, remember this mime type so we don't have to + // sniff it again when we call MediaExtractor::Create() + if (sniffedMIME != NULL) { + *sniffedMIME = tmp.string(); + } + + if (meta == NULL + || !meta->findInt64("meta-data-size", + reinterpret_cast(&metaDataSize))) { + metaDataSize = kDefaultMetaSize; + } + + if (metaDataSize < 0ll) { + ALOGE("invalid metaDataSize = %lld bytes", metaDataSize); + return NULL; + } + } + + usleep(200000); + } + } + + source = cachedSource; } else { // We do not want that prefetching, caching, datasource wrapper // in the widevine:// case. diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h index 8e62946..ab7e8b8 100644 --- a/media/libstagefright/include/WVMExtractor.h +++ b/media/libstagefright/include/WVMExtractor.h @@ -49,6 +49,7 @@ public: virtual sp getTrack(size_t index); virtual sp getTrackMetaData(size_t index, uint32_t flags); virtual sp getMetaData(); + virtual void setUID(uid_t uid); // Return the amount of data cached from the current // playback positiion (in us). @@ -74,8 +75,6 @@ public: // codec. void setCryptoPluginMode(bool cryptoPluginMode); - void setUID(uid_t uid); - static bool getVendorLibHandle(); status_t getError(); -- cgit v1.1 From 5e78d66badd543bc9587eed74128bca47df40d70 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Thu, 7 Aug 2014 06:11:39 +0000 Subject: Revert "NuPlayer: don't feed decoder input data during flushing." The previous patch results in MediaBuffer leakage. This reverts commit 69a85b792c31033a99c8858e3b1a3c2ea68b6278. Bug: 14955925 Bug: 16303659 Bug: 16467066 Bug: 16849601 Change-Id: Ib1892b7603a97e12b7ee228fd5a4009700cdc988 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 0e015b0..58d0138 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1169,11 +1169,11 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { sp reply; CHECK(msg->findMessage("reply", &reply)); - if ((audio && mFlushingAudio != NONE - && mFlushingAudio != AWAITING_DISCONTINUITY) - || (!audio && mFlushingVideo != NONE - && mFlushingVideo != AWAITING_DISCONTINUITY)) { - return -EWOULDBLOCK; + if ((audio && IsFlushingState(mFlushingAudio)) + || (!audio && IsFlushingState(mFlushingVideo))) { + reply->setInt32("err", INFO_DISCONTINUITY); + reply->post(); + return OK; } sp accessUnit; -- cgit v1.1 From a9522673f3076ea937eb2912945d7ed646ca05df Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 6 Aug 2014 11:30:16 -0700 Subject: stagefright: move ARRAY_SIZE to foundation Bug: 11990470 Change-Id: Ifae790b774a0fb210acbe33a1310d3d6ba46e7fa --- media/libstagefright/include/SoftVideoDecoderOMXComponent.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h index d050fa6..7f200dd 100644 --- a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h +++ b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h @@ -27,8 +27,6 @@ #include #include -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) - namespace android { struct SoftVideoDecoderOMXComponent : public SimpleSoftOMXComponent { -- cgit v1.1 From bf9b95d712a24b654761cb9fea0d94d383cfc661 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 7 Aug 2014 15:35:07 -0700 Subject: delay data source creation for GenericSource prepare time Bug: 16708180 Change-Id: I9d578ef5e2edaed50279d28d3831c68556468f39 --- .../nuplayer/GenericSource.cpp | 80 ++++++++++++++++++---- .../libmediaplayerservice/nuplayer/GenericSource.h | 13 +++- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 8 +-- 3 files changed, 80 insertions(+), 21 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index a18407f..a39b546 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -21,6 +21,7 @@ #include "AnotherPacketSource.h" +#include #include #include #include @@ -47,33 +48,48 @@ NuPlayer::GenericSource::GenericSource( mIsWidevine(false), mUIDValid(uidValid), mUID(uid) { + resetDataSource(); DataSource::RegisterDefaultSniffers(); } -status_t NuPlayer::GenericSource::init( +void NuPlayer::GenericSource::resetDataSource() { + mHTTPService.clear(); + mUri.clear(); + mUriHeaders.clear(); + mFd = -1; + mOffset = 0; + mLength = 0; +} + +status_t NuPlayer::GenericSource::setDataSource( const sp &httpService, const char *url, const KeyedVector *headers) { - mIsWidevine = !strncasecmp(url, "widevine://", 11); - - AString sniffedMIME; + resetDataSource(); - sp dataSource = - DataSource::CreateFromURI(httpService, url, headers, &sniffedMIME); + mHTTPService = httpService; + mUri = url; - if (dataSource == NULL) { - return UNKNOWN_ERROR; + if (headers) { + mUriHeaders = *headers; } - return initFromDataSource( - dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); + // delay data source creation to prepareAsync() to avoid blocking + // the calling thread in setDataSource for any significant time. + return OK; } -status_t NuPlayer::GenericSource::init( +status_t NuPlayer::GenericSource::setDataSource( int fd, int64_t offset, int64_t length) { - sp dataSource = new FileSource(dup(fd), offset, length); + resetDataSource(); + + mFd = dup(fd); + mOffset = offset; + mLength = length; - return initFromDataSource(dataSource, NULL); + // delay data source creation to prepareAsync() to avoid blocking + // the calling thread in setDataSource for any significant time. + return OK; } status_t NuPlayer::GenericSource::initFromDataSource( @@ -143,7 +159,8 @@ status_t NuPlayer::GenericSource::initFromDataSource( // check if the source requires secure buffers int32_t secure; - if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) && secure) { + if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) + && secure) { mIsWidevine = true; if (mUIDValid) { extractor->setUID(mUID); @@ -166,7 +183,8 @@ status_t NuPlayer::GenericSource::initFromDataSource( return OK; } -status_t NuPlayer::GenericSource::setBuffers(bool audio, Vector &buffers) { +status_t NuPlayer::GenericSource::setBuffers( + bool audio, Vector &buffers) { if (mIsWidevine && !audio) { return mVideoTrack.mSource->setBuffers(buffers); } @@ -177,6 +195,38 @@ NuPlayer::GenericSource::~GenericSource() { } void NuPlayer::GenericSource::prepareAsync() { + // delayed data source creation + AString sniffedMIME; + sp dataSource; + + if (!mUri.empty()) { + mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11); + + dataSource = DataSource::CreateFromURI( + mHTTPService, mUri.c_str(), &mUriHeaders, &sniffedMIME); + } else { + // set to false first, if the extractor + // comes back as secure, set it to true then. + mIsWidevine = false; + + dataSource = new FileSource(mFd, mOffset, mLength); + } + + if (dataSource == NULL) { + ALOGE("Failed to create data source!"); + notifyPrepared(UNKNOWN_ERROR); + return; + } + + status_t err = initFromDataSource( + dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); + + if (err != OK) { + ALOGE("Failed to init from data source!"); + notifyPrepared(err); + return; + } + if (mVideoTrack.mSource != NULL) { sp meta = mVideoTrack.mSource->getFormat(); diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 76e628b..44d690e 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -30,18 +30,19 @@ namespace android { struct AnotherPacketSource; struct ARTSPController; struct DataSource; +struct IMediaHTTPService; struct MediaSource; class MediaBuffer; struct NuPlayer::GenericSource : public NuPlayer::Source { GenericSource(const sp ¬ify, bool uidValid, uid_t uid); - status_t init( + status_t setDataSource( const sp &httpService, const char *url, const KeyedVector *headers); - status_t init(int fd, int64_t offset, int64_t length); + status_t setDataSource(int fd, int64_t offset, int64_t length); virtual void prepareAsync(); @@ -96,6 +97,14 @@ private: bool mIsWidevine; bool mUIDValid; uid_t mUID; + sp mHTTPService; + AString mUri; + KeyedVector mUriHeaders; + int mFd; + int64_t mOffset; + int64_t mLength; + + void resetDataSource(); status_t initFromDataSource( const sp &dataSource, diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index d56b1f0..0668600 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -232,12 +232,12 @@ void NuPlayer::setDataSourceAsync( // The correct flags will be updated in Source::kWhatFlagsChanged // handler when GenericSource is prepared. - status_t err = genericSource->init(httpService, url, headers); + status_t err = genericSource->setDataSource(httpService, url, headers); if (err == OK) { source = genericSource; } else { - ALOGE("Failed to initialize generic source!"); + ALOGE("Failed to set data source!"); } } msg->setObject("source", source); @@ -252,10 +252,10 @@ void NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) { sp source = new GenericSource(notify, mUIDValid, mUID); - status_t err = source->init(fd, offset, length); + status_t err = source->setDataSource(fd, offset, length); if (err != OK) { - ALOGE("Failed to initialize generic source!"); + ALOGE("Failed to set data source!"); source = NULL; } -- cgit v1.1 From 251d4be8aa5ab80bc915a82a2420233bdc62018e Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Wed, 30 Jul 2014 15:46:04 -0700 Subject: Clarify and implement MediaCodec status codes Clarify MediaCodec status codes in MediaError.h When appropriate, return OMX error codes for status. Optionally return a status code from CreateByType() and CreateByComponentName(). Bug: 12034929 Bug: 13976475 Change-Id: I7463dd08d101074f730481b26127a69c9186c97e --- media/libstagefright/ACodec.cpp | 72 +++++++++++++++++++++-- media/libstagefright/MediaCodec.cpp | 114 ++++++++++++++++++++++++------------ 2 files changed, 144 insertions(+), 42 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index b81674d..c2594ca 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -51,6 +51,48 @@ namespace android { +// OMX errors are directly mapped into status_t range if +// there is no corresponding MediaError status code. +// Use the statusFromOMXError(int32_t omxError) function. +// +// Currently this is a direct map. +// See frameworks/native/include/media/openmax/OMX_Core.h +// +// Vendor OMX errors from 0x90000000 - 0x9000FFFF +// Extension OMX errors from 0x8F000000 - 0x90000000 +// Standard OMX errors from 0x80001000 - 0x80001024 (0x80001024 current) +// + +// returns true if err is a recognized OMX error code. +// as OMX error is OMX_S32, this is an int32_t type +static inline bool isOMXError(int32_t err) { + return (ERROR_CODEC_MIN <= err && err <= ERROR_CODEC_MAX); +} + +// converts an OMX error to a status_t +static inline status_t statusFromOMXError(int32_t omxError) { + switch (omxError) { + case OMX_ErrorInvalidComponentName: + case OMX_ErrorComponentNotFound: + return NAME_NOT_FOUND; // can trigger illegal argument error for provided names. + default: + return isOMXError(omxError) ? omxError : 0; // no translation required + } +} + +// checks and converts status_t to a non-side-effect status_t +static inline status_t makeNoSideEffectStatus(status_t err) { + switch (err) { + // the following errors have side effects and may come + // from other code modules. Remap for safety reasons. + case INVALID_OPERATION: + case DEAD_OBJECT: + return UNKNOWN_ERROR; + default: + return err; + } +} + template static void InitOMXParams(T *params) { params->nSize = sizeof(T); @@ -3226,8 +3268,18 @@ void ACodec::sendFormatChange(const sp &reply) { void ACodec::signalError(OMX_ERRORTYPE error, status_t internalError) { sp notify = mNotify->dup(); notify->setInt32("what", CodecBase::kWhatError); - notify->setInt32("omx-error", error); + ALOGE("signalError(omxError %#x, internalError %d)", error, internalError); + + if (internalError == UNKNOWN_ERROR) { // find better error code + const status_t omxStatus = statusFromOMXError(error); + if (omxStatus != 0) { + internalError = omxStatus; + } else { + ALOGW("Invalid OMX error %#x", error); + } + } notify->setInt32("err", internalError); + notify->setInt32("actionCode", ACTION_CODE_FATAL); // could translate from OMX error. notify->post(); } @@ -3451,6 +3503,7 @@ bool ACodec::BaseState::onMessageReceived(const sp &msg) { case ACodec::kWhatCreateInputSurface: case ACodec::kWhatSignalEndOfInputStream: { + // This may result in an app illegal state exception. ALOGE("Message 0x%x was not handled", msg->what()); mCodec->signalError(OMX_ErrorUndefined, INVALID_OPERATION); return true; @@ -3458,6 +3511,7 @@ bool ACodec::BaseState::onMessageReceived(const sp &msg) { case ACodec::kWhatOMXDied: { + // This will result in kFlagSawMediaServerDie handling in MediaCodec. ALOGE("OMX/mediaserver died, signalling error!"); mCodec->signalError(OMX_ErrorResourcesLost, DEAD_OBJECT); break; @@ -3556,7 +3610,13 @@ bool ACodec::BaseState::onOMXEvent( ALOGE("[%s] ERROR(0x%08lx)", mCodec->mComponentName.c_str(), data1); - mCodec->signalError((OMX_ERRORTYPE)data1); + // verify OMX component sends back an error we expect. + OMX_ERRORTYPE omxError = (OMX_ERRORTYPE)data1; + if (!isOMXError(omxError)) { + ALOGW("Invalid OMX error %#x", omxError); + omxError = OMX_ErrorUndefined; + } + mCodec->signalError(omxError); return true; } @@ -3999,7 +4059,7 @@ void ACodec::BaseState::onOutputBufferDrained(const sp &msg) { info->mGraphicBuffer.get(), -1)) == OK) { info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW; } else { - mCodec->signalError(OMX_ErrorUndefined, err); + mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); info->mStatus = BufferInfo::OWNED_BY_US; } } else { @@ -4371,7 +4431,7 @@ bool ACodec::LoadedState::onConfigureComponent( ALOGE("[%s] configureCodec returning error %d", mCodec->mComponentName.c_str(), err); - mCodec->signalError(OMX_ErrorUndefined, err); + mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); return false; } @@ -4518,7 +4578,7 @@ void ACodec::LoadedToIdleState::stateEntered() { "(error 0x%08x)", err); - mCodec->signalError(OMX_ErrorUndefined, err); + mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); mCodec->changeState(mCodec->mLoadedState); } @@ -5046,7 +5106,7 @@ bool ACodec::OutputPortSettingsChangedState::onOMXEvent( "port reconfiguration (error 0x%08x)", err); - mCodec->signalError(OMX_ErrorUndefined, err); + mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); // This is technically not correct, but appears to be // the only way to free the component instance. diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 7c02959..69943ce 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -113,24 +113,26 @@ void MediaCodec::BatteryNotifier::noteStopAudio() { } // static sp MediaCodec::CreateByType( - const sp &looper, const char *mime, bool encoder) { + const sp &looper, const char *mime, bool encoder, status_t *err) { sp codec = new MediaCodec(looper); - if (codec->init(mime, true /* nameIsType */, encoder) != OK) { - return NULL; - } - return codec; + const status_t ret = codec->init(mime, true /* nameIsType */, encoder); + if (err != NULL) { + *err = ret; + } + return ret == OK ? codec : NULL; // NULL deallocates codec. } // static sp MediaCodec::CreateByComponentName( - const sp &looper, const char *name) { + const sp &looper, const char *name, status_t *err) { sp codec = new MediaCodec(looper); - if (codec->init(name, false /* nameIsType */, false /* encoder */) != OK) { - return NULL; - } - return codec; + const status_t ret = codec->init(name, false /* nameIsType */, false /* encoder */); + if (err != NULL) { + *err = ret; + } + return ret == OK ? codec : NULL; // NULL deallocates codec. } MediaCodec::MediaCodec(const sp &looper) @@ -139,6 +141,7 @@ MediaCodec::MediaCodec(const sp &looper) mCodec(NULL), mReplyID(0), mFlags(0), + mStickyError(OK), mSoftRenderer(NULL), mBatteryStatNotified(false), mIsVideo(false), @@ -330,6 +333,7 @@ status_t MediaCodec::reset() { mLooper->unregisterHandler(id()); mFlags = 0; // clear all flags + mStickyError = OK; // reset state not reset by setState(UNINITIALIZED) mReplyID = 0; @@ -620,10 +624,12 @@ void MediaCodec::cancelPendingDequeueOperations() { bool MediaCodec::handleDequeueInputBuffer(uint32_t replyID, bool newRequest) { if (!isExecuting() || (mFlags & kFlagIsAsync) - || (mFlags & kFlagStickyError) || (newRequest && (mFlags & kFlagDequeueInputPending))) { PostReplyWithError(replyID, INVALID_OPERATION); return true; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + return true; } ssize_t index = dequeuePortBuffer(kPortIndexInput); @@ -644,9 +650,10 @@ bool MediaCodec::handleDequeueOutputBuffer(uint32_t replyID, bool newRequest) { sp response = new AMessage; if (!isExecuting() || (mFlags & kFlagIsAsync) - || (mFlags & kFlagStickyError) || (newRequest && (mFlags & kFlagDequeueOutputPending))) { response->setInt32("err", INVALID_OPERATION); + } else if (mFlags & kFlagStickyError) { + response->setInt32("err", getStickyError()); } else if (mFlags & kFlagOutputBuffersChanged) { response->setInt32("err", INFO_OUTPUT_BUFFERS_CHANGED); mFlags &= ~kFlagOutputBuffersChanged; @@ -705,16 +712,12 @@ void MediaCodec::onMessageReceived(const sp &msg) { switch (what) { case CodecBase::kWhatError: { - int32_t omxError, internalError; - CHECK(msg->findInt32("omx-error", &omxError)); - CHECK(msg->findInt32("err", &internalError)); + int32_t err, actionCode; + CHECK(msg->findInt32("err", &err)); + CHECK(msg->findInt32("actionCode", &actionCode)); - ALOGE("Codec reported an error. " - "(omx error 0x%08x, internalError %d)", - omxError, internalError); - - if (omxError == OMX_ErrorResourcesLost - && internalError == DEAD_OBJECT) { + ALOGE("Codec reported err %#x, actionCode %d", err, actionCode); + if (err == DEAD_OBJECT) { mFlags |= kFlagSawMediaServerDie; } @@ -774,15 +777,24 @@ void MediaCodec::onMessageReceived(const sp &msg) { { sendErrorReponse = false; - mFlags |= kFlagStickyError; + setStickyError(err); postActivityNotificationIfPossible(); cancelPendingDequeueOperations(); if (mFlags & kFlagIsAsync) { - onError(omxError, 0); + onError(err, actionCode); + } + switch (actionCode) { + case ACTION_CODE_TRANSIENT: + break; + case ACTION_CODE_RECOVERABLE: + setState(INITIALIZED); + break; + default: + setState(UNINITIALIZED); + break; } - setState(UNINITIALIZED); break; } @@ -790,19 +802,32 @@ void MediaCodec::onMessageReceived(const sp &msg) { { sendErrorReponse = false; - mFlags |= kFlagStickyError; + setStickyError(err); postActivityNotificationIfPossible(); + // actionCode in an uninitialized state is always fatal. + if (mState == UNINITIALIZED) { + actionCode = ACTION_CODE_FATAL; + } if (mFlags & kFlagIsAsync) { - onError(omxError, 0); + onError(err, actionCode); + } + switch (actionCode) { + case ACTION_CODE_TRANSIENT: + break; + case ACTION_CODE_RECOVERABLE: + setState(INITIALIZED); + break; + default: + setState(UNINITIALIZED); + break; } - setState(UNINITIALIZED); break; } } if (sendErrorReponse) { - PostReplyWithError(mReplyID, UNKNOWN_ERROR); + PostReplyWithError(mReplyID, err); } break; } @@ -1009,7 +1034,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { ALOGE("queueCSDInputBuffer failed w/ error %d", err); - mFlags |= kFlagStickyError; + setStickyError(err); postActivityNotificationIfPossible(); cancelPendingDequeueOperations(); @@ -1401,9 +1426,12 @@ void MediaCodec::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (!isExecuting() || (mFlags & kFlagStickyError)) { + if (!isExecuting()) { PostReplyWithError(replyID, INVALID_OPERATION); break; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + break; } status_t err = onQueueInputBuffer(msg); @@ -1472,9 +1500,12 @@ void MediaCodec::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (!isExecuting() || (mFlags & kFlagStickyError)) { + if (!isExecuting()) { PostReplyWithError(replyID, INVALID_OPERATION); break; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + break; } status_t err = onReleaseOutputBuffer(msg); @@ -1488,9 +1519,12 @@ void MediaCodec::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (!isExecuting() || (mFlags & kFlagStickyError)) { + if (!isExecuting()) { PostReplyWithError(replyID, INVALID_OPERATION); break; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + break; } mReplyID = replyID; @@ -1503,10 +1537,12 @@ void MediaCodec::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (!isExecuting() || (mFlags & kFlagIsAsync) - || (mFlags & kFlagStickyError)) { + if (!isExecuting() || (mFlags & kFlagIsAsync)) { PostReplyWithError(replyID, INVALID_OPERATION); break; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + break; } int32_t portIndex; @@ -1535,9 +1571,12 @@ void MediaCodec::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (!isExecuting() || (mFlags & kFlagStickyError)) { + if (!isExecuting()) { PostReplyWithError(replyID, INVALID_OPERATION); break; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + break; } mReplyID = replyID; @@ -1561,10 +1600,12 @@ void MediaCodec::onMessageReceived(const sp &msg) { if ((mState != CONFIGURED && mState != STARTING && mState != STARTED && mState != FLUSHING && mState != FLUSHED) - || (mFlags & kFlagStickyError) || format == NULL) { PostReplyWithError(replyID, INVALID_OPERATION); break; + } else if (mFlags & kFlagStickyError) { + PostReplyWithError(replyID, getStickyError()); + break; } sp response = new AMessage; @@ -1687,6 +1728,7 @@ void MediaCodec::setState(State newState) { mFlags &= ~kFlagIsEncoder; mFlags &= ~kFlagGatherCodecSpecificData; mFlags &= ~kFlagIsAsync; + mStickyError = OK; mActivityNotify.clear(); mCallback.clear(); -- cgit v1.1 From b189a5b37cd1768f996096122b9541d9fa29ec43 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Thu, 7 Aug 2014 06:11:39 +0000 Subject: Revert "NuPlayer: don't feed decoder input data during flushing." The previous patch results in MediaBuffer leakage. This reverts commit 69a85b792c31033a99c8858e3b1a3c2ea68b6278. Bug: 14955925 Bug: 16303659 Bug: 16467066 Bug: 16849601 Change-Id: Ib1892b7603a97e12b7ee228fd5a4009700cdc988 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index d56b1f0..ba6fb7d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1198,11 +1198,11 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { sp reply; CHECK(msg->findMessage("reply", &reply)); - if ((audio && mFlushingAudio != NONE - && mFlushingAudio != AWAITING_DISCONTINUITY) - || (!audio && mFlushingVideo != NONE - && mFlushingVideo != AWAITING_DISCONTINUITY)) { - return -EWOULDBLOCK; + if ((audio && IsFlushingState(mFlushingAudio)) + || (!audio && IsFlushingState(mFlushingVideo))) { + reply->setInt32("err", INFO_DISCONTINUITY); + reply->post(); + return OK; } sp accessUnit; -- cgit v1.1 From 8accee4f0e94f19866d260be6eecd6c219eb4982 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 6 Aug 2014 11:32:00 -0700 Subject: stagefright: add AString parceling, and equal/compareIgnoreCase Bug: 11990470 Change-Id: If43ada5d2e768931f4409e499eaa268edade0500 --- media/libstagefright/foundation/AString.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'media') diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp index 894f65c..1befef4 100644 --- a/media/libstagefright/foundation/AString.cpp +++ b/media/libstagefright/foundation/AString.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include "ADebug.h" #include "AString.h" @@ -306,6 +307,14 @@ int AString::compare(const AString &other) const { return strcmp(mData, other.mData); } +int AString::compareIgnoreCase(const AString &other) const { + return strcasecmp(mData, other.mData); +} + +bool AString::equalsIgnoreCase(const AString &other) const { + return compareIgnoreCase(other) == 0; +} + void AString::tolower() { makeMutable(); @@ -342,6 +351,21 @@ bool AString::endsWithIgnoreCase(const char *suffix) const { return !strcasecmp(mData + mSize - suffixLen, suffix); } +// static +AString AString::FromParcel(const Parcel &parcel) { + size_t size = static_cast(parcel.readInt32()); + return AString(static_cast(parcel.readInplace(size)), size); +} + +status_t AString::writeToParcel(Parcel *parcel) const { + CHECK_LE(mSize, INT32_MAX); + status_t err = parcel->writeInt32(mSize); + if (err == OK) { + err = parcel->write(mData, mSize); + } + return err; +} + AString StringPrintf(const char *format, ...) { va_list ap; va_start(ap, format); -- cgit v1.1 From 60b1c0e79d12a1c70758bc8d060156924635f8ba Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 6 Aug 2014 16:55:46 -0700 Subject: stagefright: rework media codec list and infos This is in preparation of serving the codec list and codec infos from the mediaserver Bug: 11990470 Change-Id: Ib8e2708679c9ce461a4ba179974a740cdcdf2731 --- media/libmedia/Android.mk | 3 + media/libmedia/IMediaCodecList.cpp | 163 ++++++++++++++ media/libmedia/MediaCodecInfo.cpp | 252 +++++++++++++++++++++ media/libstagefright/MediaCodec.cpp | 16 +- media/libstagefright/MediaCodecList.cpp | 374 ++++++++++++-------------------- media/libstagefright/OMXCodec.cpp | 26 +-- 6 files changed, 574 insertions(+), 260 deletions(-) create mode 100644 media/libmedia/IMediaCodecList.cpp create mode 100644 media/libmedia/MediaCodecInfo.cpp (limited to 'media') diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index cee26d9..3be0651 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -25,6 +25,7 @@ LOCAL_SRC_FILES:= \ AudioRecord.cpp \ AudioSystem.cpp \ mediaplayer.cpp \ + IMediaCodecList.cpp \ IMediaHTTPConnection.cpp \ IMediaHTTPService.cpp \ IMediaLogService.cpp \ @@ -36,6 +37,7 @@ LOCAL_SRC_FILES:= \ IRemoteDisplay.cpp \ IRemoteDisplayClient.cpp \ IStreamSource.cpp \ + MediaCodecInfo.cpp \ Metadata.cpp \ mediarecorder.cpp \ IMediaMetadataRetriever.cpp \ @@ -74,6 +76,7 @@ LOCAL_MODULE:= libmedia LOCAL_C_INCLUDES := \ $(TOP)/frameworks/native/include/media/openmax \ + $(TOP)/frameworks/av/media/libstagefright \ external/icu/icu4c/source/common \ external/icu/icu4c/source/i18n \ $(call include-path-for, audio-effects) \ diff --git a/media/libmedia/IMediaCodecList.cpp b/media/libmedia/IMediaCodecList.cpp new file mode 100644 index 0000000..bf7c5ca --- /dev/null +++ b/media/libmedia/IMediaCodecList.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2014, 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 +#include + +#include +#include +#include +#include + +#include // for status_t + +namespace android { + +enum { + CREATE = IBinder::FIRST_CALL_TRANSACTION, + COUNT_CODECS, + GET_CODEC_INFO, + FIND_CODEC_BY_TYPE, + FIND_CODEC_BY_NAME, +}; + +class BpMediaCodecList: public BpInterface +{ +public: + BpMediaCodecList(const sp& impl) + : BpInterface(impl) + { + } + + virtual size_t countCodecs() const + { + Parcel data, reply; + data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor()); + remote()->transact(COUNT_CODECS, data, &reply); + return static_cast(reply.readInt32()); + } + + virtual sp getCodecInfo(size_t index) const + { + Parcel data, reply; + data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor()); + data.writeInt32(index); + remote()->transact(GET_CODEC_INFO, data, &reply); + status_t err = reply.readInt32(); + if (err == OK) { + return MediaCodecInfo::FromParcel(reply); + } else { + return NULL; + } + } + + virtual ssize_t findCodecByType( + const char *type, bool encoder, size_t startIndex = 0) const + { + if (startIndex > INT32_MAX) { + return NAME_NOT_FOUND; + } + + Parcel data, reply; + data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor()); + data.writeCString(type); + data.writeInt32(encoder); + data.writeInt32(startIndex); + remote()->transact(FIND_CODEC_BY_TYPE, data, &reply); + return static_cast(reply.readInt32()); + } + + virtual ssize_t findCodecByName(const char *name) const + { + Parcel data, reply; + data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor()); + data.writeCString(name); + remote()->transact(FIND_CODEC_BY_NAME, data, &reply); + return static_cast(reply.readInt32()); + } +}; + +IMPLEMENT_META_INTERFACE(MediaCodecList, "android.media.IMediaCodecList"); + +// ---------------------------------------------------------------------- + +status_t BnMediaCodecList::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch (code) { + case COUNT_CODECS: + { + CHECK_INTERFACE(IMediaCodecList, data, reply); + size_t count = countCodecs(); + if (count > INT32_MAX) { + count = INT32_MAX; + } + reply->writeInt32(count); + return NO_ERROR; + } + break; + + case GET_CODEC_INFO: + { + CHECK_INTERFACE(IMediaCodecList, data, reply); + size_t index = static_cast(data.readInt32()); + const sp info = getCodecInfo(index); + if (info != NULL) { + reply->writeInt32(OK); + info->writeToParcel(reply); + } else { + reply->writeInt32(-ERANGE); + } + return NO_ERROR; + } + break; + + case FIND_CODEC_BY_TYPE: + { + CHECK_INTERFACE(IMediaCodecList, data, reply); + const char *type = data.readCString(); + bool isEncoder = static_cast(data.readInt32()); + size_t startIndex = static_cast(data.readInt32()); + ssize_t index = findCodecByType(type, isEncoder, startIndex); + if (index > INT32_MAX || index < 0) { + index = NAME_NOT_FOUND; + } + reply->writeInt32(index); + return NO_ERROR; + } + break; + + case FIND_CODEC_BY_NAME: + { + CHECK_INTERFACE(IMediaCodecList, data, reply); + const char *name = data.readCString(); + ssize_t index = findCodecByName(name); + if (index > INT32_MAX || index < 0) { + index = NAME_NOT_FOUND; + } + reply->writeInt32(index); + return NO_ERROR; + } + break; + + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp new file mode 100644 index 0000000..7900eae --- /dev/null +++ b/media/libmedia/MediaCodecInfo.cpp @@ -0,0 +1,252 @@ +/* + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaCodecInfo" +#include + +#include + +#include + +#include +#include +#include + +#include + +namespace android { + +void MediaCodecInfo::Capabilities::getSupportedProfileLevels( + Vector *profileLevels) const { + profileLevels->clear(); + profileLevels->appendVector(mProfileLevels); +} + +void MediaCodecInfo::Capabilities::getSupportedColorFormats( + Vector *colorFormats) const { + colorFormats->clear(); + colorFormats->appendVector(mColorFormats); +} + +uint32_t MediaCodecInfo::Capabilities::getFlags() const { + return mFlags; +} + +const sp &MediaCodecInfo::Capabilities::getDetails() const { + return mDetails; +} + +MediaCodecInfo::Capabilities::Capabilities() + : mFlags(0) { + mDetails = new AMessage; +} + +// static +sp MediaCodecInfo::Capabilities::FromParcel( + const Parcel &parcel) { + sp caps = new Capabilities(); + size_t size = static_cast(parcel.readInt32()); + for (size_t i = 0; i < size; i++) { + ProfileLevel profileLevel; + profileLevel.mProfile = static_cast(parcel.readInt32()); + profileLevel.mLevel = static_cast(parcel.readInt32()); + if (caps != NULL) { + caps->mProfileLevels.push_back(profileLevel); + } + } + size = static_cast(parcel.readInt32()); + for (size_t i = 0; i < size; i++) { + uint32_t color = static_cast(parcel.readInt32()); + if (caps != NULL) { + caps->mColorFormats.push_back(color); + } + } + uint32_t flags = static_cast(parcel.readInt32()); + sp details = AMessage::FromParcel(parcel); + if (caps != NULL) { + caps->mFlags = flags; + caps->mDetails = details; + } + return caps; +} + +status_t MediaCodecInfo::Capabilities::writeToParcel(Parcel *parcel) const { + CHECK_LE(mProfileLevels.size(), INT32_MAX); + parcel->writeInt32(mProfileLevels.size()); + for (size_t i = 0; i < mProfileLevels.size(); i++) { + parcel->writeInt32(mProfileLevels.itemAt(i).mProfile); + parcel->writeInt32(mProfileLevels.itemAt(i).mLevel); + } + CHECK_LE(mColorFormats.size(), INT32_MAX); + parcel->writeInt32(mColorFormats.size()); + for (size_t i = 0; i < mColorFormats.size(); i++) { + parcel->writeInt32(mColorFormats.itemAt(i)); + } + parcel->writeInt32(mFlags); + mDetails->writeToParcel(parcel); + return OK; +} + +bool MediaCodecInfo::isEncoder() const { + return mIsEncoder; +} + +bool MediaCodecInfo::hasQuirk(const char *name) const { + for (size_t ix = 0; ix < mQuirks.size(); ix++) { + if (mQuirks.itemAt(ix).equalsIgnoreCase(name)) { + return true; + } + } + return false; +} + +void MediaCodecInfo::getSupportedMimes(Vector *mimes) const { + mimes->clear(); + for (size_t ix = 0; ix < mCaps.size(); ix++) { + mimes->push_back(mCaps.keyAt(ix)); + } +} + +const sp & +MediaCodecInfo::getCapabilitiesFor(const char *mime) const { + ssize_t ix = getCapabilityIndex(mime); + if (ix >= 0) { + return mCaps.valueAt(ix); + } + return NULL; +} + +const char *MediaCodecInfo::getCodecName() const { + return mName.c_str(); +} + +// static +sp MediaCodecInfo::FromParcel(const Parcel &parcel) { + AString name = AString::FromParcel(parcel); + bool isEncoder = static_cast(parcel.readInt32()); + sp info = new MediaCodecInfo(name, isEncoder, NULL); + size_t size = static_cast(parcel.readInt32()); + for (size_t i = 0; i < size; i++) { + AString quirk = AString::FromParcel(parcel); + if (info != NULL) { + info->mQuirks.push_back(quirk); + } + } + size = static_cast(parcel.readInt32()); + for (size_t i = 0; i < size; i++) { + AString mime = AString::FromParcel(parcel); + sp caps = Capabilities::FromParcel(parcel); + if (info != NULL) { + info->mCaps.add(mime, caps); + } + } + return info; +} + +status_t MediaCodecInfo::writeToParcel(Parcel *parcel) const { + mName.writeToParcel(parcel); + parcel->writeInt32(mIsEncoder); + parcel->writeInt32(mQuirks.size()); + for (size_t i = 0; i < mQuirks.size(); i++) { + mQuirks.itemAt(i).writeToParcel(parcel); + } + parcel->writeInt32(mCaps.size()); + for (size_t i = 0; i < mCaps.size(); i++) { + mCaps.keyAt(i).writeToParcel(parcel); + mCaps.valueAt(i)->writeToParcel(parcel); + } + return OK; +} + +ssize_t MediaCodecInfo::getCapabilityIndex(const char *mime) const { + for (size_t ix = 0; ix < mCaps.size(); ix++) { + if (mCaps.keyAt(ix).equalsIgnoreCase(mime)) { + return ix; + } + } + return -1; +} + +MediaCodecInfo::MediaCodecInfo(AString name, bool encoder, const char *mime) + : mName(name), + mIsEncoder(encoder), + mHasSoleMime(false) { + if (mime != NULL) { + addMime(mime); + mHasSoleMime = true; + } +} + +status_t MediaCodecInfo::addMime(const char *mime) { + if (mHasSoleMime) { + ALOGE("Codec '%s' already had its type specified", mName.c_str()); + return -EINVAL; + } + ssize_t ix = getCapabilityIndex(mime); + if (ix >= 0) { + mCurrentCaps = mCaps.valueAt(ix); + } else { + mCurrentCaps = new Capabilities(); + mCaps.add(AString(mime), mCurrentCaps); + } + return OK; +} + +status_t MediaCodecInfo::initializeCapabilities(const CodecCapabilities &caps) { + mCurrentCaps->mProfileLevels.clear(); + mCurrentCaps->mColorFormats.clear(); + + for (size_t i = 0; i < caps.mProfileLevels.size(); ++i) { + const CodecProfileLevel &src = caps.mProfileLevels.itemAt(i); + + ProfileLevel profileLevel; + profileLevel.mProfile = src.mProfile; + profileLevel.mLevel = src.mLevel; + mCurrentCaps->mProfileLevels.push_back(profileLevel); + } + + for (size_t i = 0; i < caps.mColorFormats.size(); ++i) { + mCurrentCaps->mColorFormats.push_back(caps.mColorFormats.itemAt(i)); + } + + mCurrentCaps->mFlags = caps.mFlags; + mCurrentCaps->mDetails = new AMessage; + + return OK; +} + +void MediaCodecInfo::addQuirk(const char *name) { + if (!hasQuirk(name)) { + mQuirks.push(name); + } +} + +void MediaCodecInfo::complete() { + mCurrentCaps = NULL; +} + +void MediaCodecInfo::addDetail(const AString &key, const AString &value) { + mCurrentCaps->mDetails->setString(key.c_str(), value.c_str()); +} + +void MediaCodecInfo::addFeature(const AString &key, int32_t value) { + AString tag = "feature-"; + tag.append(key); + mCurrentCaps->mDetails->setInt32(tag.c_str(), value); +} + +} // namespace android diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 7c02959..a67a933 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -195,16 +195,16 @@ status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) { if (tmp.endsWith(".secure")) { tmp.erase(tmp.size() - 7, 7); } - const MediaCodecList *mcl = MediaCodecList::getInstance(); + const sp mcl = MediaCodecList::getInstance(); ssize_t codecIdx = mcl->findCodecByName(tmp.c_str()); if (codecIdx >= 0) { - Vector types; - if (mcl->getSupportedTypes(codecIdx, &types) == OK) { - for (size_t i = 0; i < types.size(); i++) { - if (types[i].startsWith("video/")) { - needDedicatedLooper = true; - break; - } + const sp info = mcl->getCodecInfo(codecIdx); + Vector mimes; + info->getSupportedMimes(&mimes); + for (size_t i = 0; i < mimes.size(); i++) { + if (mimes[i].startsWith("video/")) { + needDedicatedLooper = true; + break; } } } diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index d021533..60809c1 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -18,13 +18,19 @@ #define LOG_TAG "MediaCodecList" #include -#include +#include + +#include +#include +#include #include #include +#include #include #include #include + #include #include @@ -33,18 +39,32 @@ namespace android { static Mutex sInitMutex; +static MediaCodecList *gCodecList = NULL; + // static -MediaCodecList *MediaCodecList::sCodecList; +sp MediaCodecList::sCodecList; // static -const MediaCodecList *MediaCodecList::getInstance() { +sp MediaCodecList::getLocalInstance() { Mutex::Autolock autoLock(sInitMutex); - if (sCodecList == NULL) { - sCodecList = new MediaCodecList; + if (gCodecList == NULL) { + gCodecList = new MediaCodecList; + if (gCodecList->initCheck() == OK) { + sCodecList = gCodecList; + } } - return sCodecList->initCheck() == OK ? sCodecList : NULL; + return sCodecList; +} + +static Mutex sRemoteInitMutex; + +sp MediaCodecList::sRemoteList; + +// static +sp MediaCodecList::getInstance() { + return getLocalInstance(); } MediaCodecList::MediaCodecList() @@ -59,37 +79,69 @@ void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml) { mHrefBase = AString(codecs_xml, href_base_end - codecs_xml + 1); } - mInitCheck = OK; + mInitCheck = OK; // keeping this here for safety mCurrentSection = SECTION_TOPLEVEL; mDepth = 0; + OMXClient client; + mInitCheck = client.connect(); + if (mInitCheck != OK) { + return; + } + mOMX = client.interface(); parseXMLFile(codecs_xml); + mOMX.clear(); if (mInitCheck != OK) { mCodecInfos.clear(); - mCodecQuirks.clear(); return; } for (size_t i = mCodecInfos.size(); i-- > 0;) { - CodecInfo *info = &mCodecInfos.editItemAt(i); + const MediaCodecInfo &info = *mCodecInfos.itemAt(i).get(); - if (info->mTypes == 0) { + if (info.mCaps.size() == 0) { // No types supported by this component??? ALOGW("Component %s does not support any type of media?", - info->mName.c_str()); + info.mName.c_str()); mCodecInfos.removeAt(i); #if LOG_NDEBUG == 0 } else { - for (size_t type_ix = 0; type_ix < mTypes.size(); ++type_ix) { - uint32_t typeMask = 1ul << mTypes.valueAt(type_ix); - if (info->mTypes & typeMask) { - AString mime = mTypes.keyAt(type_ix); - uint32_t bit = mTypes.valueAt(type_ix); - - ALOGV("%s codec info for %s: %s", info->mName.c_str(), mime.c_str(), - info->mCaps.editValueFor(bit)->debugString().c_str()); + for (size_t type_ix = 0; type_ix < info.mCaps.size(); ++type_ix) { + AString mime = info.mCaps.keyAt(type_ix); + const sp &caps = info.mCaps.valueAt(type_ix); + + ALOGV("%s codec info for %s: %s", info.mName.c_str(), mime.c_str(), + caps->getDetails()->debugString().c_str()); + ALOGV(" flags=%d", caps->getFlags()); + { + Vector colorFormats; + caps->getSupportedColorFormats(&colorFormats); + AString nice; + for (size_t ix = 0; ix < colorFormats.size(); ix++) { + if (ix > 0) { + nice.append(", "); + } + nice.append(colorFormats.itemAt(ix)); + } + ALOGV(" colors=[%s]", nice.c_str()); + } + { + Vector profileLevels; + caps->getSupportedProfileLevels(&profileLevels); + AString nice; + for (size_t ix = 0; ix < profileLevels.size(); ix++) { + if (ix > 0) { + nice.append(", "); + } + const MediaCodecInfo::ProfileLevel &pl = + profileLevels.itemAt(ix); + nice.append(pl.mProfile); + nice.append("/"); + nice.append(pl.mLevel); + } + ALOGV(" levels=[%s]", nice.c_str()); } } #endif @@ -294,9 +346,8 @@ void MediaCodecList::startElementHandler( case SECTION_DECODER_TYPE: case SECTION_ENCODER_TYPE: { - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); // ignore limits and features specified outside of type - bool outside = !inType && info->mSoleType == 0; + bool outside = !inType && !mCurrentInfo->mHasSoleMime; if (outside && (!strcmp(name, "Limit") || !strcmp(name, "Feature"))) { ALOGW("ignoring %s specified outside of a Type", name); } else if (!strcmp(name, "Limit")) { @@ -344,8 +395,7 @@ void MediaCodecList::endElementHandler(const char *name) { (mCurrentSection == SECTION_DECODER_TYPE ? SECTION_DECODER : SECTION_ENCODER); - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - info->mCurrentCaps = NULL; + mCurrentInfo->complete(); } break; } @@ -354,9 +404,8 @@ void MediaCodecList::endElementHandler(const char *name) { { if (!strcmp(name, "MediaCodec")) { mCurrentSection = SECTION_DECODERS; - - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - info->mCurrentCaps = NULL; + mCurrentInfo->complete(); + mCurrentInfo = NULL; } break; } @@ -365,9 +414,8 @@ void MediaCodecList::endElementHandler(const char *name) { { if (!strcmp(name, "MediaCodec")) { mCurrentSection = SECTION_ENCODERS; - - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - info->mCurrentCaps = NULL; + mCurrentInfo->complete();; + mCurrentInfo = NULL; } break; } @@ -418,28 +466,27 @@ status_t MediaCodecList::addMediaCodecFromAttributes( return -EINVAL; } - addMediaCodec(encoder, name, type); - - return OK; + mCurrentInfo = new MediaCodecInfo(name, encoder, type); + mCodecInfos.push_back(mCurrentInfo); + return initializeCapabilities(type); } -void MediaCodecList::addMediaCodec( - bool encoder, const char *name, const char *type) { - mCodecInfos.push(); - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - info->mName = name; - info->mIsEncoder = encoder; - info->mSoleType = 0; - info->mTypes = 0; - info->mQuirks = 0; - info->mCurrentCaps = NULL; - - if (type != NULL) { - addType(type); - // if type was specified in attributes, we do not allow - // subsequent types - info->mSoleType = info->mTypes; +status_t MediaCodecList::initializeCapabilities(const char *type) { + ALOGV("initializeCapabilities %s:%s", + mCurrentInfo->mName.c_str(), type); + + CodecCapabilities caps; + status_t err = QueryCodec( + mOMX, + mCurrentInfo->mName.c_str(), + type, + mCurrentInfo->mIsEncoder, + &caps); + if (err != OK) { + return err; } + + return mCurrentInfo->initializeCapabilities(caps); } status_t MediaCodecList::addQuirk(const char **attrs) { @@ -464,36 +511,13 @@ status_t MediaCodecList::addQuirk(const char **attrs) { return -EINVAL; } - uint32_t bit; - ssize_t index = mCodecQuirks.indexOfKey(name); - if (index < 0) { - bit = mCodecQuirks.size(); - - if (bit == 32) { - ALOGW("Too many distinct quirk names in configuration."); - return OK; - } - - mCodecQuirks.add(name, bit); - } else { - bit = mCodecQuirks.valueAt(index); - } - - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - info->mQuirks |= 1ul << bit; - + mCurrentInfo->addQuirk(name); return OK; } status_t MediaCodecList::addTypeFromAttributes(const char **attrs) { const char *name = NULL; - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - if (info->mSoleType != 0) { - ALOGE("Codec '%s' already had its type specified", info->mName.c_str()); - return -EINVAL; - } - size_t i = 0; while (attrs[i] != NULL) { if (!strcmp(attrs[i], "name")) { @@ -513,54 +537,47 @@ status_t MediaCodecList::addTypeFromAttributes(const char **attrs) { return -EINVAL; } - addType(name); - - return OK; -} - -void MediaCodecList::addType(const char *name) { - uint32_t bit; - ssize_t index = mTypes.indexOfKey(name); - if (index < 0) { - bit = mTypes.size(); - - if (bit == 32) { - ALOGW("Too many distinct type names in configuration."); - return; - } - - mTypes.add(name, bit); - } else { - bit = mTypes.valueAt(index); - } - - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - info->mTypes |= 1ul << bit; - if (info->mCaps.indexOfKey(bit) < 0) { - AMessage *msg = new AMessage(); - info->mCaps.add(bit, msg); + status_t ret = mCurrentInfo->addMime(name); + if (ret == OK) { + ret = initializeCapabilities(name); } - info->mCurrentCaps = info->mCaps.editValueFor(bit); + return ret; } +// legacy method for non-advanced codecs ssize_t MediaCodecList::findCodecByType( const char *type, bool encoder, size_t startIndex) const { - ssize_t typeIndex = mTypes.indexOfKey(type); + static const char *advancedFeatures[] = { + "feature-secure-playback", + "feature-tunneled-playback", + }; - if (typeIndex < 0) { - return -ENOENT; - } + size_t numCodecs = mCodecInfos.size(); + for (; startIndex < numCodecs; ++startIndex) { + const MediaCodecInfo &info = *mCodecInfos.itemAt(startIndex).get(); - uint32_t typeMask = 1ul << mTypes.valueAt(typeIndex); + if (info.isEncoder() != encoder) { + continue; + } + sp capabilities = info.getCapabilitiesFor(type); + if (capabilities == NULL) { + continue; + } + const sp &details = capabilities->getDetails(); - while (startIndex < mCodecInfos.size()) { - const CodecInfo &info = mCodecInfos.itemAt(startIndex); + int32_t required; + bool isAdvanced = false; + for (size_t ix = 0; ix < ARRAY_SIZE(advancedFeatures); ix++) { + if (details->findInt32(advancedFeatures[ix], &required) && + required != 0) { + isAdvanced = true; + break; + } + } - if (info.mIsEncoder == encoder && (info.mTypes & typeMask)) { + if (!isAdvanced) { return startIndex; } - - ++startIndex; } return -ENOENT; @@ -616,12 +633,11 @@ status_t MediaCodecList::addLimit(const char **attrs) { return -EINVAL; } - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - // size, blocks, bitrate, frame-rate, blocks-per-second, aspect-ratio: range // quality: range + default + [scale] // complexity: range + default bool found; + if (name == "aspect-ratio" || name == "bitrate" || name == "block-count" || name == "blocks-per-second" || name == "complexity" || name == "frame-rate" || name == "quality" || name == "size") { @@ -672,16 +688,16 @@ status_t MediaCodecList::addLimit(const char **attrs) { name = in_; } if (name == "quality") { - info->mCurrentCaps->setString("quality-scale", scale); + mCurrentInfo->addDetail("quality-scale", scale); } if (name == "quality" || name == "complexity") { AString tag = name; tag.append("-default"); - info->mCurrentCaps->setString(tag.c_str(), def); + mCurrentInfo->addDetail(tag, def); } AString tag = name; tag.append("-range"); - info->mCurrentCaps->setString(tag.c_str(), range); + mCurrentInfo->addDetail(tag, range); } else { AString max, value, ranges; if (msg->contains("default")) { @@ -708,13 +724,13 @@ status_t MediaCodecList::addLimit(const char **attrs) { if (max.size()) { AString tag = "max-"; tag.append(name); - info->mCurrentCaps->setString(tag.c_str(), max); + mCurrentInfo->addDetail(tag, max); } else if (value.size()) { - info->mCurrentCaps->setString(name.c_str(), value); + mCurrentInfo->addDetail(name, value); } else if (ranges.size()) { AString tag = name; tag.append("-ranges"); - info->mCurrentCaps->setString(tag.c_str(), ranges); + mCurrentInfo->addDetail(tag, ranges); } else { ALOGW("Ignoring unrecognized limit '%s'", name.c_str()); } @@ -769,16 +785,13 @@ status_t MediaCodecList::addFeature(const char **attrs) { return -EINVAL; } - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - AString tag = "feature-"; - tag.append(name); - info->mCurrentCaps->setInt32(tag.c_str(), (required == 1) || (optional == 0)); + mCurrentInfo->addFeature(name, (required == 1) || (optional == 0)); return OK; } ssize_t MediaCodecList::findCodecByName(const char *name) const { for (size_t i = 0; i < mCodecInfos.size(); ++i) { - const CodecInfo &info = mCodecInfos.itemAt(i); + const MediaCodecInfo &info = *mCodecInfos.itemAt(i).get(); if (info.mName == name) { return i; @@ -792,121 +805,4 @@ size_t MediaCodecList::countCodecs() const { return mCodecInfos.size(); } -const char *MediaCodecList::getCodecName(size_t index) const { - if (index >= mCodecInfos.size()) { - return NULL; - } - - const CodecInfo &info = mCodecInfos.itemAt(index); - return info.mName.c_str(); -} - -bool MediaCodecList::isEncoder(size_t index) const { - if (index >= mCodecInfos.size()) { - return false; - } - - const CodecInfo &info = mCodecInfos.itemAt(index); - return info.mIsEncoder; -} - -bool MediaCodecList::codecHasQuirk( - size_t index, const char *quirkName) const { - if (index >= mCodecInfos.size()) { - return false; - } - - const CodecInfo &info = mCodecInfos.itemAt(index); - - if (info.mQuirks != 0) { - ssize_t index = mCodecQuirks.indexOfKey(quirkName); - if (index >= 0 && info.mQuirks & (1ul << mCodecQuirks.valueAt(index))) { - return true; - } - } - - return false; -} - -status_t MediaCodecList::getSupportedTypes( - size_t index, Vector *types) const { - types->clear(); - - if (index >= mCodecInfos.size()) { - return -ERANGE; - } - - const CodecInfo &info = mCodecInfos.itemAt(index); - - for (size_t i = 0; i < mTypes.size(); ++i) { - uint32_t typeMask = 1ul << mTypes.valueAt(i); - - if (info.mTypes & typeMask) { - types->push(mTypes.keyAt(i)); - } - } - - return OK; -} - -status_t MediaCodecList::getCodecCapabilities( - size_t index, const char *type, - Vector *profileLevels, - Vector *colorFormats, - uint32_t *flags, - sp *capabilities) const { - profileLevels->clear(); - colorFormats->clear(); - - if (index >= mCodecInfos.size()) { - return -ERANGE; - } - - const CodecInfo &info = mCodecInfos.itemAt(index); - - ssize_t typeIndex = mTypes.indexOfKey(type); - if (typeIndex < 0) { - return -EINVAL; - } - // essentially doing valueFor without the CHECK abort - typeIndex = mTypes.valueAt(typeIndex); - - OMXClient client; - status_t err = client.connect(); - if (err != OK) { - return err; - } - - CodecCapabilities caps; - err = QueryCodec( - client.interface(), - info.mName.c_str(), type, info.mIsEncoder, &caps); - - if (err != OK) { - return err; - } - - for (size_t i = 0; i < caps.mProfileLevels.size(); ++i) { - const CodecProfileLevel &src = caps.mProfileLevels.itemAt(i); - - ProfileLevel profileLevel; - profileLevel.mProfile = src.mProfile; - profileLevel.mLevel = src.mLevel; - profileLevels->push(profileLevel); - } - - for (size_t i = 0; i < caps.mColorFormats.size(); ++i) { - colorFormats->push(caps.mColorFormats.itemAt(i)); - } - - *flags = caps.mFlags; - - // TODO this check will be removed once JNI side is merged - if (capabilities != NULL) { - *capabilities = info.mCaps.valueFor(typeIndex); - } - - return OK; -} - } // namespace android diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 354712c..da590a2 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -197,7 +197,7 @@ void OMXCodec::findMatchingCodecs( Vector *matchingCodecs) { matchingCodecs->clear(); - const MediaCodecList *list = MediaCodecList::getInstance(); + const sp list = MediaCodecList::getInstance(); if (list == NULL) { return; } @@ -213,7 +213,9 @@ void OMXCodec::findMatchingCodecs( index = matchIndex + 1; - const char *componentName = list->getCodecName(matchIndex); + const sp info = list->getCodecInfo(matchIndex); + CHECK(info != NULL); + const char *componentName = info->getCodecName(); // If a specific codec is requested, skip the non-matching ones. if (matchComponentName && strcmp(componentName, matchComponentName)) { @@ -231,7 +233,7 @@ void OMXCodec::findMatchingCodecs( ssize_t index = matchingCodecs->add(); CodecNameAndQuirks *entry = &matchingCodecs->editItemAt(index); entry->mName = String8(componentName); - entry->mQuirks = getComponentQuirks(list, matchIndex); + entry->mQuirks = getComponentQuirks(info); ALOGV("matching '%s' quirks 0x%08x", entry->mName.string(), entry->mQuirks); @@ -245,18 +247,15 @@ void OMXCodec::findMatchingCodecs( // static uint32_t OMXCodec::getComponentQuirks( - const MediaCodecList *list, size_t index) { + const sp &info) { uint32_t quirks = 0; - if (list->codecHasQuirk( - index, "requires-allocate-on-input-ports")) { + if (info->hasQuirk("requires-allocate-on-input-ports")) { quirks |= kRequiresAllocateBufferOnInputPorts; } - if (list->codecHasQuirk( - index, "requires-allocate-on-output-ports")) { + if (info->hasQuirk("requires-allocate-on-output-ports")) { quirks |= kRequiresAllocateBufferOnOutputPorts; } - if (list->codecHasQuirk( - index, "output-buffers-are-unreadable")) { + if (info->hasQuirk("output-buffers-are-unreadable")) { quirks |= kOutputBuffersAreUnreadable; } @@ -265,8 +264,7 @@ uint32_t OMXCodec::getComponentQuirks( // static bool OMXCodec::findCodecQuirks(const char *componentName, uint32_t *quirks) { - const MediaCodecList *list = MediaCodecList::getInstance(); - + const sp list = MediaCodecList::getInstance(); if (list == NULL) { return false; } @@ -277,7 +275,9 @@ bool OMXCodec::findCodecQuirks(const char *componentName, uint32_t *quirks) { return false; } - *quirks = getComponentQuirks(list, index); + const sp info = list->getCodecInfo(index); + CHECK(info != NULL); + *quirks = getComponentQuirks(info); return true; } -- cgit v1.1 From 1381d4b5c0385aec3741073e5998773b064c1fb0 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 7 Aug 2014 15:18:35 -0700 Subject: media/playerservice: add getCodecList() to MediaPlayerService Bug: 11990470 Change-Id: I8fa45946fd9b76f9b975fc59062819c57e6881ef --- media/libmedia/IMediaPlayerService.cpp | 15 +++++++++++++++ media/libmediaplayerservice/MediaPlayerService.cpp | 5 +++++ media/libmediaplayerservice/MediaPlayerService.h | 1 + media/libstagefright/MediaCodecList.cpp | 17 ++++++++++++++++- 4 files changed, 37 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index d116b14..2e02d17 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ enum { ADD_BATTERY_DATA, PULL_BATTERY_DATA, LISTEN_FOR_REMOTE_DISPLAY, + GET_CODEC_LIST, }; class BpMediaPlayerService: public BpInterface @@ -191,6 +193,13 @@ public: remote()->transact(LISTEN_FOR_REMOTE_DISPLAY, data, &reply); return interface_cast(reply.readStrongBinder()); } + + virtual sp getCodecList() const { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + remote()->transact(GET_CODEC_LIST, data, &reply); + return interface_cast(reply.readStrongBinder()); + } }; IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService"); @@ -318,6 +327,12 @@ status_t BnMediaPlayerService::onTransact( reply->writeStrongBinder(display->asBinder()); return NO_ERROR; } break; + case GET_CODEC_LIST: { + CHECK_INTERFACE(IMediaPlayerService, data, reply); + sp mcl = getCodecList(); + reply->writeStrongBinder(mcl->asBinder()); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 735344c..a706987 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -345,6 +346,10 @@ sp MediaPlayerService::create(const sp& client return c; } +sp MediaPlayerService::getCodecList() const { + return MediaCodecList::getLocalInstance(); +} + sp MediaPlayerService::getOMX() { Mutex::Autolock autoLock(mLock); diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 2eca6a0..406e3f6 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -273,6 +273,7 @@ public: uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat, const sp& heap, size_t *pSize); + virtual sp getCodecList() const; virtual sp getOMX(); virtual sp makeCrypto(); virtual sp makeDrm(); diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index 60809c1..7f8b7f5 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -64,7 +64,22 @@ sp MediaCodecList::sRemoteList; // static sp MediaCodecList::getInstance() { - return getLocalInstance(); + Mutex::Autolock _l(sRemoteInitMutex); + if (sRemoteList == NULL) { + sp binder = + defaultServiceManager()->getService(String16("media.player")); + sp service = + interface_cast(binder); + if (service.get() != NULL) { + sRemoteList = service->getCodecList(); + } + + if (sRemoteList == NULL) { + // if failed to get remote list, create local list + sRemoteList = getLocalInstance(); + } + } + return sRemoteList; } MediaCodecList::MediaCodecList() -- cgit v1.1 From 229d242665c612fd97431d1e7ac004823b47f181 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 7 Aug 2014 14:16:23 -0700 Subject: stagefright: support flexible YUV format - Report flexible format for standard OMX formats that are flexible. - Accept flexible format when specifying video port formats. Bug: 10706245 Change-Id: I9e82bc895bb0d5d606eb05fdf83bec766eaa2046 --- media/libstagefright/ACodec.cpp | 91 ++++++++++++++++++++++++++++++++------- media/libstagefright/OMXCodec.cpp | 20 ++++++++- 2 files changed, 95 insertions(+), 16 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index b81674d..3c0f6e3 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -1806,6 +1806,17 @@ status_t ACodec::setVideoPortFormatType( return err; } + // substitute back flexible color format to codec supported format + OMX_U32 flexibleEquivalent; + if (compressionFormat == OMX_VIDEO_CodingUnused && + isFlexibleColorFormat( + mOMX, mNode, format.eColorFormat, &flexibleEquivalent) && + colorFormat == flexibleEquivalent) { + ALOGI("[%s] using color format %#x in place of %#x", + mComponentName.c_str(), format.eColorFormat, colorFormat); + colorFormat = format.eColorFormat; + } + // The following assertion is violated by TI's video decoder. // CHECK_EQ(format.nIndex, index); @@ -2782,7 +2793,7 @@ void ACodec::processDeferredMessages() { } // static -void ACodec::describeDefaultColorFormat(DescribeColorFormatParams ¶ms) { +bool ACodec::describeDefaultColorFormat(DescribeColorFormatParams ¶ms) { MediaImage &image = params.sMediaImage; memset(&image, 0, sizeof(image)); @@ -2794,7 +2805,7 @@ void ACodec::describeDefaultColorFormat(DescribeColorFormatParams ¶ms) { if (params.nStride == 0 || params.nSliceHeight == 0) { ALOGW("cannot describe color format 0x%x = %d with stride=%u and sliceHeight=%u", fmt, fmt, params.nStride, params.nSliceHeight); - return; + return false; } image.mWidth = params.nFrameWidth; @@ -2806,7 +2817,7 @@ void ACodec::describeDefaultColorFormat(DescribeColorFormatParams ¶ms) { fmt != OMX_COLOR_FormatYUV420SemiPlanar && fmt != OMX_COLOR_FormatYUV420PackedSemiPlanar) { ALOGW("do not know color format 0x%x = %d", fmt, fmt); - return; + return false; } // set-up YUV format @@ -2856,6 +2867,67 @@ void ACodec::describeDefaultColorFormat(DescribeColorFormatParams ¶ms) { default: TRESPASS(); } + return true; +} + +// static +bool ACodec::describeColorFormat( + const sp &omx, IOMX::node_id node, + DescribeColorFormatParams &describeParams) +{ + OMX_INDEXTYPE describeColorFormatIndex; + if (omx->getExtensionIndex( + node, "OMX.google.android.index.describeColorFormat", + &describeColorFormatIndex) != OK || + omx->getParameter( + node, describeColorFormatIndex, + &describeParams, sizeof(describeParams)) != OK) { + return describeDefaultColorFormat(describeParams); + } + return describeParams.sMediaImage.mType != + MediaImage::MEDIA_IMAGE_TYPE_UNKNOWN; +} + +// static +bool ACodec::isFlexibleColorFormat( + const sp &omx, IOMX::node_id node, + uint32_t colorFormat, OMX_U32 *flexibleEquivalent) { + DescribeColorFormatParams describeParams; + InitOMXParams(&describeParams); + describeParams.eColorFormat = (OMX_COLOR_FORMATTYPE)colorFormat; + // reasonable dummy values + describeParams.nFrameWidth = 128; + describeParams.nFrameHeight = 128; + describeParams.nStride = 128; + describeParams.nSliceHeight = 128; + + CHECK(flexibleEquivalent != NULL); + + if (!describeColorFormat(omx, node, describeParams)) { + return false; + } + + const MediaImage &img = describeParams.sMediaImage; + if (img.mType == MediaImage::MEDIA_IMAGE_TYPE_YUV) { + if (img.mNumPlanes != 3 || + img.mPlane[img.Y].mHorizSubsampling != 1 || + img.mPlane[img.Y].mVertSubsampling != 1) { + return false; + } + + // YUV 420 + if (img.mPlane[img.U].mHorizSubsampling == 2 + && img.mPlane[img.U].mVertSubsampling == 2 + && img.mPlane[img.V].mHorizSubsampling == 2 + && img.mPlane[img.V].mVertSubsampling == 2) { + // possible flexible YUV420 format + if (img.mBitDepth <= 8) { + *flexibleEquivalent = OMX_COLOR_FormatYUV420Flexible; + return true; + } + } + } + return false; } status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { @@ -2885,7 +2957,6 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { notify->setInt32("slice-height", videoDef->nSliceHeight); notify->setInt32("color-format", videoDef->eColorFormat); - DescribeColorFormatParams describeParams; InitOMXParams(&describeParams); describeParams.eColorFormat = videoDef->eColorFormat; @@ -2894,17 +2965,7 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { describeParams.nStride = videoDef->nStride; describeParams.nSliceHeight = videoDef->nSliceHeight; - OMX_INDEXTYPE describeColorFormatIndex; - if (mOMX->getExtensionIndex( - mNode, "OMX.google.android.index.describeColorFormat", - &describeColorFormatIndex) || - mOMX->getParameter( - mNode, describeColorFormatIndex, - &describeParams, sizeof(describeParams))) { - describeDefaultColorFormat(describeParams); - } - - if (describeParams.sMediaImage.mType != MediaImage::MEDIA_IMAGE_TYPE_UNKNOWN) { + if (describeColorFormat(mOMX, mNode, describeParams)) { notify->setBuffer( "image-data", ABuffer::CreateAsCopy( diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index da590a2..3d1d40e 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -1551,7 +1552,7 @@ OMXCodec::~OMXCodec() { status_t err = mOMX->freeNode(mNode); CHECK_EQ(err, (status_t)OK); - mNode = NULL; + mNode = 0; setState(DEAD); clearCodecSpecificData(); @@ -4746,6 +4747,8 @@ status_t QueryCodec( } // Color format query + // return colors in the order reported by the OMX component + // prefix "flexible" standard ones with the flexible equivalent OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat; InitOMXParams(&portFormat); portFormat.nPortIndex = !isEncoder ? 1 : 0; @@ -4756,6 +4759,21 @@ status_t QueryCodec( if (err != OK) { break; } + + OMX_U32 flexibleEquivalent; + if (ACodec::isFlexibleColorFormat( + omx, node, portFormat.eColorFormat, &flexibleEquivalent)) { + bool marked = false; + for (size_t i = 0; i < caps->mColorFormats.size(); i++) { + if (caps->mColorFormats.itemAt(i) == flexibleEquivalent) { + marked = true; + break; + } + } + if (!marked) { + caps->mColorFormats.push(flexibleEquivalent); + } + } caps->mColorFormats.push(portFormat.eColorFormat); } -- cgit v1.1 From 1198a3394a21d3c31b19395b124c77f09a8f0924 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 7 Aug 2014 21:38:10 -0700 Subject: libstagefright_foundation: fix build Change-Id: If61766efa8834df175bd5758c760344364458d4a --- media/libstagefright/foundation/AString.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp index 1befef4..bf474e1 100644 --- a/media/libstagefright/foundation/AString.cpp +++ b/media/libstagefright/foundation/AString.cpp @@ -358,7 +358,7 @@ AString AString::FromParcel(const Parcel &parcel) { } status_t AString::writeToParcel(Parcel *parcel) const { - CHECK_LE(mSize, INT32_MAX); + CHECK_LE(mSize, (size_t)INT32_MAX); status_t err = parcel->writeInt32(mSize); if (err == OK) { err = parcel->write(mData, mSize); -- cgit v1.1 From a19f33e4e50cda5d5953fa0cc662502262ac9dfd Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 7 Aug 2014 15:35:07 -0700 Subject: delay data source creation for GenericSource prepare time Bug: 16708180 Change-Id: I9d578ef5e2edaed50279d28d3831c68556468f39 --- .../nuplayer/GenericSource.cpp | 80 ++++++++++++++++++---- .../libmediaplayerservice/nuplayer/GenericSource.h | 13 +++- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 8 +-- 3 files changed, 80 insertions(+), 21 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 9df3f53..1616448 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -21,6 +21,7 @@ #include "AnotherPacketSource.h" +#include #include #include #include @@ -47,33 +48,48 @@ NuPlayer::GenericSource::GenericSource( mIsWidevine(false), mUIDValid(uidValid), mUID(uid) { + resetDataSource(); DataSource::RegisterDefaultSniffers(); } -status_t NuPlayer::GenericSource::init( +void NuPlayer::GenericSource::resetDataSource() { + mHTTPService.clear(); + mUri.clear(); + mUriHeaders.clear(); + mFd = -1; + mOffset = 0; + mLength = 0; +} + +status_t NuPlayer::GenericSource::setDataSource( const sp &httpService, const char *url, const KeyedVector *headers) { - mIsWidevine = !strncasecmp(url, "widevine://", 11); - - AString sniffedMIME; + resetDataSource(); - sp dataSource = - DataSource::CreateFromURI(httpService, url, headers, &sniffedMIME); + mHTTPService = httpService; + mUri = url; - if (dataSource == NULL) { - return UNKNOWN_ERROR; + if (headers) { + mUriHeaders = *headers; } - return initFromDataSource( - dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); + // delay data source creation to prepareAsync() to avoid blocking + // the calling thread in setDataSource for any significant time. + return OK; } -status_t NuPlayer::GenericSource::init( +status_t NuPlayer::GenericSource::setDataSource( int fd, int64_t offset, int64_t length) { - sp dataSource = new FileSource(dup(fd), offset, length); + resetDataSource(); + + mFd = dup(fd); + mOffset = offset; + mLength = length; - return initFromDataSource(dataSource, NULL); + // delay data source creation to prepareAsync() to avoid blocking + // the calling thread in setDataSource for any significant time. + return OK; } status_t NuPlayer::GenericSource::initFromDataSource( @@ -143,7 +159,8 @@ status_t NuPlayer::GenericSource::initFromDataSource( // check if the source requires secure buffers int32_t secure; - if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) && secure) { + if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) + && secure) { mIsWidevine = true; if (mUIDValid) { extractor->setUID(mUID); @@ -166,7 +183,8 @@ status_t NuPlayer::GenericSource::initFromDataSource( return OK; } -status_t NuPlayer::GenericSource::setBuffers(bool audio, Vector &buffers) { +status_t NuPlayer::GenericSource::setBuffers( + bool audio, Vector &buffers) { if (mIsWidevine && !audio) { return mVideoTrack.mSource->setBuffers(buffers); } @@ -177,6 +195,38 @@ NuPlayer::GenericSource::~GenericSource() { } void NuPlayer::GenericSource::prepareAsync() { + // delayed data source creation + AString sniffedMIME; + sp dataSource; + + if (!mUri.empty()) { + mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11); + + dataSource = DataSource::CreateFromURI( + mHTTPService, mUri.c_str(), &mUriHeaders, &sniffedMIME); + } else { + // set to false first, if the extractor + // comes back as secure, set it to true then. + mIsWidevine = false; + + dataSource = new FileSource(mFd, mOffset, mLength); + } + + if (dataSource == NULL) { + ALOGE("Failed to create data source!"); + notifyPrepared(UNKNOWN_ERROR); + return; + } + + status_t err = initFromDataSource( + dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); + + if (err != OK) { + ALOGE("Failed to init from data source!"); + notifyPrepared(err); + return; + } + if (mVideoTrack.mSource != NULL) { sp meta = mVideoTrack.mSource->getFormat(); diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 76e628b..44d690e 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -30,18 +30,19 @@ namespace android { struct AnotherPacketSource; struct ARTSPController; struct DataSource; +struct IMediaHTTPService; struct MediaSource; class MediaBuffer; struct NuPlayer::GenericSource : public NuPlayer::Source { GenericSource(const sp ¬ify, bool uidValid, uid_t uid); - status_t init( + status_t setDataSource( const sp &httpService, const char *url, const KeyedVector *headers); - status_t init(int fd, int64_t offset, int64_t length); + status_t setDataSource(int fd, int64_t offset, int64_t length); virtual void prepareAsync(); @@ -96,6 +97,14 @@ private: bool mIsWidevine; bool mUIDValid; uid_t mUID; + sp mHTTPService; + AString mUri; + KeyedVector mUriHeaders; + int mFd; + int64_t mOffset; + int64_t mLength; + + void resetDataSource(); status_t initFromDataSource( const sp &dataSource, diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index ba6fb7d..fe115c6 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -232,12 +232,12 @@ void NuPlayer::setDataSourceAsync( // The correct flags will be updated in Source::kWhatFlagsChanged // handler when GenericSource is prepared. - status_t err = genericSource->init(httpService, url, headers); + status_t err = genericSource->setDataSource(httpService, url, headers); if (err == OK) { source = genericSource; } else { - ALOGE("Failed to initialize generic source!"); + ALOGE("Failed to set data source!"); } } msg->setObject("source", source); @@ -252,10 +252,10 @@ void NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) { sp source = new GenericSource(notify, mUIDValid, mUID); - status_t err = source->init(fd, offset, length); + status_t err = source->setDataSource(fd, offset, length); if (err != OK) { - ALOGE("Failed to initialize generic source!"); + ALOGE("Failed to set data source!"); source = NULL; } -- cgit v1.1 From e17bb5cafdbc6089716d8e8c5afbb00f207a59bb Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 8 Aug 2014 11:43:41 +0200 Subject: Fix PIC relocations for non-Bsymbolic builds The ARM assembly contains a couple of hand-coded PC relative references to data defined in other object files. Make sure the externs are tagged as hidden so the linker knows that it can resolve the reference locally at build time. Signed-off-by: Ard Biesheuvel Bug: 16853291 Change-Id: If7bc8e5bb6a2c63b9df33666d56e6c42f398fd47 (cherry picked from commit 97e3e847179c17eb9059fb322413b6facd3e5a03) --- .../codecs/amrwbenc/src/asm/ARMV5E/Filt_6k_7k_opt.s | 1 + .../codecs/amrwbenc/src/asm/ARMV5E/pred_lt4_1_opt.s | 1 + .../codecs/amrwbenc/src/asm/ARMV7/Filt_6k_7k_neon.s | 1 + .../codecs/amrwbenc/src/asm/ARMV7/pred_lt4_1_neon.s | 1 + .../mp3dec/src/asm/pvmp3_polyphase_filter_window_gcc.s | 1 + .../vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S | 16 ++++++++++++++++ .../vc/m4p10/src_gcc/armVCM4P10_DequantTables_s.S | 8 ++++++++ 7 files changed, 29 insertions(+) (limited to 'media') diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Filt_6k_7k_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Filt_6k_7k_opt.s index 8451195..f23b5a0 100644 --- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Filt_6k_7k_opt.s +++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Filt_6k_7k_opt.s @@ -29,6 +29,7 @@ .global Filt_6k_7k_asm .extern voAWB_Copy .extern fir_6k_7k + .hidden fir_6k_7k Filt_6k_7k_asm: diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/pred_lt4_1_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/pred_lt4_1_opt.s index ac2dd13..deb7efc 100644 --- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/pred_lt4_1_opt.s +++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/pred_lt4_1_opt.s @@ -32,6 +32,7 @@ .section .text .global pred_lt4_asm .extern inter4_2 + .hidden inter4_2 pred_lt4_asm: diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Filt_6k_7k_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Filt_6k_7k_neon.s index fc42a03..8df0caa 100644 --- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Filt_6k_7k_neon.s +++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Filt_6k_7k_neon.s @@ -28,6 +28,7 @@ .section .text .global Filt_6k_7k_asm .extern fir_6k_7k + .hidden fir_6k_7k Filt_6k_7k_asm: diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/pred_lt4_1_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/pred_lt4_1_neon.s index 8d2aaf2..67be1ed 100644 --- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/pred_lt4_1_neon.s +++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/pred_lt4_1_neon.s @@ -29,6 +29,7 @@ .section .text .global pred_lt4_asm .extern inter4_2 + .hidden inter4_2 pred_lt4_asm: diff --git a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_gcc.s b/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_gcc.s index b74c849..1140ed7 100644 --- a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_gcc.s +++ b/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_gcc.s @@ -35,6 +35,7 @@ .text .extern pqmfSynthWin +.hidden pqmfSynthWin diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S index 073dbba..bcc6b6b 100644 --- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S +++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S @@ -10,6 +10,22 @@ .fpu neon .text + .extern armVCM4P10_CAVLCCoeffTokenTables + .extern armVCM4P10_SuffixToLevel + .extern armVCM4P10_CAVLCTotalZeros2x2Tables + .extern armVCM4P10_CAVLCTotalZeroTables + .extern armVCM4P10_CAVLCRunBeforeTables + .extern armVCM4P10_ZigZag_2x2 + .extern armVCM4P10_ZigZag_4x4 + + .hidden armVCM4P10_CAVLCCoeffTokenTables + .hidden armVCM4P10_SuffixToLevel + .hidden armVCM4P10_CAVLCTotalZeros2x2Tables + .hidden armVCM4P10_CAVLCTotalZeroTables + .hidden armVCM4P10_CAVLCRunBeforeTables + .hidden armVCM4P10_ZigZag_2x2 + .hidden armVCM4P10_ZigZag_4x4 + .global armVCM4P10_DecodeCoeffsToPair .func armVCM4P10_DecodeCoeffsToPair armVCM4P10_DecodeCoeffsToPair: diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DequantTables_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DequantTables_s.S index 44eb428..5bc7875 100644 --- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DequantTables_s.S +++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DequantTables_s.S @@ -20,6 +20,14 @@ .global armVCM4P10_QPModuloTable .global armVCM4P10_VMatrixU16 + .hidden armVCM4P10_QPDivTable + .hidden armVCM4P10_VMatrixQPModTable + .hidden armVCM4P10_PosToVCol4x4 + .hidden armVCM4P10_PosToVCol2x2 + .hidden armVCM4P10_VMatrix + .hidden armVCM4P10_QPModuloTable + .hidden armVCM4P10_VMatrixU16 + armVCM4P10_PosToVCol4x4: .byte 0, 2, 0, 2 .byte 2, 1, 2, 1 -- cgit v1.1 From e43f501f3d4fda8578da519fc50d9156d8828e3a Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Thu, 7 Aug 2014 22:21:08 -0700 Subject: Fix the build after -Bsymbolic fix. Bug: 16853291 Change-Id: Idc9808f76e8be7afb70513c4036b57c91690728e (cherry picked from commit 8173554d5b5e25215e9c591a0dbb92b8c0ff082e) --- media/libstagefright/codecs/hevcdec/Android.mk | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'media') diff --git a/media/libstagefright/codecs/hevcdec/Android.mk b/media/libstagefright/codecs/hevcdec/Android.mk index 960602f..c0c694e 100644 --- a/media/libstagefright/codecs/hevcdec/Android.mk +++ b/media/libstagefright/codecs/hevcdec/Android.mk @@ -20,6 +20,10 @@ LOCAL_SHARED_LIBRARIES += libstagefright_foundation LOCAL_SHARED_LIBRARIES += libutils LOCAL_SHARED_LIBRARIES += liblog +# We need this because the current asm generates the following link error: +# requires unsupported dynamic reloc R_ARM_REL32; recompile with -fPIC +# Bug: 16853291 +LOCAL_LDFLAGS := -Wl,-Bsymbolic include $(BUILD_SHARED_LIBRARY) -- cgit v1.1 From 8045853d03649f43ea2f7107e7d2dbb9b2d20855 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Fri, 1 Aug 2014 22:17:48 -0700 Subject: AAC decoder: add support for controlling presentation parameters Control the dowmixing of the AAC decoder Control the DRC processing of the AAC decoder Bug 16740915 Change-Id: I9b06ea8785f56213ea120ed85eeb360c88223297 --- media/libstagefright/ACodec.cpp | 50 +++++++++++++++++-- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 66 ++++++++++++++++++++++++- 2 files changed, 111 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index b81674d..1808d07 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -1290,6 +1290,8 @@ status_t ACodec::configureCodec( } else { int32_t isADTS, aacProfile; int32_t sbrMode; + int32_t maxOutputChannelCount; + drcParams_t drc; if (!msg->findInt32("is-adts", &isADTS)) { isADTS = 0; } @@ -1300,9 +1302,33 @@ status_t ACodec::configureCodec( sbrMode = -1; } + if (!msg->findInt32("aac-max-output-channel_count", &maxOutputChannelCount)) { + maxOutputChannelCount = -1; + } + if (!msg->findInt32("aac-encoded-target-level", &drc.encodedTargetLevel)) { + // value is unknown + drc.encodedTargetLevel = -1; + } + if (!msg->findInt32("aac-drc-cut-level", &drc.drcCut)) { + // value is unknown + drc.drcCut = -1; + } + if (!msg->findInt32("aac-drc-boost-level", &drc.drcBoost)) { + // value is unknown + drc.drcBoost = -1; + } + if (!msg->findInt32("aac-drc-heavy-compression", &drc.heavyCompression)) { + // value is unknown + drc.heavyCompression = -1; + } + if (!msg->findInt32("aac-target-ref-level", &drc.targetRefLevel)) { + // value is unknown + drc.targetRefLevel = -1; + } + err = setupAACCodec( encoder, numChannels, sampleRate, bitRate, aacProfile, - isADTS != 0, sbrMode); + isADTS != 0, sbrMode, maxOutputChannelCount, drc); } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) { err = setupAMRCodec(encoder, false /* isWAMR */, bitRate); @@ -1464,7 +1490,8 @@ status_t ACodec::selectAudioPortFormat( status_t ACodec::setupAACCodec( bool encoder, int32_t numChannels, int32_t sampleRate, - int32_t bitRate, int32_t aacProfile, bool isADTS, int32_t sbrMode) { + int32_t bitRate, int32_t aacProfile, bool isADTS, int32_t sbrMode, + int32_t maxOutputChannelCount, const drcParams_t& drc) { if (encoder && isADTS) { return -EINVAL; } @@ -1587,8 +1614,23 @@ status_t ACodec::setupAACCodec( ? OMX_AUDIO_AACStreamFormatMP4ADTS : OMX_AUDIO_AACStreamFormatMP4FF; - return mOMX->setParameter( - mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); + OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE presentation; + presentation.nMaxOutputChannels = maxOutputChannelCount; + presentation.nDrcCut = drc.drcCut; + presentation.nDrcBoost = drc.drcBoost; + presentation.nHeavyCompression = drc.heavyCompression; + presentation.nTargetReferenceLevel = drc.targetRefLevel; + presentation.nEncodedTargetLevel = drc.encodedTargetLevel; + + status_t res = mOMX->setParameter(mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); + if (res == OK) { + // optional parameters, will not cause configuration failure + mOMX->setParameter(mNode, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAacPresentation, + &presentation, sizeof(presentation)); + } else { + ALOGW("did not set AudioAndroidAacPresentation due to error %d when setting AudioAac", res); + } + return res; } status_t ACodec::setupAC3Codec( diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index ab30865..09c6e69 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -19,6 +19,8 @@ #include #include "SoftAAC2.h" +#include +#include #include #include @@ -119,6 +121,7 @@ void SoftAAC2::initPorts() { } status_t SoftAAC2::initDecoder() { + ALOGV("initDecoder()"); status_t status = UNKNOWN_ERROR; mAACDecoder = aacDecoder_Open(TT_MP4_ADIF, /* num layers */ 1); if (mAACDecoder != NULL) { @@ -275,7 +278,7 @@ OMX_ERRORTYPE SoftAAC2::internalGetParameter( OMX_ERRORTYPE SoftAAC2::internalSetParameter( OMX_INDEXTYPE index, const OMX_PTR params) { - switch (index) { + switch ((int)index) { case OMX_IndexParamStandardComponentRole: { const OMX_PARAM_COMPONENTROLETYPE *roleParams = @@ -311,6 +314,67 @@ OMX_ERRORTYPE SoftAAC2::internalSetParameter( return OMX_ErrorNone; } + case OMX_IndexParamAudioAndroidAacPresentation: + { + const OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE *aacPresParams = + (const OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE *)params; + // for the following parameters of the OMX_AUDIO_PARAM_AACPROFILETYPE structure, + // a value of -1 implies the parameter is not set by the application: + // nMaxOutputChannels uses default platform properties, see configureDownmix() + // nDrcCut uses default platform properties, see initDecoder() + // nDrcBoost idem + // nHeavyCompression idem + // nTargetReferenceLevel idem + // nEncodedTargetLevel idem + if (aacPresParams->nMaxOutputChannels >= 0) { + int max; + if (aacPresParams->nMaxOutputChannels >= 8) { max = 8; } + else if (aacPresParams->nMaxOutputChannels >= 6) { max = 6; } + else if (aacPresParams->nMaxOutputChannels >= 2) { max = 2; } + else { + // -1 or 0: disable downmix, 1: mono + max = aacPresParams->nMaxOutputChannels; + } + ALOGV("set nMaxOutputChannels=%d", max); + aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, max); + } + bool updateDrcWrapper = false; + if (aacPresParams->nDrcBoost >= 0) { + ALOGV("set nDrcBoost=%d", aacPresParams->nDrcBoost); + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, + aacPresParams->nDrcBoost); + updateDrcWrapper = true; + } + if (aacPresParams->nDrcCut >= 0) { + ALOGV("set nDrcCut=%d", aacPresParams->nDrcCut); + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, aacPresParams->nDrcCut); + updateDrcWrapper = true; + } + if (aacPresParams->nHeavyCompression >= 0) { + ALOGV("set nHeavyCompression=%d", aacPresParams->nHeavyCompression); + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, + aacPresParams->nHeavyCompression); + updateDrcWrapper = true; + } + if (aacPresParams->nTargetReferenceLevel >= 0) { + ALOGV("set nTargetReferenceLevel=%d", aacPresParams->nTargetReferenceLevel); + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, + aacPresParams->nTargetReferenceLevel); + updateDrcWrapper = true; + } + if (aacPresParams->nEncodedTargetLevel >= 0) { + ALOGV("set nEncodedTargetLevel=%d", aacPresParams->nEncodedTargetLevel); + mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, + aacPresParams->nEncodedTargetLevel); + updateDrcWrapper = true; + } + if (updateDrcWrapper) { + mDrcWrap.update(); + } + + return OMX_ErrorNone; + } + case OMX_IndexParamAudioPcm: { const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = -- cgit v1.1 From 55971df8768a2e613717a14251d56993b9322b5e Mon Sep 17 00:00:00 2001 From: Sasha Levitskiy Date: Fri, 8 Aug 2014 09:47:37 -0700 Subject: libstagefright: foundation: Add syntactic sugar to the cast. Change-Id: I0b6b3ae440addd4891c26b0639bd6e647a7b031e --- media/libstagefright/foundation/AString.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp index bf474e1..9835ca3 100644 --- a/media/libstagefright/foundation/AString.cpp +++ b/media/libstagefright/foundation/AString.cpp @@ -358,7 +358,7 @@ AString AString::FromParcel(const Parcel &parcel) { } status_t AString::writeToParcel(Parcel *parcel) const { - CHECK_LE(mSize, (size_t)INT32_MAX); + CHECK_LE(mSize, static_cast(INT32_MAX)); status_t err = parcel->writeInt32(mSize); if (err == OK) { err = parcel->write(mData, mSize); -- cgit v1.1 From ced1c2f8f6c422063092f5cc5c675ccdebb2dc10 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Fri, 8 Aug 2014 15:22:35 -0700 Subject: some clean up of video size change notification need to consider rotation when notifying video size change after initial prepare, in addition to after an output format change. Bug: 16870964 Change-Id: Icd1c9e901ac932e720ce95b8a983c0edcf251c35 --- .../nuplayer/GenericSource.cpp | 8 +- .../nuplayer/HTTPLiveSource.cpp | 4 +- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 184 +++++++++++---------- media/libmediaplayerservice/nuplayer/NuPlayer.h | 4 + .../nuplayer/NuPlayerSource.h | 2 +- .../libmediaplayerservice/nuplayer/RTSPSource.cpp | 2 +- .../nuplayer/StreamingSource.cpp | 2 +- 7 files changed, 109 insertions(+), 97 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 1616448..6676461 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -228,13 +228,7 @@ void NuPlayer::GenericSource::prepareAsync() { } if (mVideoTrack.mSource != NULL) { - sp meta = mVideoTrack.mSource->getFormat(); - - int32_t width, height; - CHECK(meta->findInt32(kKeyWidth, &width)); - CHECK(meta->findInt32(kKeyHeight, &height)); - - notifyVideoSizeChanged(width, height); + notifyVideoSizeChanged(getFormat(false /* audio */)); } notifyFlagsChanged( diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp index e8431e9..c713d39 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp @@ -210,9 +210,9 @@ void NuPlayer::HTTPLiveSource::onSessionNotify(const sp &msg) { int32_t height; if (format != NULL && format->findInt32("width", &width) && format->findInt32("height", &height)) { - notifyVideoSizeChanged(width, height); + notifyVideoSizeChanged(format); } else { - notifyVideoSizeChanged(0, 0); + notifyVideoSizeChanged(); } uint32_t flags = FLAG_CAN_PAUSE; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index fe115c6..6f6c9d9 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -852,60 +852,10 @@ void NuPlayer::onMessageReceived(const sp &msg) { mRenderer->signalAudioSinkChanged(); } else { // video + sp inputFormat = + mSource->getFormat(false /* audio */); - int32_t width, height; - CHECK(format->findInt32("width", &width)); - CHECK(format->findInt32("height", &height)); - - int32_t cropLeft, cropTop, cropRight, cropBottom; - CHECK(format->findRect( - "crop", - &cropLeft, &cropTop, &cropRight, &cropBottom)); - - int32_t displayWidth = cropRight - cropLeft + 1; - int32_t displayHeight = cropBottom - cropTop + 1; - - ALOGV("Video output format changed to %d x %d " - "(crop: %d x %d @ (%d, %d))", - width, height, - displayWidth, - displayHeight, - cropLeft, cropTop); - - sp videoInputFormat = - mSource->getFormat(false /* audio */); - - // Take into account sample aspect ratio if necessary: - int32_t sarWidth, sarHeight; - if (videoInputFormat->findInt32("sar-width", &sarWidth) - && videoInputFormat->findInt32( - "sar-height", &sarHeight)) { - ALOGV("Sample aspect ratio %d : %d", - sarWidth, sarHeight); - - displayWidth = (displayWidth * sarWidth) / sarHeight; - - ALOGV("display dimensions %d x %d", - displayWidth, displayHeight); - } - - int32_t rotationDegrees; - if (!videoInputFormat->findInt32( - "rotation-degrees", &rotationDegrees)) { - rotationDegrees = 0; - } - - if (rotationDegrees == 90 || rotationDegrees == 270) { - notifyListener( - MEDIA_SET_VIDEO_SIZE, - displayHeight, - displayWidth); - } else { - notifyListener( - MEDIA_SET_VIDEO_SIZE, - displayWidth, - displayHeight); - } + updateVideoSize(inputFormat, format); } } else if (what == Decoder::kWhatShutdownCompleted) { ALOGV("%s shutdown completed", audio ? "audio" : "video"); @@ -1383,6 +1333,72 @@ void NuPlayer::renderBuffer(bool audio, const sp &msg) { mRenderer->queueBuffer(audio, buffer, reply); } +void NuPlayer::updateVideoSize( + const sp &inputFormat, + const sp &outputFormat) { + if (inputFormat == NULL) { + ALOGW("Unknown video size, reporting 0x0!"); + notifyListener(MEDIA_SET_VIDEO_SIZE, 0, 0); + return; + } + + int32_t displayWidth, displayHeight; + int32_t cropLeft, cropTop, cropRight, cropBottom; + + if (outputFormat != NULL) { + int32_t width, height; + CHECK(outputFormat->findInt32("width", &width)); + CHECK(outputFormat->findInt32("height", &height)); + + int32_t cropLeft, cropTop, cropRight, cropBottom; + CHECK(outputFormat->findRect( + "crop", + &cropLeft, &cropTop, &cropRight, &cropBottom)); + + displayWidth = cropRight - cropLeft + 1; + displayHeight = cropBottom - cropTop + 1; + + ALOGV("Video output format changed to %d x %d " + "(crop: %d x %d @ (%d, %d))", + width, height, + displayWidth, + displayHeight, + cropLeft, cropTop); + } else { + CHECK(inputFormat->findInt32("width", &displayWidth)); + CHECK(inputFormat->findInt32("height", &displayHeight)); + + ALOGV("Video input format %d x %d", displayWidth, displayHeight); + } + + // Take into account sample aspect ratio if necessary: + int32_t sarWidth, sarHeight; + if (inputFormat->findInt32("sar-width", &sarWidth) + && inputFormat->findInt32("sar-height", &sarHeight)) { + ALOGV("Sample aspect ratio %d : %d", sarWidth, sarHeight); + + displayWidth = (displayWidth * sarWidth) / sarHeight; + + ALOGV("display dimensions %d x %d", displayWidth, displayHeight); + } + + int32_t rotationDegrees; + if (!inputFormat->findInt32("rotation-degrees", &rotationDegrees)) { + rotationDegrees = 0; + } + + if (rotationDegrees == 90 || rotationDegrees == 270) { + int32_t tmp = displayWidth; + displayWidth = displayHeight; + displayHeight = tmp; + } + + notifyListener( + MEDIA_SET_VIDEO_SIZE, + displayWidth, + displayHeight); +} + void NuPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *in) { if (mDriver == NULL) { return; @@ -1441,19 +1457,19 @@ void NuPlayer::flushDecoder(bool audio, bool needShutdown) { } } -sp NuPlayer::Source::getFormat(bool audio) { - sp meta = getFormatMeta(audio); +void NuPlayer::queueDecoderShutdown( + bool audio, bool video, const sp &reply) { + ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video); - if (meta == NULL) { - return NULL; - } + mDeferredActions.push_back( + new ShutdownDecoderAction(audio, video)); - sp msg = new AMessage; + mDeferredActions.push_back( + new SimpleAction(&NuPlayer::performScanSources)); - if(convertMetaDataToMessage(meta, &msg) == OK) { - return msg; - } - return NULL; + mDeferredActions.push_back(new PostMessageAction(reply)); + + processDeferredActions(); } status_t NuPlayer::setVideoScalingMode(int32_t mode) { @@ -1729,11 +1745,10 @@ void NuPlayer::onSourceNotify(const sp &msg) { case Source::kWhatVideoSizeChanged: { - int32_t width, height; - CHECK(msg->findInt32("width", &width)); - CHECK(msg->findInt32("height", &height)); + sp format; + CHECK(msg->findMessage("format", &format)); - notifyListener(MEDIA_SET_VIDEO_SIZE, width, height); + updateVideoSize(format); break; } @@ -1889,6 +1904,21 @@ void NuPlayer::sendTimedTextData(const sp &buffer) { } //////////////////////////////////////////////////////////////////////////////// +sp NuPlayer::Source::getFormat(bool audio) { + sp meta = getFormatMeta(audio); + + if (meta == NULL) { + return NULL; + } + + sp msg = new AMessage; + + if(convertMetaDataToMessage(meta, &msg) == OK) { + return msg; + } + return NULL; +} + void NuPlayer::Source::notifyFlagsChanged(uint32_t flags) { sp notify = dupNotify(); notify->setInt32("what", kWhatFlagsChanged); @@ -1896,11 +1926,10 @@ void NuPlayer::Source::notifyFlagsChanged(uint32_t flags) { notify->post(); } -void NuPlayer::Source::notifyVideoSizeChanged(int32_t width, int32_t height) { +void NuPlayer::Source::notifyVideoSizeChanged(const sp &format) { sp notify = dupNotify(); notify->setInt32("what", kWhatVideoSizeChanged); - notify->setInt32("width", width); - notify->setInt32("height", height); + notify->setMessage("format", format); notify->post(); } @@ -1915,19 +1944,4 @@ void NuPlayer::Source::onMessageReceived(const sp & /* msg */) { TRESPASS(); } -void NuPlayer::queueDecoderShutdown( - bool audio, bool video, const sp &reply) { - ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video); - - mDeferredActions.push_back( - new ShutdownDecoderAction(audio, video)); - - mDeferredActions.push_back( - new SimpleAction(&NuPlayer::performScanSources)); - - mDeferredActions.push_back(new PostMessageAction(reply)); - - processDeferredActions(); -} - } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 8bcf10e..486b7cc 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -167,6 +167,10 @@ private: status_t instantiateDecoder(bool audio, sp *decoder); + void updateVideoSize( + const sp &inputFormat, + const sp &outputFormat = NULL); + status_t feedDecoderInputData(bool audio, const sp &msg); void renderBuffer(bool audio, const sp &msg); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index 0ec017e..06bbbec 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -110,7 +110,7 @@ protected: sp dupNotify() const { return mNotify->dup(); } void notifyFlagsChanged(uint32_t flags); - void notifyVideoSizeChanged(int32_t width, int32_t height); + void notifyVideoSizeChanged(const sp &format = NULL); void notifyPrepared(status_t err = OK); private: diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index 2338b23..a911f6c 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -356,7 +356,7 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp &msg) { { onConnected(); - notifyVideoSizeChanged(0, 0); + notifyVideoSizeChanged(); uint32_t flags = 0; diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp index 28f0d50..2e9a29a 100644 --- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp +++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp @@ -44,7 +44,7 @@ NuPlayer::StreamingSource::~StreamingSource() { } void NuPlayer::StreamingSource::prepareAsync() { - notifyVideoSizeChanged(0, 0); + notifyVideoSizeChanged(); notifyFlagsChanged(0); notifyPrepared(); } -- cgit v1.1 From e3fdb6012905d593c9350958f4429d0d670adae4 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Fri, 8 Aug 2014 15:52:38 -0700 Subject: Fix WAVExtractor to output full audio frames only Fixes NuPlayer crash from MediaBuffers ending in partial audio frames. Bug: 16881623 Change-Id: Ia80a9910f99245e645860c00ae85118cc85bef57 --- media/libstagefright/WAVExtractor.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'media') diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp index 7124fd3..a4a651d 100644 --- a/media/libstagefright/WAVExtractor.cpp +++ b/media/libstagefright/WAVExtractor.cpp @@ -439,6 +439,10 @@ status_t WAVSource::read( maxBytesToRead = maxBytesAvailable; } + // read only integral amounts of audio unit frames. + const size_t inputUnitFrameSize = mNumChannels * mBitsPerSample / 8; + maxBytesToRead -= maxBytesToRead % inputUnitFrameSize; + if (mWaveFormat == WAVE_FORMAT_MSGSM) { // Microsoft packs 2 frames into 65 bytes, rather than using separate 33-byte frames, // so read multiples of 65, and use smaller buffers to account for ~10:1 expansion ratio -- cgit v1.1 From 5a446aafff3020d607ad6fb14cc7ae76dd8f7947 Mon Sep 17 00:00:00 2001 From: Rachad Date: Tue, 29 Jul 2014 16:47:56 -0700 Subject: Added Tunneled video playback support to ACodec Bug:16132368 Change-Id: I88d2d66b8548fc203f4a2c4797196af15e56ff38 --- media/libmedia/IOMX.cpp | 38 ++++++ media/libstagefright/ACodec.cpp | 157 ++++++++++++++++--------- media/libstagefright/OMXClient.cpp | 11 ++ media/libstagefright/include/OMX.h | 4 + media/libstagefright/include/OMXNodeInstance.h | 4 + media/libstagefright/omx/OMX.cpp | 7 ++ media/libstagefright/omx/OMXNodeInstance.cpp | 43 +++++++ 7 files changed, 207 insertions(+), 57 deletions(-) (limited to 'media') diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index 5df232f..c583d32 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -54,6 +54,7 @@ enum { GET_GRAPHIC_BUFFER_USAGE, SET_INTERNAL_OPTION, UPDATE_GRAPHIC_BUFFER_IN_META, + CONFIGURE_VIDEO_TUNNEL_MODE, }; class BpOMX : public BpInterface { @@ -368,6 +369,25 @@ public: return err; } + virtual status_t configureVideoTunnelMode( + node_id node, OMX_U32 portIndex, OMX_BOOL tunneled, + OMX_U32 audioHwSync, native_handle_t **sidebandHandle ) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeInt32((int32_t)node); + data.writeInt32(portIndex); + data.writeInt32((int32_t)tunneled); + data.writeInt32(audioHwSync); + remote()->transact(CONFIGURE_VIDEO_TUNNEL_MODE, data, &reply); + + status_t err = reply.readInt32(); + if (sidebandHandle) { + *sidebandHandle = (native_handle_t *)reply.readNativeHandle(); + } + return err; + } + + virtual status_t allocateBuffer( node_id node, OMX_U32 port_index, size_t size, buffer_id *buffer, void **buffer_data) { @@ -804,6 +824,24 @@ status_t BnOMX::onTransact( return NO_ERROR; } + case CONFIGURE_VIDEO_TUNNEL_MODE: + { + CHECK_OMX_INTERFACE(IOMX, data, reply); + + node_id node = (node_id)data.readInt32(); + OMX_U32 port_index = data.readInt32(); + OMX_BOOL tunneled = (OMX_BOOL)data.readInt32(); + OMX_U32 audio_hw_sync = data.readInt32(); + + native_handle_t *sideband_handle; + status_t err = configureVideoTunnelMode( + node, port_index, tunneled, audio_hw_sync, &sideband_handle); + reply->writeInt32(err); + reply->writeNativeHandle(sideband_handle); + + return NO_ERROR; + } + case ALLOC_BUFFER: { CHECK_OMX_INTERFACE(IOMX, data, reply); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 503ce81..ac80da2 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -1224,77 +1224,99 @@ status_t ACodec::configureCodec( } } - // Always try to enable dynamic output buffers on native surface sp obj; int32_t haveNativeWindow = msg->findObject("native-window", &obj) && - obj != NULL; + obj != NULL; mStoreMetaDataInOutputBuffers = false; if (video && !encoder) { inputFormat->setInt32("adaptive-playback", false); } if (!encoder && video && haveNativeWindow) { - err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_TRUE); - if (err != OK) { - ALOGE("[%s] storeMetaDataInBuffers failed w/ err %d", - mComponentName.c_str(), err); - - // if adaptive playback has been requested, try JB fallback - // NOTE: THIS FALLBACK MECHANISM WILL BE REMOVED DUE TO ITS - // LARGE MEMORY REQUIREMENT - - // we will not do adaptive playback on software accessed - // surfaces as they never had to respond to changes in the - // crop window, and we don't trust that they will be able to. - int usageBits = 0; - bool canDoAdaptivePlayback; - - sp windowWrapper( - static_cast(obj.get())); - sp nativeWindow = windowWrapper->getNativeWindow(); - - if (nativeWindow->query( - nativeWindow.get(), - NATIVE_WINDOW_CONSUMER_USAGE_BITS, - &usageBits) != OK) { - canDoAdaptivePlayback = false; - } else { - canDoAdaptivePlayback = - (usageBits & - (GRALLOC_USAGE_SW_READ_MASK | - GRALLOC_USAGE_SW_WRITE_MASK)) == 0; + sp windowWrapper( + static_cast(obj.get())); + sp nativeWindow = windowWrapper->getNativeWindow(); + + int32_t tunneled; + if (msg->findInt32("feature-tunneled-playback", &tunneled) && + tunneled != 0) { + ALOGI("Configuring TUNNELED video playback."); + + int64_t audioHwSync = 0; + if (!msg->findInt64("audio-hw-sync", &audioHwSync)) { + ALOGW("No Audio HW Sync provided for video tunnel"); + } + err = configureTunneledVideoPlayback(audioHwSync, nativeWindow); + if (err != OK) { + ALOGE("configureTunneledVideoPlayback(%" PRId64 ",%p) failed!", + audioHwSync, nativeWindow.get()); + return err; } - int32_t maxWidth = 0, maxHeight = 0; - if (canDoAdaptivePlayback && - msg->findInt32("max-width", &maxWidth) && - msg->findInt32("max-height", &maxHeight)) { - ALOGV("[%s] prepareForAdaptivePlayback(%dx%d)", - mComponentName.c_str(), maxWidth, maxHeight); - - err = mOMX->prepareForAdaptivePlayback( - mNode, kPortIndexOutput, OMX_TRUE, maxWidth, maxHeight); - ALOGW_IF(err != OK, - "[%s] prepareForAdaptivePlayback failed w/ err %d", + inputFormat->setInt32("adaptive-playback", true); + } else { + // Always try to enable dynamic output buffers on native surface + err = mOMX->storeMetaDataInBuffers( + mNode, kPortIndexOutput, OMX_TRUE); + if (err != OK) { + ALOGE("[%s] storeMetaDataInBuffers failed w/ err %d", mComponentName.c_str(), err); - if (err == OK) { - inputFormat->setInt32("max-width", maxWidth); - inputFormat->setInt32("max-height", maxHeight); - inputFormat->setInt32("adaptive-playback", true); + // if adaptive playback has been requested, try JB fallback + // NOTE: THIS FALLBACK MECHANISM WILL BE REMOVED DUE TO ITS + // LARGE MEMORY REQUIREMENT + + // we will not do adaptive playback on software accessed + // surfaces as they never had to respond to changes in the + // crop window, and we don't trust that they will be able to. + int usageBits = 0; + bool canDoAdaptivePlayback; + + if (nativeWindow->query( + nativeWindow.get(), + NATIVE_WINDOW_CONSUMER_USAGE_BITS, + &usageBits) != OK) { + canDoAdaptivePlayback = false; + } else { + canDoAdaptivePlayback = + (usageBits & + (GRALLOC_USAGE_SW_READ_MASK | + GRALLOC_USAGE_SW_WRITE_MASK)) == 0; + } + + int32_t maxWidth = 0, maxHeight = 0; + if (canDoAdaptivePlayback && + msg->findInt32("max-width", &maxWidth) && + msg->findInt32("max-height", &maxHeight)) { + ALOGV("[%s] prepareForAdaptivePlayback(%dx%d)", + mComponentName.c_str(), maxWidth, maxHeight); + + err = mOMX->prepareForAdaptivePlayback( + mNode, kPortIndexOutput, OMX_TRUE, maxWidth, + maxHeight); + ALOGW_IF(err != OK, + "[%s] prepareForAdaptivePlayback failed w/ err %d", + mComponentName.c_str(), err); + + if (err == OK) { + inputFormat->setInt32("max-width", maxWidth); + inputFormat->setInt32("max-height", maxHeight); + inputFormat->setInt32("adaptive-playback", true); + } } + // allow failure + err = OK; + } else { + ALOGV("[%s] storeMetaDataInBuffers succeeded", + mComponentName.c_str()); + mStoreMetaDataInOutputBuffers = true; + inputFormat->setInt32("adaptive-playback", true); } - // allow failure - err = OK; - } else { - ALOGV("[%s] storeMetaDataInBuffers succeeded", mComponentName.c_str()); - mStoreMetaDataInOutputBuffers = true; - inputFormat->setInt32("adaptive-playback", true); - } - int32_t push; - if (msg->findInt32("push-blank-buffers-on-shutdown", &push) - && push != 0) { - mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown; + int32_t push; + if (msg->findInt32("push-blank-buffers-on-shutdown", &push) + && push != 0) { + mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown; + } } int32_t rotationDegrees; @@ -1869,6 +1891,27 @@ status_t ACodec::setupRawAudioFormat( mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams)); } +status_t ACodec::configureTunneledVideoPlayback( + int64_t audioHwSync, const sp &nativeWindow) { + native_handle_t* sidebandHandle; + + status_t err = mOMX->configureVideoTunnelMode( + mNode, kPortIndexOutput, OMX_TRUE, audioHwSync, &sidebandHandle); + if (err != OK) { + ALOGE("configureVideoTunnelMode failed! (err %d).", err); + return err; + } + + err = native_window_set_sideband_stream(nativeWindow.get(), sidebandHandle); + if (err != OK) { + ALOGE("native_window_set_sideband_stream(%p) failed! (err %d).", + sidebandHandle, err); + return err; + } + + return OK; +} + status_t ACodec::setVideoPortFormatType( OMX_U32 portIndex, OMX_VIDEO_CODINGTYPE compressionFormat, diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp index aca21cf..ca031aa 100644 --- a/media/libstagefright/OMXClient.cpp +++ b/media/libstagefright/OMXClient.cpp @@ -78,6 +78,10 @@ struct MuxOMX : public IOMX { node_id node, OMX_U32 port_index, OMX_BOOL enable, OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight); + virtual status_t configureVideoTunnelMode( + node_id node, OMX_U32 portIndex, OMX_BOOL tunneled, + OMX_U32 audioHwSync, native_handle_t **sidebandHandle); + virtual status_t enableGraphicBuffers( node_id node, OMX_U32 port_index, OMX_BOOL enable); @@ -291,6 +295,13 @@ status_t MuxOMX::prepareForAdaptivePlayback( node, port_index, enable, maxFrameWidth, maxFrameHeight); } +status_t MuxOMX::configureVideoTunnelMode( + node_id node, OMX_U32 portIndex, OMX_BOOL enable, + OMX_U32 audioHwSync, native_handle_t **sidebandHandle) { + return getOMX(node)->configureVideoTunnelMode( + node, portIndex, enable, audioHwSync, sidebandHandle); +} + status_t MuxOMX::enableGraphicBuffers( node_id node, OMX_U32 port_index, OMX_BOOL enable) { return getOMX(node)->enableGraphicBuffers(node, port_index, enable); diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h index cd51bbf..e8c4970 100644 --- a/media/libstagefright/include/OMX.h +++ b/media/libstagefright/include/OMX.h @@ -75,6 +75,10 @@ public: node_id node, OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 max_frame_width, OMX_U32 max_frame_height); + virtual status_t configureVideoTunnelMode( + node_id node, OMX_U32 portIndex, OMX_BOOL tunneled, + OMX_U32 audioHwSync, native_handle_t **sidebandHandle); + virtual status_t useBuffer( node_id node, OMX_U32 port_index, const sp ¶ms, buffer_id *buffer); diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h index 3967dc6..dc6d410 100644 --- a/media/libstagefright/include/OMXNodeInstance.h +++ b/media/libstagefright/include/OMXNodeInstance.h @@ -62,6 +62,10 @@ struct OMXNodeInstance { OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight); + status_t configureVideoTunnelMode( + OMX_U32 portIndex, OMX_BOOL tunneled, + OMX_U32 audioHwSync, native_handle_t **sidebandHandle); + status_t useBuffer( OMX_U32 portIndex, const sp ¶ms, OMX::buffer_id *buffer); diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index cc4770a..41407e4 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -342,6 +342,13 @@ status_t OMX::prepareForAdaptivePlayback( portIndex, enable, maxFrameWidth, maxFrameHeight); } +status_t OMX::configureVideoTunnelMode( + node_id node, OMX_U32 portIndex, OMX_BOOL tunneled, + OMX_U32 audioHwSync, native_handle_t **sidebandHandle) { + return findInstance(node)->configureVideoTunnelMode( + portIndex, tunneled, audioHwSync, sidebandHandle); +} + status_t OMX::useBuffer( node_id node, OMX_U32 port_index, const sp ¶ms, buffer_id *buffer) { diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index d6ab109..efb27f5 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -460,6 +460,49 @@ status_t OMXNodeInstance::prepareForAdaptivePlayback( return err; } +status_t OMXNodeInstance::configureVideoTunnelMode( + OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync, + native_handle_t **sidebandHandle) { + Mutex::Autolock autolock(mLock); + + OMX_INDEXTYPE index; + OMX_STRING name = const_cast( + "OMX.google.android.index.configureVideoTunnelMode"); + + OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index); + if (err != OMX_ErrorNone) { + ALOGE("configureVideoTunnelMode extension is missing!"); + return StatusFromOMXError(err); + } + + ConfigureVideoTunnelModeParams tunnelParams; + tunnelParams.nSize = sizeof(tunnelParams); + tunnelParams.nVersion.s.nVersionMajor = 1; + tunnelParams.nVersion.s.nVersionMinor = 0; + tunnelParams.nVersion.s.nRevision = 0; + tunnelParams.nVersion.s.nStep = 0; + + tunnelParams.nPortIndex = portIndex; + tunnelParams.bTunneled = tunneled; + tunnelParams.nAudioHwSync = audioHwSync; + err = OMX_SetParameter(mHandle, index, &tunnelParams); + if (err != OMX_ErrorNone) { + ALOGE("configureVideoTunnelMode failed! (err %d).", err); + return UNKNOWN_ERROR; + } + + err = OMX_GetParameter(mHandle, index, &tunnelParams); + if (err != OMX_ErrorNone) { + ALOGE("GetVideoTunnelWindow failed! (err %d).", err); + return UNKNOWN_ERROR; + } + if (sidebandHandle) { + *sidebandHandle = (native_handle_t*)tunnelParams.pSidebandWindow; + } + + return err; +} + status_t OMXNodeInstance::useBuffer( OMX_U32 portIndex, const sp ¶ms, OMX::buffer_id *buffer) { -- cgit v1.1 From 25a147aaad0ce30da8db763054d963ceaedb4065 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 8 Aug 2014 10:05:03 -0700 Subject: stagefright: set crop rect in SoftwareRenderer Bug: 9563986 Change-Id: Id66a21ef8cdd8350e3eb95d6359fe9c1b94c4f98 --- media/libstagefright/colorconversion/SoftwareRenderer.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'media') diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp index 67dfcd2..0c5527a 100644 --- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp +++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp @@ -112,6 +112,17 @@ SoftwareRenderer::SoftwareRenderer( bufHeight, halFormat)); + // NOTE: native window uses extended right-bottom coordinate + android_native_rect_t crop; + crop.left = mCropLeft; + crop.top = mCropTop; + crop.right = mCropRight + 1; + crop.bottom = mCropBottom + 1; + ALOGV("setting crop: [%d, %d, %d, %d] for size [%zu, %zu]", + crop.left, crop.top, crop.right, crop.bottom, bufWidth, bufHeight); + + CHECK_EQ(0, native_window_set_crop(mNativeWindow.get(), &crop)); + uint32_t transform; switch (rotationDegrees) { case 0: transform = 0; break; -- cgit v1.1 From 7c4f0d757bfeedaab4b7ef4ccf5b0a72ec8f4306 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 9 Jul 2014 18:53:31 -0700 Subject: NuPlayer: getSelectedTrack Change-Id: If5251f89b881e7f268e11a06cd3685d794c958b6 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 38 ++++++++++++++++++++++ media/libmediaplayerservice/nuplayer/NuPlayer.h | 2 ++ .../nuplayer/NuPlayerDriver.cpp | 6 ++++ .../nuplayer/NuPlayerSource.h | 5 +++ 4 files changed, 51 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 6f6c9d9..55fd708 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -427,6 +427,31 @@ void NuPlayer::onMessageReceived(const sp &msg) { break; } + case kWhatGetSelectedTrack: + { + status_t err = INVALID_OPERATION; + if (mSource != NULL) { + err = OK; + + int32_t type32; + CHECK(msg->findInt32("type", (int32_t*)&type32)); + media_track_type type = (media_track_type)type32; + ssize_t selectedTrack = mSource->getSelectedTrack(type); + + Parcel* reply; + CHECK(msg->findPointer("reply", (void**)&reply)); + reply->writeInt32(selectedTrack); + } + + sp response = new AMessage; + response->setInt32("err", err); + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + response->postReply(replyID); + break; + } + case kWhatSelectTrack: { uint32_t replyID; @@ -1495,6 +1520,19 @@ status_t NuPlayer::getTrackInfo(Parcel* reply) const { return err; } +status_t NuPlayer::getSelectedTrack(int32_t type, Parcel* reply) const { + sp msg = new AMessage(kWhatGetSelectedTrack, id()); + msg->setPointer("reply", reply); + msg->setInt32("type", type); + + sp response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + } + return err; +} + status_t NuPlayer::selectTrack(size_t trackIndex, bool select) { sp msg = new AMessage(kWhatSelectTrack, id()); msg->setSize("trackIndex", trackIndex); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 486b7cc..fc456a4 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -63,6 +63,7 @@ struct NuPlayer : public AHandler { status_t setVideoScalingMode(int32_t mode); status_t getTrackInfo(Parcel* reply) const; + status_t getSelectedTrack(int32_t type, Parcel* reply) const; status_t selectTrack(size_t trackIndex, bool select); protected: @@ -109,6 +110,7 @@ private: kWhatPollDuration = 'polD', kWhatSourceNotify = 'srcN', kWhatGetTrackInfo = 'gTrI', + kWhatGetSelectedTrack = 'gSel', kWhatSelectTrack = 'selT', }; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 4748546..e33e647 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -422,6 +422,12 @@ status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) { return mPlayer->selectTrack(trackIndex, false /* select */); } + case INVOKE_ID_GET_SELECTED_TRACK: + { + int32_t type = request.readInt32(); + return mPlayer->getSelectedTrack(type, reply); + } + default: { return INVALID_OPERATION; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index 06bbbec..74892b6 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -22,6 +22,7 @@ #include #include +#include #include namespace android { @@ -86,6 +87,10 @@ struct NuPlayer::Source : public AHandler { return NULL; } + virtual ssize_t getSelectedTrack(media_track_type /* type */) const { + return INVALID_OPERATION; + } + virtual status_t selectTrack(size_t /* trackIndex */, bool /* select */) { return INVALID_OPERATION; } -- cgit v1.1 From 4b75b86785d674b98dade17cd197b912d87cd279 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 15 Aug 2013 15:59:19 -0700 Subject: NuPlayer: add support for proper stop MediaPlayer.stop() should move to the Stopped state which is semantically identical to the Initialized state. Bug: 13138230 Change-Id: I5d7b4a22533f545c24a18e2cd9f7cb2685d42c84 Signed-off-by: Lajos Molnar --- .../nuplayer/NuPlayerDriver.cpp | 64 +++++++++++++++++++++- .../nuplayer/NuPlayerDriver.h | 3 + 2 files changed, 64 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index e33e647..e37b4df 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -178,6 +178,16 @@ status_t NuPlayerDriver::prepare_l() { mCondition.wait(mLock); } return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR; + case STATE_STOPPED: + // this is really just paused. handle as seek to start + mAtEOS = false; + mState = STATE_STOPPED_AND_PREPARING; + mIsAsyncPrepare = false; + mPlayer->seekToAsync(0); + while (mState == STATE_STOPPED_AND_PREPARING) { + mCondition.wait(mLock); + } + return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR; default: return INVALID_OPERATION; }; @@ -192,6 +202,13 @@ status_t NuPlayerDriver::prepareAsync() { mIsAsyncPrepare = true; mPlayer->prepareAsync(); return OK; + case STATE_STOPPED: + // this is really just paused. handle as seek to start + mAtEOS = false; + mState = STATE_STOPPED_AND_PREPARING; + mIsAsyncPrepare = true; + mPlayer->seekToAsync(0); + return OK; default: return INVALID_OPERATION; }; @@ -235,6 +252,7 @@ status_t NuPlayerDriver::start() { break; case STATE_PAUSED: + case STATE_STOPPED_AND_PREPARED: { mPlayer->resume(); break; @@ -250,7 +268,29 @@ status_t NuPlayerDriver::start() { } status_t NuPlayerDriver::stop() { - return pause(); + Mutex::Autolock autoLock(mLock); + + switch (mState) { + case STATE_RUNNING: + mPlayer->pause(); + // fall through + + case STATE_PAUSED: + notifyListener(MEDIA_STOPPED); + // fall through + + case STATE_PREPARED: + case STATE_STOPPED: + case STATE_STOPPED_AND_PREPARING: + case STATE_STOPPED_AND_PREPARED: + mState = STATE_STOPPED; + break; + + default: + return INVALID_OPERATION; + } + + return OK; } status_t NuPlayerDriver::pause() { @@ -359,7 +399,9 @@ status_t NuPlayerDriver::reset() { break; } - notifyListener(MEDIA_STOPPED); + if (mState != STATE_STOPPED) { + notifyListener(MEDIA_STOPPED); + } mState = STATE_RESET_IN_PROGRESS; mPlayer->resetAsync(); @@ -503,7 +545,23 @@ void NuPlayerDriver::notifyPosition(int64_t positionUs) { } void NuPlayerDriver::notifySeekComplete() { - notifyListener(MEDIA_SEEK_COMPLETE); + bool wasSeeking = true; + { + Mutex::Autolock autoLock(mLock); + if (mState == STATE_STOPPED_AND_PREPARING) { + wasSeeking = false; + mState = STATE_STOPPED_AND_PREPARED; + mCondition.broadcast(); + if (!mIsAsyncPrepare) { + // if we are preparing synchronously, no need to notify listener + return; + } + } else if (mState == STATE_STOPPED) { + // no need to notify listener + return; + } + } + notifyListener(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED); } void NuPlayerDriver::notifyFrameStats( diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index 9424aae..4618c91 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -87,6 +87,9 @@ private: STATE_RUNNING, STATE_PAUSED, STATE_RESET_IN_PROGRESS, + STATE_STOPPED, // equivalent to PAUSED + STATE_STOPPED_AND_PREPARING, // equivalent to PAUSED, but seeking + STATE_STOPPED_AND_PREPARED, // equivalent to PAUSED, but seek complete }; mutable Mutex mLock; -- cgit v1.1 From cd04484f4837b8ca0041d118286ab6a98e84fc75 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Thu, 7 Aug 2014 11:04:34 -0700 Subject: Extend downsampling ratios greater than 2:1 Also improve robustness to choice of sampling rate or buffer size such that increasing either by 10x does not cause overflow. Bug: 12979141 Bug: 15933066 Change-Id: If7989bd745d1bee3bdf811b8b7c978543ccafb65 --- media/libmedia/AudioTrack.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index b5c9125..d87e6f5 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #define WAIT_PERIOD_MS 10 #define WAIT_STREAM_END_TIMEOUT_SEC 120 @@ -82,7 +83,7 @@ status_t AudioTrack::getMinFrameCount( } *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount : - afFrameCount * minBufCount * sampleRate / afSampleRate; + afFrameCount * minBufCount * uint64_t(sampleRate) / afSampleRate; // The formula above should always produce a non-zero value, but return an error // in the unlikely event that it does not, as that's part of the API contract. if (*frameCount == 0) { @@ -646,8 +647,7 @@ status_t AudioTrack::setSampleRate(uint32_t rate) if (AudioSystem::getOutputSamplingRateForAttr(&afSamplingRate, &mAttributes) != NO_ERROR) { return NO_INIT; } - // Resampler implementation limits input sampling rate to 2 x output sampling rate. - if (rate == 0 || rate > afSamplingRate*2 ) { + if (rate == 0 || rate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) { return BAD_VALUE; } @@ -1002,7 +1002,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) minBufCount = nBuffering; } - size_t minFrameCount = (afFrameCount*mSampleRate*minBufCount)/afSampleRate; + size_t minFrameCount = afFrameCount * minBufCount * uint64_t(mSampleRate) / afSampleRate; ALOGV("minFrameCount: %zu, afFrameCount=%zu, minBufCount=%d, sampleRate=%u, afSampleRate=%u" ", afLatency=%d", minFrameCount, afFrameCount, minBufCount, mSampleRate, afSampleRate, afLatency); -- cgit v1.1 From f4c0a94ab32541611f5ed6d407fc25b394c1988b Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Mon, 11 Aug 2014 15:14:10 -0700 Subject: propogate heartbeat error code to app Bug: 16885604 Change-Id: Ib6c60f0ef8cf72aa1aac67a75121142bff304018 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 6f6c9d9..4889dbc 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -876,7 +876,11 @@ void NuPlayer::onMessageReceived(const sp &msg) { ALOGE("Received error from %s decoder, aborting playback.", audio ? "audio" : "video"); - mRenderer->queueEOS(audio, UNKNOWN_ERROR); + status_t err; + if (!msg->findInt32("err", &err)) { + err = UNKNOWN_ERROR; + } + mRenderer->queueEOS(audio, err); } else if (what == Decoder::kWhatDrainThisBuffer) { renderBuffer(audio, msg); } else { -- cgit v1.1 From 6ff58f04f78886b07c72c0118eb71a78d08f5651 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 11 Aug 2014 16:46:15 -0700 Subject: MediaCodecList: handle errors gracefully Handle missing OMX codecs, and codecs that do not load. Fix NULL dereference when initializing codec with no type. Bug: 16907578 Bug: 16905025 Change-Id: I5d103db36ebb029d1aab03222bf6e9324beb1566 --- media/libmedia/MediaCodecInfo.cpp | 8 ++++++++ media/libstagefright/MediaCodecList.cpp | 26 +++++++++++++++++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp index 7900eae..8f47292 100644 --- a/media/libmedia/MediaCodecInfo.cpp +++ b/media/libmedia/MediaCodecInfo.cpp @@ -206,6 +206,14 @@ status_t MediaCodecInfo::addMime(const char *mime) { return OK; } +void MediaCodecInfo::removeMime(const char *mime) { + ssize_t ix = getCapabilityIndex(mime); + if (ix >= 0) { + mCaps.removeItemsAt(ix); + // mCurrentCaps will be removed when completed + } +} + status_t MediaCodecInfo::initializeCapabilities(const CodecCapabilities &caps) { mCurrentCaps->mProfileLevels.clear(); mCurrentCaps->mColorFormats.clear(); diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index 7f8b7f5..2f2a0b3 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -482,11 +482,21 @@ status_t MediaCodecList::addMediaCodecFromAttributes( } mCurrentInfo = new MediaCodecInfo(name, encoder, type); - mCodecInfos.push_back(mCurrentInfo); - return initializeCapabilities(type); + // The next step involves trying to load the codec, which may + // fail. Only list the codec if this succeeds. + // However, keep mCurrentInfo object around until parsing + // of full codec info is completed. + if (initializeCapabilities(type) == OK) { + mCodecInfos.push_back(mCurrentInfo); + } + return OK; } status_t MediaCodecList::initializeCapabilities(const char *type) { + if (type == NULL) { + return OK; + } + ALOGV("initializeCapabilities %s:%s", mCurrentInfo->mName.c_str(), type); @@ -553,10 +563,16 @@ status_t MediaCodecList::addTypeFromAttributes(const char **attrs) { } status_t ret = mCurrentInfo->addMime(name); - if (ret == OK) { - ret = initializeCapabilities(name); + if (ret != OK) { + return ret; } - return ret; + + // The next step involves trying to load the codec, which may + // fail. Handle this gracefully (by not reporting such mime). + if (initializeCapabilities(name) != OK) { + mCurrentInfo->removeMime(name); + } + return OK; } // legacy method for non-advanced codecs -- cgit v1.1 From 2461e0cf6ae3fe5c9b52ce9e3ac764f4aff5e5eb Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Tue, 12 Aug 2014 08:55:25 -0700 Subject: MediaCodecList: don't return references Bug: 16905025 Change-Id: I5b42b294f0cc785b8e4dda0e82c8f8377a46f487 --- media/libmedia/MediaCodecInfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp index 7900eae..5ea0519 100644 --- a/media/libmedia/MediaCodecInfo.cpp +++ b/media/libmedia/MediaCodecInfo.cpp @@ -46,7 +46,7 @@ uint32_t MediaCodecInfo::Capabilities::getFlags() const { return mFlags; } -const sp &MediaCodecInfo::Capabilities::getDetails() const { +const sp MediaCodecInfo::Capabilities::getDetails() const { return mDetails; } @@ -121,7 +121,7 @@ void MediaCodecInfo::getSupportedMimes(Vector *mimes) const { } } -const sp & +const sp MediaCodecInfo::getCapabilitiesFor(const char *mime) const { ssize_t ix = getCapabilityIndex(mime); if (ix >= 0) { -- cgit v1.1 From e53350373ac516257b4f8956ff1e3f1ac48f607e Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Tue, 12 Aug 2014 10:28:12 -0700 Subject: stagefright: allow scenarios when dequeueBufferFromNativeWindow fails We can run out of native buffers when the bufferqueue is abandoned. Bug: 16839124 Change-Id: If605f692b87082f1630e1da0fd44da0cb76133f5 --- media/libstagefright/ACodec.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index ac80da2..b77e1cd 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -3946,8 +3946,7 @@ void ACodec::BaseState::onInputBufferFilled(const sp &msg) { (outputMode == FREE_BUFFERS ? "FREE" : outputMode == KEEP_BUFFERS ? "KEEP" : "RESUBMIT")); if (outputMode == RESUBMIT_BUFFERS) { - CHECK_EQ(mCodec->submitOutputMetaDataBuffer(), - (status_t)OK); + mCodec->submitOutputMetaDataBuffer(); } } -- cgit v1.1 From de01afbbc55ac9c5c23ec66154603f34217aed2c Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 13 Aug 2014 13:48:10 -0700 Subject: cache up to 200K bytes (instead of 10 buffers) in DecoderPassThrough Bug: 16892521 Change-Id: I0e2da4134a37e632f9f2c29d1d27d8fded7a7863 --- .../nuplayer/NuPlayerDecoderPassThrough.cpp | 16 +++++++++++++--- .../nuplayer/NuPlayerDecoderPassThrough.h | 3 ++- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp index eec6960..c9be0dd 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp @@ -31,6 +31,7 @@ namespace android { static const int kMaxPendingBuffers = 10; +static const int kMaxCachedBytes = 200000; NuPlayer::DecoderPassThrough::DecoderPassThrough( const sp ¬ify) @@ -39,6 +40,7 @@ NuPlayer::DecoderPassThrough::DecoderPassThrough( mBufferGeneration(0), mReachedEOS(true), mPendingBuffers(0), + mCachedBytes(0), mComponentName("pass through decoder") { mDecoderLooper = new ALooper; mDecoderLooper->setName("NuPlayerDecoderPassThrough"); @@ -78,6 +80,7 @@ bool NuPlayer::DecoderPassThrough::supportsSeamlessFormatChange( void NuPlayer::DecoderPassThrough::onConfigure(const sp &format) { ALOGV("[%s] onConfigure", mComponentName.c_str()); mPendingBuffers = 0; + mCachedBytes = 0; mReachedEOS = false; ++mBufferGeneration; @@ -96,7 +99,7 @@ bool NuPlayer::DecoderPassThrough::isStaleReply(const sp &msg) { } void NuPlayer::DecoderPassThrough::requestABuffer() { - if (mPendingBuffers >= kMaxPendingBuffers || mReachedEOS) { + if (mCachedBytes >= kMaxCachedBytes || mReachedEOS) { ALOGV("[%s] mReachedEOS=%d, max pending buffers(%d:%d)", mComponentName.c_str(), (mReachedEOS ? 1 : 0), mPendingBuffers, kMaxPendingBuffers); @@ -136,8 +139,11 @@ void android::NuPlayer::DecoderPassThrough::onInputBufferFilled( return; } + mCachedBytes += buffer->size(); + sp reply = new AMessage(kWhatBufferConsumed, id()); reply->setInt32("generation", mBufferGeneration); + reply->setInt32("size", buffer->size()); sp notify = mNotify->dup(); notify->setInt32("what", kWhatDrainThisBuffer); @@ -146,8 +152,9 @@ void android::NuPlayer::DecoderPassThrough::onInputBufferFilled( notify->post(); } -void NuPlayer::DecoderPassThrough::onBufferConsumed() { +void NuPlayer::DecoderPassThrough::onBufferConsumed(int32_t size) { mPendingBuffers--; + mCachedBytes -= size; sp message = new AMessage(kWhatRequestABuffer, id()); message->setInt32("generation", mBufferGeneration); message->post(); @@ -160,6 +167,7 @@ void NuPlayer::DecoderPassThrough::onFlush() { notify->setInt32("what", kWhatFlushCompleted); notify->post(); mPendingBuffers = 0; + mCachedBytes = 0; mReachedEOS = false; } @@ -205,7 +213,9 @@ void NuPlayer::DecoderPassThrough::onMessageReceived(const sp &msg) { case kWhatBufferConsumed: { if (!isStaleReply(msg)) { - onBufferConsumed(); + int32_t size; + CHECK(msg->findInt32("size", &size)); + onBufferConsumed(size); } break; } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h index e9e5658..8590856 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h @@ -61,12 +61,13 @@ private: void onConfigure(const sp &format); void onFlush(); void onInputBufferFilled(const sp &msg); - void onBufferConsumed(); + void onBufferConsumed(int32_t size); void onShutdown(); int32_t mBufferGeneration; bool mReachedEOS; int32_t mPendingBuffers; + int32_t mCachedBytes; AString mComponentName; DISALLOW_EVIL_CONSTRUCTORS(DecoderPassThrough); -- cgit v1.1 From 7b3cd1f33dcfc0b6034144cf48c0919cf7ca6046 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 13 Aug 2014 15:26:49 -0700 Subject: make NuPlayer's http connection mechanism behave more like that of AwesomePlayer's - remove cache specific headers before connect - read mime type before creating cached source on top of the http source Bug: 16892521 Change-Id: Ie13a62dd8dd959be6095a42e2b41e3bc817efeb5 --- media/libstagefright/DataSource.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'media') diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 908cdca..008da5a 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -209,25 +209,29 @@ sp DataSource::CreateFromURI( uri = tmp.string(); } - if (httpSource->connect(uri, headers) != OK) { + String8 cacheConfig; + bool disconnectAtHighwatermark; + KeyedVector nonCacheSpecificHeaders; + if (headers != NULL) { + nonCacheSpecificHeaders = *headers; + NuCachedSource2::RemoveCacheSpecificHeaders( + &nonCacheSpecificHeaders, + &cacheConfig, + &disconnectAtHighwatermark); + } + + if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) { ALOGE("Failed to connect http source!"); return NULL; } if (!isWidevine) { - String8 cacheConfig; - bool disconnectAtHighwatermark; - if (headers != NULL) { - KeyedVector copy = *headers; - NuCachedSource2::RemoveCacheSpecificHeaders( - ©, &cacheConfig, &disconnectAtHighwatermark); - } + String8 contentType = httpSource->getMIMEType(); sp cachedSource = new NuCachedSource2( httpSource, - cacheConfig.isEmpty() ? NULL : cacheConfig.string()); - - String8 contentType = httpSource->getMIMEType(); + cacheConfig.isEmpty() ? NULL : cacheConfig.string(), + disconnectAtHighwatermark); if (strncasecmp(contentType.string(), "audio/", 6)) { // We're not doing this for streams that appear to be audio-only -- cgit v1.1 From 1228d6b175de8b21787cbe0c6c4bb5642f4d555e Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 12 Aug 2014 21:25:48 -0700 Subject: use dedicated looper for GenericSource - handle setVideoSurface in deferred action, and return to client immediately - handle GenericSource's prepareAsync on its own looper, instead of sharing looper with NuPlayer - let HTTPLiveSource share looper with LiveSession, instead of NuPlayer - remove reflector in RTSPSource Bug: 16892748 Change-Id: I1aed557320052012065f5a90adbcb03c238da988 --- .../nuplayer/GenericSource.cpp | 22 ++++++++++++++++++++++ .../libmediaplayerservice/nuplayer/GenericSource.h | 6 ++++++ .../nuplayer/HTTPLiveSource.cpp | 15 +++++++++++---- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 10 ---------- .../nuplayer/NuPlayerDriver.cpp | 20 -------------------- .../nuplayer/NuPlayerDriver.h | 2 -- .../libmediaplayerservice/nuplayer/RTSPSource.cpp | 12 ++++++------ media/libmediaplayerservice/nuplayer/RTSPSource.h | 3 --- 8 files changed, 45 insertions(+), 45 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 6676461..76e1d54 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -192,9 +192,26 @@ status_t NuPlayer::GenericSource::setBuffers( } NuPlayer::GenericSource::~GenericSource() { + if (mLooper != NULL) { + mLooper->unregisterHandler(id()); + mLooper->stop(); + } } void NuPlayer::GenericSource::prepareAsync() { + if (mLooper == NULL) { + mLooper = new ALooper; + mLooper->setName("generic"); + mLooper->start(); + + mLooper->registerHandler(this); + } + + sp msg = new AMessage(kWhatPrepareAsync, id()); + msg->post(); +} + +void NuPlayer::GenericSource::onPrepareAsync() { // delayed data source creation AString sniffedMIME; sp dataSource; @@ -267,6 +284,11 @@ status_t NuPlayer::GenericSource::feedMoreTSData() { void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { switch (msg->what()) { + case kWhatPrepareAsync: + { + onPrepareAsync(); + break; + } case kWhatFetchSubtitleData: { fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 44d690e..d3081de 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -70,6 +70,7 @@ protected: private: enum { + kWhatPrepareAsync, kWhatFetchSubtitleData, kWhatFetchTimedTextData, kWhatSendSubtitleData, @@ -104,12 +105,17 @@ private: int64_t mOffset; int64_t mLength; + sp mLooper; + + void resetDataSource(); status_t initFromDataSource( const sp &dataSource, const char *mime); + void onPrepareAsync(); + void fetchTextData( uint32_t what, media_track_type type, int32_t curGen, sp packets, sp msg); diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp index c713d39..a003c81 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp @@ -62,17 +62,24 @@ NuPlayer::HTTPLiveSource::HTTPLiveSource( NuPlayer::HTTPLiveSource::~HTTPLiveSource() { if (mLiveSession != NULL) { mLiveSession->disconnect(); - mLiveSession.clear(); + mLiveLooper->unregisterHandler(mLiveSession->id()); + mLiveLooper->unregisterHandler(id()); mLiveLooper->stop(); + + mLiveSession.clear(); mLiveLooper.clear(); } } void NuPlayer::HTTPLiveSource::prepareAsync() { - mLiveLooper = new ALooper; - mLiveLooper->setName("http live"); - mLiveLooper->start(); + if (mLiveLooper == NULL) { + mLiveLooper = new ALooper; + mLiveLooper->setName("http live"); + mLiveLooper->start(); + + mLiveLooper->registerHandler(this); + } sp notify = new AMessage(kWhatSessionNotify, id()); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 9a4e811..fea43f1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -372,7 +372,6 @@ void NuPlayer::onMessageReceived(const sp &msg) { CHECK(msg->findObject("source", &obj)); if (obj != NULL) { mSource = static_cast(obj.get()); - looper()->registerHandler(mSource); } else { err = UNKNOWN_ERROR; } @@ -1688,8 +1687,6 @@ void NuPlayer::performReset() { if (mSource != NULL) { mSource->stop(); - looper()->unregisterHandler(mSource->id()); - mSource.clear(); } @@ -1722,13 +1719,6 @@ void NuPlayer::performSetSurface(const sp &wrapper) { // XXX - ignore error from setVideoScalingMode for now setVideoScalingMode(mVideoScalingMode); - - if (mDriver != NULL) { - sp driver = mDriver.promote(); - if (driver != NULL) { - driver->notifySetSurfaceComplete(); - } - } } void NuPlayer::onSourceNotify(const sp &msg) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index e33e647..bf7542f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -34,7 +34,6 @@ NuPlayerDriver::NuPlayerDriver() : mState(STATE_IDLE), mIsAsyncPrepare(false), mAsyncResult(UNKNOWN_ERROR), - mSetSurfaceInProgress(false), mDurationUs(-1), mPositionUs(-1), mNumFramesTotal(0), @@ -135,10 +134,6 @@ status_t NuPlayerDriver::setVideoSurfaceTexture( const sp &bufferProducer) { Mutex::Autolock autoLock(mLock); - if (mSetSurfaceInProgress) { - return INVALID_OPERATION; - } - switch (mState) { case STATE_SET_DATASOURCE_PENDING: case STATE_RESET_IN_PROGRESS: @@ -148,14 +143,8 @@ status_t NuPlayerDriver::setVideoSurfaceTexture( break; } - mSetSurfaceInProgress = true; - mPlayer->setVideoSurfaceTextureAsync(bufferProducer); - while (mSetSurfaceInProgress) { - mCondition.wait(mLock); - } - return OK; } @@ -483,15 +472,6 @@ void NuPlayerDriver::notifyResetComplete() { mCondition.broadcast(); } -void NuPlayerDriver::notifySetSurfaceComplete() { - Mutex::Autolock autoLock(mLock); - - CHECK(mSetSurfaceInProgress); - mSetSurfaceInProgress = false; - - mCondition.broadcast(); -} - void NuPlayerDriver::notifyDuration(int64_t durationUs) { Mutex::Autolock autoLock(mLock); mDurationUs = durationUs; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index 9424aae..a9ff8b6 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -66,7 +66,6 @@ struct NuPlayerDriver : public MediaPlayerInterface { void notifySetDataSourceCompleted(status_t err); void notifyPrepareCompleted(status_t err); void notifyResetComplete(); - void notifySetSurfaceComplete(); void notifyDuration(int64_t durationUs); void notifyPosition(int64_t positionUs); void notifySeekComplete(); @@ -99,7 +98,6 @@ private: // The following are protected through "mLock" // >>> - bool mSetSurfaceInProgress; int64_t mDurationUs; int64_t mPositionUs; int64_t mNumFramesTotal; diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index a911f6c..ffacb8f 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -70,6 +70,7 @@ NuPlayer::RTSPSource::RTSPSource( NuPlayer::RTSPSource::~RTSPSource() { if (mLooper != NULL) { + mLooper->unregisterHandler(id()); mLooper->stop(); } } @@ -80,14 +81,13 @@ void NuPlayer::RTSPSource::prepareAsync() { mLooper->setName("rtsp"); mLooper->start(); - mReflector = new AHandlerReflector(this); - mLooper->registerHandler(mReflector); + mLooper->registerHandler(this); } CHECK(mHandler == NULL); CHECK(mSDPLoader == NULL); - sp notify = new AMessage(kWhatNotify, mReflector->id()); + sp notify = new AMessage(kWhatNotify, id()); CHECK_EQ(mState, (int)DISCONNECTED); mState = CONNECTING; @@ -118,7 +118,7 @@ void NuPlayer::RTSPSource::stop() { if (mLooper == NULL) { return; } - sp msg = new AMessage(kWhatDisconnect, mReflector->id()); + sp msg = new AMessage(kWhatDisconnect, id()); sp dummy; msg->postAndAwaitResponse(&dummy); @@ -305,7 +305,7 @@ status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) { } status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) { - sp msg = new AMessage(kWhatPerformSeek, mReflector->id()); + sp msg = new AMessage(kWhatPerformSeek, id()); msg->setInt32("generation", ++mSeekGeneration); msg->setInt64("timeUs", seekTimeUs); msg->post(200000ll); @@ -613,7 +613,7 @@ void NuPlayer::RTSPSource::onSDPLoaded(const sp &msg) { ALOGE("Unable to find url in SDP"); err = UNKNOWN_ERROR; } else { - sp notify = new AMessage(kWhatNotify, mReflector->id()); + sp notify = new AMessage(kWhatNotify, id()); mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID); mLooper->registerHandler(mHandler); diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h index 3718bf9..f1cae53 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.h +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h @@ -22,8 +22,6 @@ #include "ATSParser.h" -#include - namespace android { struct ALooper; @@ -102,7 +100,6 @@ private: bool mBuffering; sp mLooper; - sp > mReflector; sp mHandler; sp mSDPLoader; -- cgit v1.1 From 282a7e31681840253a4cb6fab3f6725d35798699 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Thu, 14 Aug 2014 15:56:34 -0700 Subject: nuplayer: create AudioSink early to verify offload is possible Offload audio playback is not guaranteed even if AudioSystem says it is allowed. Create AudioSink early to verify offload is really possible. Move AudioSink open / close into functions. Bug: 16732303 Bug: 16978805 Change-Id: Ie1c73a96656863c1281bed3280a84b86d3cbadf5 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 285 ++++++++++++---------- media/libmediaplayerservice/nuplayer/NuPlayer.h | 4 + 2 files changed, 156 insertions(+), 133 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 9a4e811..06c6e8d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -147,6 +147,7 @@ NuPlayer::NuPlayer() mSourceFlags(0), mVideoIsAVC(false), mOffloadAudio(false), + mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER), mAudioEOS(false), mVideoEOS(false), mScanSourcesPending(false), @@ -639,11 +640,18 @@ void NuPlayer::onMessageReceived(const sp &msg) { bool mHadAnySourcesBefore = (mAudioDecoder != NULL) || (mVideoDecoder != NULL); + // initialize video before audio because successful initialization of + // video may change deep buffer mode of audio. if (mNativeWindow != NULL) { instantiateDecoder(false, &mVideoDecoder); } if (mAudioSink != NULL) { + if (mOffloadAudio) { + // open audio sink early under offload mode. + sp format = mSource->getFormat(true /*audio*/); + openAudioSink(format, true /*offloadOnly*/); + } instantiateDecoder(true, &mAudioDecoder); } @@ -743,138 +751,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { CHECK(msg->findMessage("format", &format)); if (audio) { - int32_t numChannels; - CHECK(format->findInt32( - "channel-count", &numChannels)); - - int32_t sampleRate; - CHECK(format->findInt32("sample-rate", &sampleRate)); - - ALOGV("Audio output format changed to %d Hz, %d channels", - sampleRate, numChannels); - - mAudioSink->close(); - - uint32_t flags; - int64_t durationUs; - // FIXME: we should handle the case where the video decoder - // is created after we receive the format change indication. - // Current code will just make that we select deep buffer - // with video which should not be a problem as it should - // not prevent from keeping A/V sync. - if (mVideoDecoder == NULL && - mSource->getDuration(&durationUs) == OK && - durationUs - > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) { - flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; - } else { - flags = AUDIO_OUTPUT_FLAG_NONE; - } - - int32_t channelMask; - if (!format->findInt32("channel-mask", &channelMask)) { - channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; - } - - if (mOffloadAudio) { - audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT; - audio_offload_info_t offloadInfo = - AUDIO_INFO_INITIALIZER; - - AString mime; - CHECK(format->findString("mime", &mime)); - - status_t err = - mapMimeToAudioFormat(audioFormat, mime.c_str()); - if (err != OK) { - ALOGE("Couldn't map mime \"%s\" to a valid " - "audio_format", mime.c_str()); - mOffloadAudio = false; - } else { - ALOGV("Mime \"%s\" mapped to audio_format 0x%x", - mime.c_str(), audioFormat); - - int32_t aacProfile = -1; - if (audioFormat == AUDIO_FORMAT_AAC - && format->findInt32("aac-profile", &aacProfile)) { - // Redefine AAC format as per aac profile - mapAACProfileToAudioFormat( - audioFormat, - aacProfile); - } - - flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; - - offloadInfo.duration_us = -1; - format->findInt64( - "durationUs", &offloadInfo.duration_us); - - int avgBitRate = -1; - format->findInt32("bit-rate", &avgBitRate); - - offloadInfo.sample_rate = sampleRate; - offloadInfo.channel_mask = channelMask; - offloadInfo.format = audioFormat; - offloadInfo.stream_type = AUDIO_STREAM_MUSIC; - offloadInfo.bit_rate = avgBitRate; - offloadInfo.has_video = (mVideoDecoder != NULL); - offloadInfo.is_streaming = true; - - ALOGV("try to open AudioSink in offload mode"); - err = mAudioSink->open( - sampleRate, - numChannels, - (audio_channel_mask_t)channelMask, - audioFormat, - 8 /* bufferCount */, - &NuPlayer::Renderer::AudioSinkCallback, - mRenderer.get(), - (audio_output_flags_t)flags, - &offloadInfo); - - if (err == OK) { - // If the playback is offloaded to h/w, we pass - // the HAL some metadata information. - // We don't want to do this for PCM because it - // will be going through the AudioFlinger mixer - // before reaching the hardware. - sp audioMeta = - mSource->getFormatMeta(true /* audio */); - sendMetaDataToHal(mAudioSink, audioMeta); - - err = mAudioSink->start(); - } - } - - if (err != OK) { - // Clean up, fall back to non offload mode. - mAudioSink->close(); - mAudioDecoder.clear(); - mRenderer->signalDisableOffloadAudio(); - mOffloadAudio = false; - - instantiateDecoder( - true /* audio */, &mAudioDecoder); - } - } - - if (!mOffloadAudio) { - flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; - ALOGV("open AudioSink in NON-offload mode"); - CHECK_EQ(mAudioSink->open( - sampleRate, - numChannels, - (audio_channel_mask_t)channelMask, - AUDIO_FORMAT_PCM_16_BIT, - 8 /* bufferCount */, - NULL, - NULL, - (audio_output_flags_t)flags), - (status_t)OK); - mAudioSink->start(); - } - - mRenderer->signalAudioSinkChanged(); + openAudioSink(format, false /*offloadOnly*/); } else { // video sp inputFormat = @@ -981,7 +858,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { ALOGV("Tear down audio offload, fall back to s/w path"); int64_t positionUs; CHECK(msg->findInt64("positionUs", &positionUs)); - mAudioSink->close(); + closeAudioSink(); mAudioDecoder.clear(); mRenderer->flush(true /* audio */); if (mVideoDecoder != NULL) { @@ -1108,6 +985,148 @@ void NuPlayer::postScanSources() { mScanSourcesPending = true; } +void NuPlayer::openAudioSink(const sp &format, bool offloadOnly) { + ALOGV("openAudioSink: offloadOnly(%d) mOffloadAudio(%d)", + offloadOnly, mOffloadAudio); + bool audioSinkChanged = false; + + int32_t numChannels; + CHECK(format->findInt32("channel-count", &numChannels)); + + int32_t channelMask; + if (!format->findInt32("channel-mask", &channelMask)) { + // signal to the AudioSink to derive the mask from count. + channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; + } + + int32_t sampleRate; + CHECK(format->findInt32("sample-rate", &sampleRate)); + + uint32_t flags; + int64_t durationUs; + // FIXME: we should handle the case where the video decoder + // is created after we receive the format change indication. + // Current code will just make that we select deep buffer + // with video which should not be a problem as it should + // not prevent from keeping A/V sync. + if (mVideoDecoder == NULL && + mSource->getDuration(&durationUs) == OK && + durationUs + > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) { + flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; + } else { + flags = AUDIO_OUTPUT_FLAG_NONE; + } + + if (mOffloadAudio) { + audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT; + AString mime; + CHECK(format->findString("mime", &mime)); + status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str()); + + if (err != OK) { + ALOGE("Couldn't map mime \"%s\" to a valid " + "audio_format", mime.c_str()); + mOffloadAudio = false; + } else { + ALOGV("Mime \"%s\" mapped to audio_format 0x%x", + mime.c_str(), audioFormat); + + int avgBitRate = -1; + format->findInt32("bit-rate", &avgBitRate); + + int32_t aacProfile = -1; + if (audioFormat == AUDIO_FORMAT_AAC + && format->findInt32("aac-profile", &aacProfile)) { + // Redefine AAC format as per aac profile + mapAACProfileToAudioFormat( + audioFormat, + aacProfile); + } + + audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER; + offloadInfo.duration_us = -1; + format->findInt64( + "durationUs", &offloadInfo.duration_us); + offloadInfo.sample_rate = sampleRate; + offloadInfo.channel_mask = channelMask; + offloadInfo.format = audioFormat; + offloadInfo.stream_type = AUDIO_STREAM_MUSIC; + offloadInfo.bit_rate = avgBitRate; + offloadInfo.has_video = (mVideoDecoder != NULL); + offloadInfo.is_streaming = true; + + if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) { + ALOGV("openAudioSink: no change in offload mode"); + return; // no change from previous configuration, everything ok. + } + ALOGV("openAudioSink: try to open AudioSink in offload mode"); + flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; + audioSinkChanged = true; + mAudioSink->close(); + err = mAudioSink->open( + sampleRate, + numChannels, + (audio_channel_mask_t)channelMask, + audioFormat, + 8 /* bufferCount */, + &NuPlayer::Renderer::AudioSinkCallback, + mRenderer.get(), + (audio_output_flags_t)flags, + &offloadInfo); + + if (err == OK) { + // If the playback is offloaded to h/w, we pass + // the HAL some metadata information. + // We don't want to do this for PCM because it + // will be going through the AudioFlinger mixer + // before reaching the hardware. + sp audioMeta = + mSource->getFormatMeta(true /* audio */); + sendMetaDataToHal(mAudioSink, audioMeta); + mCurrentOffloadInfo = offloadInfo; + err = mAudioSink->start(); + ALOGV_IF(err == OK, "openAudioSink: offload succeeded"); + } + if (err != OK) { + // Clean up, fall back to non offload mode. + mAudioSink->close(); + mRenderer->signalDisableOffloadAudio(); + mOffloadAudio = false; + mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; + ALOGV("openAudioSink: offload failed"); + } + } + } + if (!offloadOnly && !mOffloadAudio) { + flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; + ALOGV("openAudioSink: open AudioSink in NON-offload mode"); + + audioSinkChanged = true; + mAudioSink->close(); + mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; + CHECK_EQ(mAudioSink->open( + sampleRate, + numChannels, + (audio_channel_mask_t)channelMask, + AUDIO_FORMAT_PCM_16_BIT, + 8 /* bufferCount */, + NULL, + NULL, + (audio_output_flags_t)flags), + (status_t)OK); + mAudioSink->start(); + } + if (audioSinkChanged) { + mRenderer->signalAudioSinkChanged(); + } +} + +void NuPlayer::closeAudioSink() { + mAudioSink->close(); + mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; +} + status_t NuPlayer::instantiateDecoder(bool audio, sp *decoder) { if (*decoder != NULL) { return OK; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index fc456a4..48882c5 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -124,6 +124,7 @@ private: sp mVideoDecoder; bool mVideoIsAVC; bool mOffloadAudio; + audio_offload_info_t mCurrentOffloadInfo; sp mAudioDecoder; sp mCCDecoder; sp mRenderer; @@ -167,6 +168,9 @@ private: bool mStarted; + void openAudioSink(const sp &format, bool offloadOnly); + void closeAudioSink(); + status_t instantiateDecoder(bool audio, sp *decoder); void updateVideoSize( -- cgit v1.1 From 732c6d955524ead6c31e6e1bafbd41ea4cee525d Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 14 Aug 2014 19:54:08 -0700 Subject: stagefright/media: add support for codec features with text value Bug: 11990470 Change-Id: I7600d999c5f4b6821d825d25fa7e8a2bb5a80c46 --- media/libmedia/MediaCodecInfo.cpp | 6 ++++++ media/libstagefright/MediaCodecList.cpp | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp index 446c582..7b4c4e2 100644 --- a/media/libmedia/MediaCodecInfo.cpp +++ b/media/libmedia/MediaCodecInfo.cpp @@ -257,4 +257,10 @@ void MediaCodecInfo::addFeature(const AString &key, int32_t value) { mCurrentCaps->mDetails->setInt32(tag.c_str(), value); } +void MediaCodecInfo::addFeature(const AString &key, const char *value) { + AString tag = "feature-"; + tag.append(key); + mCurrentCaps->mDetails->setString(tag.c_str(), value); +} + } // namespace android diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index 2f2a0b3..5b8be46 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -783,6 +783,7 @@ status_t MediaCodecList::addFeature(const char **attrs) { const char *name = NULL; int32_t optional = -1; int32_t required = -1; + const char *value = NULL; while (attrs[i] != NULL) { if (attrs[i + 1] == NULL) { @@ -801,6 +802,9 @@ status_t MediaCodecList::addFeature(const char **attrs) { required = value; } ++i; + } else if (!strcmp(attrs[i], "value")) { + value = attrs[i + 1]; + ++i; } else { return -EINVAL; } @@ -816,7 +820,16 @@ status_t MediaCodecList::addFeature(const char **attrs) { return -EINVAL; } - mCurrentInfo->addFeature(name, (required == 1) || (optional == 0)); + if ((optional != -1 || required != -1) && (value != NULL)) { + ALOGE("feature '%s' has both a value and optional/required attribute", name); + return -EINVAL; + } + + if (value != NULL) { + mCurrentInfo->addFeature(name, value); + } else { + mCurrentInfo->addFeature(name, (required == 1) || (optional == 0)); + } return OK; } -- cgit v1.1 From cd39746f8d83bb3f12e8f613e77c3c3b5f77c077 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 14 Aug 2014 19:55:25 -0700 Subject: stagefright: allow specifying flac copmression level by 'complexity' Bug: 11990470 Change-Id: I428961cc654b768773814078f753e2e67243f186 --- media/libstagefright/ACodec.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index b77e1cd..b44d5cc 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -1419,8 +1419,10 @@ status_t ACodec::configureCodec( } else { if (encoder) { if (!msg->findInt32( + "complexity", &compressionLevel) && + !msg->findInt32( "flac-compression-level", &compressionLevel)) { - compressionLevel = 5;// default FLAC compression level + compressionLevel = 5; // default FLAC compression level } else if (compressionLevel < 0) { ALOGW("compression level %d outside [0..8] range, " "using 0", -- cgit v1.1 From 037f9b619f166e2bd67384f2e66b99bab19700ac Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 14 Aug 2014 17:42:47 -0700 Subject: stagefright: add codec capability info for google audio codecs Bug: 11990470 Change-Id: I6a7d6758727cc205c636dfb19eb7fe99d67fb084 --- .../data/media_codecs_google_audio.xml | 83 ++++++++++++++++++---- .../data/media_codecs_google_telephony.xml | 6 +- 2 files changed, 74 insertions(+), 15 deletions(-) (limited to 'media') diff --git a/media/libstagefright/data/media_codecs_google_audio.xml b/media/libstagefright/data/media_codecs_google_audio.xml index f6db0cc..f599004 100644 --- a/media/libstagefright/data/media_codecs_google_audio.xml +++ b/media/libstagefright/data/media_codecs_google_audio.xml @@ -16,21 +16,76 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/media/libstagefright/data/media_codecs_google_telephony.xml b/media/libstagefright/data/media_codecs_google_telephony.xml index 28f5ffc..5ad90d9 100644 --- a/media/libstagefright/data/media_codecs_google_telephony.xml +++ b/media/libstagefright/data/media_codecs_google_telephony.xml @@ -16,6 +16,10 @@ - + + + + + -- cgit v1.1 From c0b56379020941b913419f0fabbc64c815539a53 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 14 Aug 2014 19:52:45 -0700 Subject: stagefright: add codec capability info for google video codecs Bug: 11990470 Change-Id: I3926551506ebc33181d50f532ef379be55b60147 --- .../data/media_codecs_google_video.xml | 91 +++++++++++++++++++--- 1 file changed, 81 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml index 9b930bc..c97be28 100644 --- a/media/libstagefright/data/media_codecs_google_video.xml +++ b/media/libstagefright/data/media_codecs_google_video.xml @@ -16,18 +16,89 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.1 From 475da7ef08c05a482ced8d318832cf5aa1141aff Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Fri, 8 Aug 2014 15:24:55 -0700 Subject: stagefright: Fix race condition between MediaCodec and SoftwareRenderer * Set the buffer's format info when it's returned from OMX component. * Move frame format meta from SoftwareRenderer's ctor to the render call. I.e. each frame sent to the renderer carries the format info. * Reset renderer with the new format instead of re-creating SoftwareRenderer when incoming frame's format is changed. Bug: 13842676 Change-Id: Ibab46f109200bcbdeab13a4cc1bcd0870f2a99fb --- media/libstagefright/AwesomePlayer.cpp | 12 ++- media/libstagefright/MediaCodec.cpp | 38 ++----- media/libstagefright/Utils.cpp | 38 +++++++ .../colorconversion/SoftwareRenderer.cpp | 114 +++++++++++++-------- media/libstagefright/include/SoftwareRenderer.h | 10 +- 5 files changed, 135 insertions(+), 77 deletions(-) (limited to 'media') diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index cd05c54..ab8ac79 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -103,8 +103,9 @@ private: struct AwesomeLocalRenderer : public AwesomeRenderer { AwesomeLocalRenderer( - const sp &nativeWindow, const sp &meta) - : mTarget(new SoftwareRenderer(nativeWindow, meta)) { + const sp &nativeWindow, const sp &format) + : mFormat(format), + mTarget(new SoftwareRenderer(nativeWindow)) { } virtual void render(MediaBuffer *buffer) { @@ -116,7 +117,7 @@ struct AwesomeLocalRenderer : public AwesomeRenderer { } void render(const void *data, size_t size, int64_t timestampNs) { - mTarget->render(data, size, timestampNs, NULL); + mTarget->render(data, size, timestampNs, NULL, mFormat); } protected: @@ -126,6 +127,7 @@ protected: } private: + sp mFormat; SoftwareRenderer *mTarget; AwesomeLocalRenderer(const AwesomeLocalRenderer &); @@ -1236,7 +1238,9 @@ void AwesomePlayer::initRenderer_l() { // allocate their buffers in local address space. This renderer // then performs a color conversion and copy to get the data // into the ANativeBuffer. - mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta); + sp format; + convertMetaDataToMessage(meta, &format); + mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, format); } } diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 42691b9..7bb7ed9 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -958,36 +958,14 @@ void MediaCodec::onMessageReceived(const sp &msg) { { ALOGV("codec output format changed"); - if ((mFlags & kFlagIsSoftwareCodec) - && mNativeWindow != NULL) { + if (mSoftRenderer == NULL && + mNativeWindow != NULL && + (mFlags & kFlagIsSoftwareCodec)) { AString mime; CHECK(msg->findString("mime", &mime)); - if (!strncasecmp("video/", mime.c_str(), 6)) { - delete mSoftRenderer; - mSoftRenderer = NULL; - - int32_t width, height; - CHECK(msg->findInt32("width", &width)); - CHECK(msg->findInt32("height", &height)); - - int32_t cropLeft, cropTop, cropRight, cropBottom; - CHECK(msg->findRect("crop", - &cropLeft, &cropTop, &cropRight, &cropBottom)); - - int32_t colorFormat; - CHECK(msg->findInt32( - "color-format", &colorFormat)); - - sp meta = new MetaData; - meta->setInt32(kKeyWidth, width); - meta->setInt32(kKeyHeight, height); - meta->setRect(kKeyCropRect, - cropLeft, cropTop, cropRight, cropBottom); - meta->setInt32(kKeyColorFormat, colorFormat); - - mSoftRenderer = - new SoftwareRenderer(mNativeWindow, meta); + if (mime.startsWithIgnoreCase("video/")) { + mSoftRenderer = new SoftwareRenderer(mNativeWindow); } } @@ -1799,6 +1777,8 @@ size_t MediaCodec::updateBuffers( CHECK(info->mNotify == NULL); CHECK(msg->findMessage("reply", &info->mNotify)); + info->mFormat = + (portIndex == kPortIndexInput) ? mInputFormat : mOutputFormat; mAvailPortBuffers[portIndex].push_back(i); return i; @@ -1978,7 +1958,8 @@ status_t MediaCodec::onReleaseOutputBuffer(const sp &msg) { if (mSoftRenderer != NULL) { mSoftRenderer->render( - info->mData->data(), info->mData->size(), timestampNs, NULL); + info->mData->data(), info->mData->size(), + timestampNs, NULL, info->mFormat); } } @@ -2004,7 +1985,6 @@ ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) { CHECK(!info->mOwnedByClient); { Mutex::Autolock al(mBufferLock); - info->mFormat = portIndex == kPortIndexInput ? mInputFormat : mOutputFormat; info->mOwnedByClient = true; // set image-data diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 5f1d1c6..25afc5b 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -109,6 +109,25 @@ status_t convertMetaDataToMessage( msg->setInt32("sar-width", sarWidth); msg->setInt32("sar-height", sarHeight); } + + int32_t colorFormat; + if (meta->findInt32(kKeyColorFormat, &colorFormat)) { + msg->setInt32("color-format", colorFormat); + } + + int32_t cropLeft, cropTop, cropRight, cropBottom; + if (meta->findRect(kKeyCropRect, + &cropLeft, + &cropTop, + &cropRight, + &cropBottom)) { + msg->setRect("crop", cropLeft, cropTop, cropRight, cropBottom); + } + + int32_t rotationDegrees; + if (meta->findInt32(kKeyRotation, &rotationDegrees)) { + msg->setInt32("rotation-degrees", rotationDegrees); + } } else if (!strncasecmp("audio/", mime, 6)) { int32_t numChannels, sampleRate; CHECK(meta->findInt32(kKeyChannelCount, &numChannels)); @@ -475,6 +494,25 @@ void convertMessageToMetaData(const sp &msg, sp &meta) { meta->setInt32(kKeySARWidth, sarWidth); meta->setInt32(kKeySARHeight, sarHeight); } + + int32_t colorFormat; + if (msg->findInt32("color-format", &colorFormat)) { + meta->setInt32(kKeyColorFormat, colorFormat); + } + + int32_t cropLeft, cropTop, cropRight, cropBottom; + if (msg->findRect("crop", + &cropLeft, + &cropTop, + &cropRight, + &cropBottom)) { + meta->setRect(kKeyCropRect, cropLeft, cropTop, cropRight, cropBottom); + } + + int32_t rotationDegrees; + if (msg->findInt32("rotation-degrees", &rotationDegrees)) { + meta->setInt32(kKeyRotation, rotationDegrees); + } } else if (mime.startsWith("audio/")) { int32_t numChannels; if (msg->findInt32("channel-count", &numChannels)) { diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp index 0c5527a..cc98da0 100644 --- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp +++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp @@ -21,7 +21,7 @@ #include // for property_get #include -#include +#include #include #include #include @@ -33,34 +33,71 @@ static bool runningInEmulator() { return (property_get("ro.kernel.qemu", prop, NULL) > 0); } -SoftwareRenderer::SoftwareRenderer( - const sp &nativeWindow, const sp &meta) - : mConverter(NULL), +static int ALIGN(int x, int y) { + // y must be a power of 2. + return (x + y - 1) & ~(y - 1); +} + +SoftwareRenderer::SoftwareRenderer(const sp &nativeWindow) + : mColorFormat(OMX_COLOR_FormatUnused), + mConverter(NULL), mYUVMode(None), - mNativeWindow(nativeWindow) { - int32_t tmp; - CHECK(meta->findInt32(kKeyColorFormat, &tmp)); - mColorFormat = (OMX_COLOR_FORMATTYPE)tmp; - - CHECK(meta->findInt32(kKeyWidth, &mWidth)); - CHECK(meta->findInt32(kKeyHeight, &mHeight)); - - if (!meta->findRect( - kKeyCropRect, - &mCropLeft, &mCropTop, &mCropRight, &mCropBottom)) { - mCropLeft = mCropTop = 0; - mCropRight = mWidth - 1; - mCropBottom = mHeight - 1; + mNativeWindow(nativeWindow), + mWidth(0), + mHeight(0), + mCropLeft(0), + mCropTop(0), + mCropRight(0), + mCropBottom(0), + mCropWidth(0), + mCropHeight(0) { +} + +SoftwareRenderer::~SoftwareRenderer() { + delete mConverter; + mConverter = NULL; +} + +void SoftwareRenderer::resetFormatIfChanged(const sp &format) { + CHECK(format != NULL); + + int32_t colorFormatNew; + CHECK(format->findInt32("color-format", &colorFormatNew)); + + int32_t widthNew, heightNew; + CHECK(format->findInt32("width", &widthNew)); + CHECK(format->findInt32("height", &heightNew)); + + int32_t cropLeftNew, cropTopNew, cropRightNew, cropBottomNew; + if (!format->findRect( + "crop", &cropLeftNew, &cropTopNew, &cropRightNew, &cropBottomNew)) { + cropLeftNew = cropTopNew = 0; + cropRightNew = widthNew - 1; + cropBottomNew = heightNew - 1; } + if (static_cast(mColorFormat) == colorFormatNew && + mWidth == widthNew && + mHeight == heightNew && + mCropLeft == cropLeftNew && + mCropTop == cropTopNew && + mCropRight == cropRightNew && + mCropBottom == cropBottomNew) { + // Nothing changed, no need to reset renderer. + return; + } + + mColorFormat = static_cast(colorFormatNew); + mWidth = widthNew; + mHeight = heightNew; + mCropLeft = cropLeftNew; + mCropTop = cropTopNew; + mCropRight = cropRightNew; + mCropBottom = cropBottomNew; + mCropWidth = mCropRight - mCropLeft + 1; mCropHeight = mCropBottom - mCropTop + 1; - int32_t rotationDegrees; - if (!meta->findInt32(kKeyRotation, &rotationDegrees)) { - rotationDegrees = 0; - } - int halFormat; size_t bufWidth, bufHeight; @@ -106,10 +143,12 @@ SoftwareRenderer::SoftwareRenderer( NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)); // Width must be multiple of 32??? - CHECK_EQ(0, native_window_set_buffers_geometry( + CHECK_EQ(0, native_window_set_buffers_dimensions( mNativeWindow.get(), bufWidth, - bufHeight, + bufHeight)); + CHECK_EQ(0, native_window_set_buffers_format( + mNativeWindow.get(), halFormat)); // NOTE: native window uses extended right-bottom coordinate @@ -123,6 +162,10 @@ SoftwareRenderer::SoftwareRenderer( CHECK_EQ(0, native_window_set_crop(mNativeWindow.get(), &crop)); + int32_t rotationDegrees; + if (!format->findInt32("rotation-degrees", &rotationDegrees)) { + rotationDegrees = 0; + } uint32_t transform; switch (rotationDegrees) { case 0: transform = 0; break; @@ -132,24 +175,15 @@ SoftwareRenderer::SoftwareRenderer( default: transform = 0; break; } - if (transform) { - CHECK_EQ(0, native_window_set_buffers_transform( - mNativeWindow.get(), transform)); - } -} - -SoftwareRenderer::~SoftwareRenderer() { - delete mConverter; - mConverter = NULL; -} - -static int ALIGN(int x, int y) { - // y must be a power of 2. - return (x + y - 1) & ~(y - 1); + CHECK_EQ(0, native_window_set_buffers_transform( + mNativeWindow.get(), transform)); } void SoftwareRenderer::render( - const void *data, size_t size, int64_t timestampNs, void *platformPrivate) { + const void *data, size_t /*size*/, int64_t timestampNs, + void* /*platformPrivate*/, const sp& format) { + resetFormatIfChanged(format); + ANativeWindowBuffer *buf; int err; if ((err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h index 0ba670c..fa3ea89 100644 --- a/media/libstagefright/include/SoftwareRenderer.h +++ b/media/libstagefright/include/SoftwareRenderer.h @@ -24,17 +24,17 @@ namespace android { -struct MetaData; +struct AMessage; class SoftwareRenderer { public: - SoftwareRenderer( - const sp &nativeWindow, const sp &meta); + explicit SoftwareRenderer(const sp &nativeWindow); ~SoftwareRenderer(); void render( - const void *data, size_t size, int64_t timestampNs, void *platformPrivate); + const void *data, size_t size, int64_t timestampNs, + void *platformPrivate, const sp &format); private: enum YUVMode { @@ -51,6 +51,8 @@ private: SoftwareRenderer(const SoftwareRenderer &); SoftwareRenderer &operator=(const SoftwareRenderer &); + + void resetFormatIfChanged(const sp &format); }; } // namespace android -- cgit v1.1 From dc9aa7e2cb903bb4ebfce558671a97088477bb6e Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 19 Aug 2014 16:53:42 -0700 Subject: Don't crash for bitstream errors in AMPEG4ElementaryAssembler Bug: 17110981 Change-Id: I0d0960fa12f2ad179231494be29af307de217b2a --- media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp index 98b50dd..76f8f54 100644 --- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp +++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp @@ -249,11 +249,15 @@ ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket( mPackets.push_back(buffer); } else { // hexdump(buffer->data(), buffer->size()); + if (buffer->size() < 2) { + return MALFORMED_PACKET; + } - CHECK_GE(buffer->size(), 2u); unsigned AU_headers_length = U16_AT(buffer->data()); // in bits - CHECK_GE(buffer->size(), 2 + (AU_headers_length + 7) / 8); + if (buffer->size() < 2 + (AU_headers_length + 7) / 8) { + return MALFORMED_PACKET; + } List headers; @@ -342,7 +346,9 @@ ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket( it != headers.end(); ++it) { const AUHeader &header = *it; - CHECK_LE(offset + header.mSize, buffer->size()); + if (buffer->size() < offset + header.mSize) { + return MALFORMED_PACKET; + } sp accessUnit = new ABuffer(header.mSize); memcpy(accessUnit->data(), buffer->data() + offset, header.mSize); @@ -352,8 +358,6 @@ ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket( CopyTimes(accessUnit, buffer); mPackets.push_back(accessUnit); } - - CHECK_EQ(offset, buffer->size()); } queue->erase(queue->begin()); @@ -400,6 +404,7 @@ ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::assembleMore( const sp &source) { AssemblyStatus status = addPacket(source); if (status == MALFORMED_PACKET) { + ALOGI("access unit is damaged"); mAccessUnitDamaged = true; } return status; -- cgit v1.1 From f2575571d88cd42508407e98957a19a875dcf926 Mon Sep 17 00:00:00 2001 From: aarti jadhav-gaikwad Date: Wed, 13 Aug 2014 15:04:39 +0530 Subject: stagefright: Do not add silence data for compress offload Bug: 16683770 Bug: 17035257 Change-Id: I7aef543c47214cc2854d143167b02f1603cf8bea --- media/libmediaplayerservice/MediaPlayerService.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index a706987..2c48306 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1898,7 +1898,8 @@ void MediaPlayerService::AudioOutput::CallbackWrapper( me, buffer->raw, buffer->size, me->mCallbackCookie, CB_EVENT_FILL_BUFFER); - if (actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) { + if ((me->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0 && + actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) { // We've reached EOS but the audio track is not stopped yet, // keep playing silence. -- cgit v1.1 From 3e5efb37308aa1f54c2a72cd8a7a73d2d7921a90 Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Mon, 18 Aug 2014 16:27:08 -0700 Subject: NuPlayerRenderer: only query audio sink for position for the first entry. Bug: 17035257 Change-Id: I472ec4610e1174c59986f42d72fe55f90e93731e --- media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 3640038..3777f64 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -318,6 +318,7 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { bool hasEOS = false; size_t sizeCopied = 0; + bool firstEntry = true; while (sizeCopied < size && !mAudioQueue.empty()) { QueueEntry *entry = &*mAudioQueue.begin(); @@ -328,14 +329,14 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { break; } - if (entry->mOffset == 0) { + if (firstEntry && entry->mOffset == 0) { + firstEntry = false; int64_t mediaTimeUs; CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); if (mFirstAudioTimeUs == -1) { mFirstAudioTimeUs = mediaTimeUs; } - mAnchorTimeMediaUs = mediaTimeUs; uint32_t numFramesPlayed; CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); -- cgit v1.1 From 1ffb5381ca40884868299a2ac8a1424b68a1a43e Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Mon, 18 Aug 2014 15:57:03 -0700 Subject: NuPlayer: disable deep audio buffer in offload mode. Bug: 17035257 Change-Id: I56ca28d4c4774c1c0103d19126cf0b8f859964b7 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 5e7ecfa..7ed65de 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1061,6 +1061,7 @@ void NuPlayer::openAudioSink(const sp &format, bool offloadOnly) { } ALOGV("openAudioSink: try to open AudioSink in offload mode"); flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; + flags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER; audioSinkChanged = true; mAudioSink->close(); err = mAudioSink->open( -- cgit v1.1 From a518dd9ac06d519bf226e6b1e952f85d6078eecc Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Mon, 4 Aug 2014 16:59:20 -0700 Subject: stagefright: Fix thumbnail generation for some clips. Fix thumbnail generation for clips that include an immediate resolution change: * Enable dynamic resolution change, when port settings may change while we have filled buffers. * Handle the case when port settings change happens right after stop is called. Bug: 16210021 Change-Id: I8b2c48365d74ce7551f000a1f4b0711647a9796f --- media/libstagefright/OMXCodec.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'media') diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 3d1d40e..78758da 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -2500,12 +2500,6 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { data1, data2); if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) { - // There is no need to check whether mFilledBuffers is empty or not - // when the OMX_EventPortSettingsChanged is not meant for reallocating - // the output buffers. - if (data1 == kPortIndexOutput) { - CHECK(mFilledBuffers.empty()); - } onPortSettingsChanged(data1); } else if (data1 == kPortIndexOutput && (data2 == OMX_IndexConfigCommonOutputCrop || @@ -2899,7 +2893,7 @@ status_t OMXCodec::freeBuffer(OMX_U32 portIndex, size_t bufIndex) { void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) { CODEC_LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex); - CHECK_EQ((int)mState, (int)EXECUTING); + CHECK(mState == EXECUTING || mState == EXECUTING_TO_IDLE); CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput); CHECK(!mOutputPortSettingsChangedPending); -- cgit v1.1 From 9d7fc5c5fab0c7c967a625d22fffda046f9d5c29 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Mon, 18 Aug 2014 17:17:03 -0700 Subject: HTTPLiveSource: check for NULL before getTrackCount/Info The effect is MediaPlayer returns a 0-length array when getTrackInfo is called before PREPARED state. Bug: 12029173 Change-Id: Ib3a48525eac07b04a2ff88ce199d66dcc61c1641 --- media/libstagefright/httplive/LiveSession.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 8667a6b..7b18348 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -1019,11 +1019,19 @@ bool LiveSession::hasDynamicDuration() const { } size_t LiveSession::getTrackCount() const { - return mPlaylist->getTrackCount(); + if (mPlaylist == NULL) { + return 0; + } else { + return mPlaylist->getTrackCount(); + } } sp LiveSession::getTrackInfo(size_t trackIndex) const { - return mPlaylist->getTrackInfo(trackIndex); + if (mPlaylist == NULL) { + return NULL; + } else { + return mPlaylist->getTrackInfo(trackIndex); + } } status_t LiveSession::selectTrack(size_t index, bool select) { -- cgit v1.1 From 53904f372b9c4a5ea7f839012b52b3d564e41207 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Tue, 29 Jul 2014 10:22:53 -0700 Subject: Allow audio and video flushed separately. Bug: 14955925 Bug: 16303659 Bug: 16467066 Bug: 13133027 Change-Id: I956a9f55513970115119c7639a5e33b39e6d2f55 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 68 +++++------------------ media/libmediaplayerservice/nuplayer/NuPlayer.h | 1 - 2 files changed, 14 insertions(+), 55 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 5e7ecfa..c4ae43d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -943,11 +943,13 @@ void NuPlayer::onMessageReceived(const sp &msg) { } void NuPlayer::finishFlushIfPossible() { - if (mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) { + if (mFlushingAudio != NONE && mFlushingAudio != FLUSHED + && mFlushingAudio != SHUT_DOWN) { return; } - if (mFlushingVideo != FLUSHED && mFlushingVideo != SHUT_DOWN) { + if (mFlushingVideo != NONE && mFlushingVideo != FLUSHED + && mFlushingVideo != SHUT_DOWN) { return; } @@ -958,11 +960,11 @@ void NuPlayer::finishFlushIfPossible() { mTimeDiscontinuityPending = false; } - if (mAudioDecoder != NULL) { + if (mAudioDecoder != NULL && mFlushingAudio == FLUSHED) { mAudioDecoder->signalResume(); } - if (mVideoDecoder != NULL) { + if (mVideoDecoder != NULL && mFlushingVideo == FLUSHED) { mVideoDecoder->signalResume(); } @@ -1195,8 +1197,8 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { sp reply; CHECK(msg->findMessage("reply", &reply)); - if ((audio && IsFlushingState(mFlushingAudio)) - || (!audio && IsFlushingState(mFlushingVideo))) { + if ((audio && mFlushingAudio != NONE) + || (!audio && mFlushingVideo != NONE)) { reply->setInt32("err", INFO_DISCONTINUITY); reply->post(); return OK; @@ -1276,15 +1278,6 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { } } else { // This stream is unaffected by the discontinuity - - if (audio) { - mFlushingAudio = FLUSHED; - } else { - mFlushingVideo = FLUSHED; - } - - finishFlushIfPossible(); - return -EWOULDBLOCK; } } @@ -1335,7 +1328,8 @@ void NuPlayer::renderBuffer(bool audio, const sp &msg) { sp reply; CHECK(msg->findMessage("reply", &reply)); - if (IsFlushingState(audio ? mFlushingAudio : mFlushingVideo)) { + if ((audio && mFlushingAudio != NONE) + || (!audio && mFlushingVideo != NONE)) { // We're currently attempting to flush the decoder, in order // to complete this, the decoder wants all its buffers back, // so we don't want any output buffers it sent us (from before @@ -1480,27 +1474,13 @@ void NuPlayer::flushDecoder(bool audio, bool needShutdown) { needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER; if (audio) { - CHECK(mFlushingAudio == NONE - || mFlushingAudio == AWAITING_DISCONTINUITY); - + ALOGE_IF(mFlushingAudio != NONE, + "audio flushDecoder() is called in state %d", mFlushingAudio); mFlushingAudio = newStatus; - - if (mFlushingVideo == NONE) { - mFlushingVideo = (mVideoDecoder != NULL) - ? AWAITING_DISCONTINUITY - : FLUSHED; - } } else { - CHECK(mFlushingVideo == NONE - || mFlushingVideo == AWAITING_DISCONTINUITY); - + ALOGE_IF(mFlushingVideo != NONE, + "video flushDecoder() is called in state %d", mFlushingVideo); mFlushingVideo = newStatus; - - if (mFlushingAudio == NONE) { - mFlushingAudio = (mAudioDecoder != NULL) - ? AWAITING_DISCONTINUITY - : FLUSHED; - } } } @@ -1590,18 +1570,6 @@ void NuPlayer::processDeferredActions() { // an intermediate state, i.e. one more more decoders are currently // flushing or shutting down. - if (mRenderer != NULL) { - // There's an edge case where the renderer owns all output - // buffers and is paused, therefore the decoder will not read - // more input data and will never encounter the matching - // discontinuity. To avoid this, we resume the renderer. - - if (mFlushingAudio == AWAITING_DISCONTINUITY - || mFlushingVideo == AWAITING_DISCONTINUITY) { - mRenderer->resume(); - } - } - if (mFlushingAudio != NONE || mFlushingVideo != NONE) { // We're currently flushing, postpone the reset until that's // completed. @@ -1666,14 +1634,6 @@ void NuPlayer::performDecoderShutdown(bool audio, bool video) { mTimeDiscontinuityPending = true; - if (mFlushingAudio == NONE && (!audio || mAudioDecoder == NULL)) { - mFlushingAudio = FLUSHED; - } - - if (mFlushingVideo == NONE && (!video || mVideoDecoder == NULL)) { - mFlushingVideo = FLUSHED; - } - if (audio && mAudioDecoder != NULL) { flushDecoder(true /* audio */, true /* needShutdown */); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 48882c5..cc74ad0 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -143,7 +143,6 @@ private: enum FlushStatus { NONE, - AWAITING_DISCONTINUITY, FLUSHING_DECODER, FLUSHING_DECODER_SHUTDOWN, SHUTTING_DOWN_DECODER, -- cgit v1.1 From 76dc9c5052741bf0910a23a20c9df6018c4979d8 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 20 Aug 2014 10:51:07 -0700 Subject: StagefrightRecorder: add VIDEO_ENCODER_VP8 case in setupVideoEncoder Bug: 16329805 Change-Id: Ibc80cdeb1958f739dd67b65e57f6b7cc551a9db3 --- media/libmediaplayerservice/StagefrightRecorder.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 8774117..e2bcb1e 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -1433,6 +1433,10 @@ status_t StagefrightRecorder::setupVideoEncoder( format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC); break; + case VIDEO_ENCODER_VP8: + format->setString("mime", MEDIA_MIMETYPE_VIDEO_VP8); + break; + default: CHECK(!"Should not be here, unsupported video encoding."); break; -- cgit v1.1 From eb645a0d1820b227af287a5309f017afadbab4e3 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 20 Aug 2014 09:44:44 -0700 Subject: Fix NuPlayer deadlock Mutexes can't be locked recursively. This would cause a seek in the prepared state to deadlock Bug: 14057920 Change-Id: Ifb5e25f24450b7e5f71611a8ee2bdba45dba70a7 --- .../nuplayer/NuPlayerDriver.cpp | 33 +++++++++++++--------- .../nuplayer/NuPlayerDriver.h | 1 + 2 files changed, 20 insertions(+), 14 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 140e1ae..e11f40e 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -227,7 +227,7 @@ status_t NuPlayerDriver::start() { if (mStartupSeekTimeUs >= 0) { if (mStartupSeekTimeUs == 0) { - notifySeekComplete(); + notifySeekComplete_l(); } else { mPlayer->seekToAsync(mStartupSeekTimeUs); } @@ -320,7 +320,7 @@ status_t NuPlayerDriver::seekTo(int msec) { // pretend that the seek completed. It will actually happen when starting playback. // TODO: actually perform the seek here, so the player is ready to go at the new // location - notifySeekComplete(); + notifySeekComplete_l(); break; } @@ -525,23 +525,28 @@ void NuPlayerDriver::notifyPosition(int64_t positionUs) { } void NuPlayerDriver::notifySeekComplete() { + Mutex::Autolock autoLock(mLock); + notifySeekComplete_l(); +} + +void NuPlayerDriver::notifySeekComplete_l() { bool wasSeeking = true; - { - Mutex::Autolock autoLock(mLock); - if (mState == STATE_STOPPED_AND_PREPARING) { - wasSeeking = false; - mState = STATE_STOPPED_AND_PREPARED; - mCondition.broadcast(); - if (!mIsAsyncPrepare) { - // if we are preparing synchronously, no need to notify listener - return; - } - } else if (mState == STATE_STOPPED) { - // no need to notify listener + if (mState == STATE_STOPPED_AND_PREPARING) { + wasSeeking = false; + mState = STATE_STOPPED_AND_PREPARED; + mCondition.broadcast(); + if (!mIsAsyncPrepare) { + // if we are preparing synchronously, no need to notify listener return; } + } else if (mState == STATE_STOPPED) { + // no need to notify listener + return; } + // note: notifyListener called with lock held + mLock.unlock(); notifyListener(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED); + mLock.lock(); } void NuPlayerDriver::notifyFrameStats( diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index f520395..a006d8f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -69,6 +69,7 @@ struct NuPlayerDriver : public MediaPlayerInterface { void notifyDuration(int64_t durationUs); void notifyPosition(int64_t positionUs); void notifySeekComplete(); + void notifySeekComplete_l(); void notifyFrameStats(int64_t numFramesTotal, int64_t numFramesDropped); void notifyListener(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL); void notifyFlagsChanged(uint32_t flags); -- cgit v1.1 From 9e2b7918eb5621b24bd54c922f630da45339de77 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 18 Aug 2014 16:13:03 -0700 Subject: handle error during flush in MediaPlayer.reset() If there was an error during the flush phase of a reset, then the reset would never complete. We now make sure the MediaCodec moves to the right state in this case, and that NuPlayer cleans up and resumes the rest of the reset after a failed flush. Bug: 16955082 Change-Id: Ied61136871a9fcdffcc80647fa2bba64a926ac2a --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 8 ++++++++ media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 4 ++-- media/libstagefright/MediaCodec.cpp | 11 ++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 5e7ecfa..818155c 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -782,6 +782,14 @@ void NuPlayer::onMessageReceived(const sp &msg) { err = UNKNOWN_ERROR; } mRenderer->queueEOS(audio, err); + if (audio && mFlushingAudio != NONE) { + mAudioDecoder.clear(); + mFlushingAudio = SHUT_DOWN; + } else if (!audio && mFlushingVideo != NONE){ + mVideoDecoder.clear(); + mFlushingVideo = SHUT_DOWN; + } + finishFlushIfPossible(); } else if (what == Decoder::kWhatDrainThisBuffer) { renderBuffer(audio, msg); } else { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 8fce2f4..60c645a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -44,11 +44,11 @@ NuPlayer::Decoder::Decoder( // Every decoder has its own looper because MediaCodec operations // are blocking, but NuPlayer needs asynchronous operations. mDecoderLooper = new ALooper; - mDecoderLooper->setName("NuPlayerDecoder"); + mDecoderLooper->setName("NPDecoder"); mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO); mCodecLooper = new ALooper; - mCodecLooper->setName("NuPlayerDecoder-MC"); + mCodecLooper->setName("NPDecoder-CL"); mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO); } diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 42691b9..1181c2b 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -716,7 +716,8 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->findInt32("err", &err)); CHECK(msg->findInt32("actionCode", &actionCode)); - ALOGE("Codec reported err %#x, actionCode %d", err, actionCode); + ALOGE("Codec reported err %#x, actionCode %d, while in state %d", + err, actionCode, mState); if (err == DEAD_OBJECT) { mFlags |= kFlagSawMediaServerDie; } @@ -767,8 +768,12 @@ void MediaCodec::onMessageReceived(const sp &msg) { case FLUSHING: { - setState( - (mFlags & kFlagIsAsync) ? FLUSHED : STARTED); + if (actionCode == ACTION_CODE_FATAL) { + setState(UNINITIALIZED); + } else { + setState( + (mFlags & kFlagIsAsync) ? FLUSHED : STARTED); + } break; } -- cgit v1.1 From 88703c34fb4a9db1ff51495879f9775474c8ce89 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 6 Aug 2014 11:24:07 -0700 Subject: NuPlayer: use generation to detect stale requests from old decoders. Bug: 14955925 Bug: 16303659 Bug: 16467066 Bug: 13133027 Change-Id: I3e66b25b2302c0eb795361629b03bf2e96ed34e4 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 33 ++++++++++++++++++++--- media/libmediaplayerservice/nuplayer/NuPlayer.h | 2 ++ 2 files changed, 31 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 5e7ecfa..0cba7f7 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -148,6 +148,8 @@ NuPlayer::NuPlayer() mVideoIsAVC(false), mOffloadAudio(false), mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER), + mAudioDecoderGeneration(0), + mVideoDecoderGeneration(0), mAudioEOS(false), mVideoEOS(false), mScanSourcesPending(false), @@ -691,6 +693,25 @@ void NuPlayer::onMessageReceived(const sp &msg) { { bool audio = msg->what() == kWhatAudioNotify; + int32_t currentDecoderGeneration = + (audio? mAudioDecoderGeneration : mVideoDecoderGeneration); + int32_t requesterGeneration = currentDecoderGeneration - 1; + CHECK(msg->findInt32("generation", &requesterGeneration)); + + if (requesterGeneration != currentDecoderGeneration) { + ALOGV("got message from old %s decoder, generation(%d:%d)", + audio ? "audio" : "video", requesterGeneration, + currentDecoderGeneration); + sp reply; + if (!(msg->findMessage("reply", &reply))) { + return; + } + + reply->setInt32("err", INFO_DISCONTINUITY); + reply->post(); + return; + } + int32_t what; CHECK(msg->findInt32("what", &what)); @@ -1150,17 +1171,21 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp *decoder) { } } - sp notify = - new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify, - id()); - if (audio) { + sp notify = new AMessage(kWhatAudioNotify, id()); + ++mAudioDecoderGeneration; + notify->setInt32("generation", mAudioDecoderGeneration); + if (mOffloadAudio) { *decoder = new DecoderPassThrough(notify); } else { *decoder = new Decoder(notify); } } else { + sp notify = new AMessage(kWhatVideoNotify, id()); + ++mVideoDecoderGeneration; + notify->setInt32("generation", mVideoDecoderGeneration); + *decoder = new Decoder(notify, mNativeWindow); } (*decoder)->init(); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 48882c5..bb76636 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -129,6 +129,8 @@ private: sp mCCDecoder; sp mRenderer; sp mRendererLooper; + int32_t mAudioDecoderGeneration; + int32_t mVideoDecoderGeneration; List > mDeferredActions; -- cgit v1.1 From 28a8a9ff2a2bfd5edbdbbadde50c6d804335ffdc Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Mon, 18 Aug 2014 11:29:50 -0700 Subject: NuPlayerRenderer: allow flush() to be called multiple times. Also fix racing condition on accessing some members. Bug: 16982307 Bug: 13133027 Change-Id: I0d4a605146e24ad7396a07369d501593cad73f41 --- .../nuplayer/NuPlayerRenderer.cpp | 68 ++++++++++++++-------- 1 file changed, 43 insertions(+), 25 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 3640038..8391b9e 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -93,10 +93,14 @@ void NuPlayer::Renderer::flush(bool audio) { { Mutex::Autolock autoLock(mFlushLock); if (audio) { - CHECK(!mFlushingAudio); + if (mFlushingAudio) { + return; + } mFlushingAudio = true; } else { - CHECK(!mFlushingVideo); + if (mFlushingVideo) { + return; + } mFlushingVideo = true; } } @@ -115,6 +119,14 @@ void NuPlayer::Renderer::signalTimeDiscontinuity() { mSyncQueues = false; } +void NuPlayer::Renderer::signalAudioSinkChanged() { + (new AMessage(kWhatAudioSinkChanged, id()))->post(); +} + +void NuPlayer::Renderer::signalDisableOffloadAudio() { + (new AMessage(kWhatDisableOffloadAudio, id()))->post(); +} + void NuPlayer::Renderer::pause() { (new AMessage(kWhatPause, id()))->post(); } @@ -251,14 +263,6 @@ void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) { msg->post(delayUs); } -void NuPlayer::Renderer::signalAudioSinkChanged() { - (new AMessage(kWhatAudioSinkChanged, id()))->post(); -} - -void NuPlayer::Renderer::signalDisableOffloadAudio() { - (new AMessage(kWhatDisableOffloadAudio, id()))->post(); -} - void NuPlayer::Renderer::prepareForMediaRenderingStart() { mAudioRenderingStartGeneration = mAudioQueueGeneration; mVideoRenderingStartGeneration = mVideoQueueGeneration; @@ -716,6 +720,15 @@ void NuPlayer::Renderer::onFlush(const sp &msg) { int32_t audio; CHECK(msg->findInt32("audio", &audio)); + { + Mutex::Autolock autoLock(mFlushLock); + if (audio) { + mFlushingAudio = false; + } else { + mFlushingVideo = false; + } + } + // If we're currently syncing the queues, i.e. dropping audio while // aligning the first audio/video buffer times and only one of the // two queues has data, we may starve that queue by not requesting @@ -734,17 +747,18 @@ void NuPlayer::Renderer::onFlush(const sp &msg) { { Mutex::Autolock autoLock(mLock); flushQueue(&mAudioQueue); - } - Mutex::Autolock autoLock(mFlushLock); - mFlushingAudio = false; + ++mAudioQueueGeneration; + prepareForMediaRenderingStart(); + + if (offloadingAudio()) { + mFirstAudioTimeUs = -1; + } + } mDrainAudioQueuePending = false; - ++mAudioQueueGeneration; - prepareForMediaRenderingStart(); if (offloadingAudio()) { - mFirstAudioTimeUs = -1; mAudioSink->pause(); mAudioSink->flush(); mAudioSink->start(); @@ -752,9 +766,6 @@ void NuPlayer::Renderer::onFlush(const sp &msg) { } else { flushQueue(&mVideoQueue); - Mutex::Autolock autoLock(mFlushLock); - mFlushingVideo = false; - mDrainVideoQueuePending = false; ++mVideoQueueGeneration; @@ -852,13 +863,15 @@ void NuPlayer::Renderer::notifyPosition() { void NuPlayer::Renderer::onPause() { CHECK(!mPaused); - mDrainAudioQueuePending = false; - ++mAudioQueueGeneration; + { + Mutex::Autolock autoLock(mLock); + ++mAudioQueueGeneration; + ++mVideoQueueGeneration; + prepareForMediaRenderingStart(); + } + mDrainAudioQueuePending = false; mDrainVideoQueuePending = false; - ++mVideoQueueGeneration; - - prepareForMediaRenderingStart(); if (mHasAudio) { mAudioSink->pause(); @@ -895,7 +908,12 @@ void NuPlayer::Renderer::onAudioOffloadTearDown() { uint32_t numFramesPlayed; CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); - int64_t currentPositionUs = mFirstAudioTimeUs + int64_t firstAudioTimeUs; + { + Mutex::Autolock autoLock(mLock); + firstAudioTimeUs = mFirstAudioTimeUs; + } + int64_t currentPositionUs = firstAudioTimeUs + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll; mAudioSink->stop(); -- cgit v1.1 From 80804f4e953d6c5f6ed0c3c8e004c4cce280f5c1 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 19 Aug 2014 18:07:08 -0700 Subject: print warning if offset != buffer size Bug: 17110981 Change-Id: Iacceca203372f4c06ff5ef7ce98edd5554727b64 --- media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'media') diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp index 76f8f54..7eb6542 100644 --- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp +++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp @@ -358,6 +358,11 @@ ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket( CopyTimes(accessUnit, buffer); mPackets.push_back(accessUnit); } + + if (offset != buffer->size()) { + ALOGW("potentially malformed packet (offset %d, size %d)", + offset, buffer->size()); + } } queue->erase(queue->begin()); -- cgit v1.1 From 44d3281b6529370efb72fe2fb126ee3a468d53e2 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 20 Aug 2014 12:46:47 -0700 Subject: Fix typo in comment Bug: 14057920 Change-Id: I51c4d47b9e175ef789ed3c51d59c9eda77edc1e0 --- media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index e11f40e..8a63cfe 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -543,7 +543,7 @@ void NuPlayerDriver::notifySeekComplete_l() { // no need to notify listener return; } - // note: notifyListener called with lock held + // note: notifyListener called with lock released mLock.unlock(); notifyListener(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED); mLock.lock(); -- cgit v1.1 From 9b48f5d780757ffb81709df3633d06b62edaf39f Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 20 Aug 2014 13:58:34 -0700 Subject: disable AwesomePlayer for Ogg vorbis Bug: 17108024 Change-Id: I0a970e6476d0f739e65d2200d0f5220dee8d36ef --- media/libmediaplayerservice/MediaPlayerFactory.cpp | 25 ++++++++++++---------- media/libmediaplayerservice/MediaPlayerFactory.h | 1 - 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp index dacb144..3e0fc0d 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.cpp +++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp @@ -60,7 +60,7 @@ status_t MediaPlayerFactory::registerFactory_l(IFactory* factory, return OK; } -player_type MediaPlayerFactory::getDefaultPlayerType() { +static player_type getDefaultPlayerType() { char value[PROPERTY_VALUE_MAX]; if (property_get("media.stagefright.use-awesome", value, NULL) && (!strcmp("1", value) || !strcasecmp("true", value))) { @@ -181,16 +181,19 @@ class StagefrightPlayerFactory : int64_t offset, int64_t /*length*/, float /*curScore*/) { - char buf[20]; - lseek(fd, offset, SEEK_SET); - read(fd, buf, sizeof(buf)); - lseek(fd, offset, SEEK_SET); - - uint32_t ident = *((uint32_t*)buf); - - // Ogg vorbis? - if (ident == 0x5367674f) // 'OggS' - return 1.0; + if (getDefaultPlayerType() + == STAGEFRIGHT_PLAYER) { + char buf[20]; + lseek(fd, offset, SEEK_SET); + read(fd, buf, sizeof(buf)); + lseek(fd, offset, SEEK_SET); + + uint32_t ident = *((uint32_t*)buf); + + // Ogg vorbis? + if (ident == 0x5367674f) // 'OggS' + return 1.0; + } return 0.0; } diff --git a/media/libmediaplayerservice/MediaPlayerFactory.h b/media/libmediaplayerservice/MediaPlayerFactory.h index 5ddde19..55ff918 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.h +++ b/media/libmediaplayerservice/MediaPlayerFactory.h @@ -71,7 +71,6 @@ class MediaPlayerFactory { static status_t registerFactory_l(IFactory* factory, player_type type); - static player_type getDefaultPlayerType(); static Mutex sLock; static tFactoryMap sFactoryMap; -- cgit v1.1 From 15506a6582fb86567c6887c4c426d44be02d12af Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 20 Aug 2014 15:14:44 -0700 Subject: NuPlayerDriver: include lapsed time when reporting current position. Bug: 17031731 Change-Id: I01962ee9194bdaa9e8ed1a51abbf365733be3c85 --- media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 11 ++++++++++- media/libmediaplayerservice/nuplayer/NuPlayerDriver.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 8a63cfe..c0091bf 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -36,6 +36,8 @@ NuPlayerDriver::NuPlayerDriver() mAsyncResult(UNKNOWN_ERROR), mDurationUs(-1), mPositionUs(-1), + mNotifyTimeRealUs(0), + mPauseStartedTimeUs(0), mNumFramesTotal(0), mNumFramesDropped(0), mLooper(new ALooper), @@ -244,6 +246,7 @@ status_t NuPlayerDriver::start() { case STATE_STOPPED_AND_PREPARED: { mPlayer->resume(); + mPositionUs -= ALooper::GetNowUs() - mPauseStartedTimeUs; break; } @@ -278,6 +281,7 @@ status_t NuPlayerDriver::stop() { default: return INVALID_OPERATION; } + mPauseStartedTimeUs = ALooper::GetNowUs(); return OK; } @@ -299,6 +303,7 @@ status_t NuPlayerDriver::pause() { return INVALID_OPERATION; } + mPauseStartedTimeUs = ALooper::GetNowUs(); mState = STATE_PAUSED; return OK; @@ -347,7 +352,10 @@ status_t NuPlayerDriver::getCurrentPosition(int *msec) { if (mPositionUs < 0) { *msec = 0; } else { - *msec = (mPositionUs + 500ll) / 1000; + int64_t nowUs = + (mState != STATE_RUNNING ? + mPauseStartedTimeUs : ALooper::GetNowUs()); + *msec = (mPositionUs + nowUs - mNotifyTimeRealUs + 500ll) / 1000; } return OK; @@ -522,6 +530,7 @@ void NuPlayerDriver::notifyDuration(int64_t durationUs) { void NuPlayerDriver::notifyPosition(int64_t positionUs) { Mutex::Autolock autoLock(mLock); mPositionUs = positionUs; + mNotifyTimeRealUs = ALooper::GetNowUs(); } void NuPlayerDriver::notifySeekComplete() { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index a006d8f..076493d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -104,6 +104,8 @@ private: // >>> int64_t mDurationUs; int64_t mPositionUs; + int64_t mNotifyTimeRealUs; + int64_t mPauseStartedTimeUs; int64_t mNumFramesTotal; int64_t mNumFramesDropped; // <<< -- cgit v1.1 From a31335a4ec96ba351f25f3b26fa79a78c2723a13 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Wed, 20 Aug 2014 17:37:59 -0700 Subject: Fix SoundPool and MediaPlayerService buffer overflow Overflow occurs when SoundPool sample tracks cannot fit in the MediaPlayerService AudioCache buffer. Unnecessary decoding occurred with AwesomePlayer and an assert failure occurred with NuPlayer. NuPlayerRenderer is also tweaked to handle the latter case. Bug: 17122639 Change-Id: I4d25d3e2c0c62e36a91da6bf969edabddc2ebbb0 --- media/libmediaplayerservice/MediaPlayerService.cpp | 31 ++++++++++++++++--- media/libmediaplayerservice/MediaPlayerService.h | 3 +- .../nuplayer/NuPlayerRenderer.cpp | 36 +++++++++++++++++----- 3 files changed, 57 insertions(+), 13 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 2c48306..b5bd988 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1798,7 +1798,9 @@ ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size) //ALOGV("write(%p, %u)", buffer, size); if (mTrack != 0) { ssize_t ret = mTrack->write(buffer, size); - mBytesWritten += ret; + if (ret >= 0) { + mBytesWritten += ret; + } return ret; } return NO_INIT; @@ -1945,7 +1947,7 @@ uint32_t MediaPlayerService::AudioOutput::getSampleRate() const #define LOG_TAG "AudioCache" MediaPlayerService::AudioCache::AudioCache(const sp& heap) : mHeap(heap), mChannelCount(0), mFrameCount(1024), mSampleRate(0), mSize(0), - mError(NO_ERROR), mCommandComplete(false) + mFrameSize(1), mError(NO_ERROR), mCommandComplete(false) { } @@ -1962,14 +1964,14 @@ float MediaPlayerService::AudioCache::msecsPerFrame() const status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position) const { if (position == 0) return BAD_VALUE; - *position = mSize; + *position = mSize / mFrameSize; return NO_ERROR; } status_t MediaPlayerService::AudioCache::getFramesWritten(uint32_t *written) const { if (written == 0) return BAD_VALUE; - *written = mSize; + *written = mSize / mFrameSize; return NO_ERROR; } @@ -2031,6 +2033,8 @@ bool CallbackThread::threadLoop() { if (actualSize > 0) { sink->write(mBuffer, actualSize); + // Could return false on sink->write() error or short count. + // Not necessarily appropriate but would work for AudioCache behavior. } return true; @@ -2053,6 +2057,9 @@ status_t MediaPlayerService::AudioCache::open( mChannelCount = (uint16_t)channelCount; mFormat = format; mMsecsPerFrame = 1.e3 / (float) sampleRate; + mFrameSize = audio_is_linear_pcm(mFormat) + ? mChannelCount * audio_bytes_per_sample(mFormat) : 1; + mFrameCount = mHeap->getSize() / mFrameSize; if (cb != NULL) { mCallbackThread = new CallbackThread(this, cb, cookie); @@ -2082,12 +2089,26 @@ ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size) if (p == NULL) return NO_INIT; p += mSize; ALOGV("memcpy(%p, %p, %u)", p, buffer, size); - if (mSize + size > mHeap->getSize()) { + + bool overflow = mSize + size > mHeap->getSize(); + if (overflow) { ALOGE("Heap size overflow! req size: %d, max size: %d", (mSize + size), mHeap->getSize()); size = mHeap->getSize() - mSize; } + size -= size % mFrameSize; // consume only integral amounts of frame size memcpy(p, buffer, size); mSize += size; + + if (overflow) { + // Signal heap filled here (last frame may be truncated). + // After this point, no more data should be written as the + // heap is filled and the AudioCache should be effectively + // immutable with respect to future writes. + // + // It is thus safe for another thread to read the AudioCache. + mCommandComplete = true; + mSignal.signal(); + } return size; } diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 406e3f6..4fe7075 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -194,7 +194,7 @@ class MediaPlayerService : public BnMediaPlayerService virtual ssize_t bufferSize() const { return frameSize() * mFrameCount; } virtual ssize_t frameCount() const { return mFrameCount; } virtual ssize_t channelCount() const { return (ssize_t)mChannelCount; } - virtual ssize_t frameSize() const { return ssize_t(mChannelCount * ((mFormat == AUDIO_FORMAT_PCM_16_BIT)?sizeof(int16_t):sizeof(u_int8_t))); } + virtual ssize_t frameSize() const { return (ssize_t)mFrameSize; } virtual uint32_t latency() const; virtual float msecsPerFrame() const; virtual status_t getPosition(uint32_t *position) const; @@ -244,6 +244,7 @@ class MediaPlayerService : public BnMediaPlayerService ssize_t mFrameCount; uint32_t mSampleRate; uint32_t mSize; + size_t mFrameSize; int mError; bool mCommandComplete; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 3777f64..35cca1c 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -444,11 +444,13 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { copy = numBytesAvailableToWrite; } - CHECK_EQ(mAudioSink->write( - entry->mBuffer->data() + entry->mOffset, copy), - (ssize_t)copy); + ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset, copy); + if (written < 0) { + // An error in AudioSink write is fatal here. + LOG_ALWAYS_FATAL("AudioSink write error(%zd) when writing %zu bytes", written, copy); + } - entry->mOffset += copy; + entry->mOffset += written; if (entry->mOffset == entry->mBuffer->size()) { entry->mNotifyConsumed->post(); mAudioQueue.erase(mAudioQueue.begin()); @@ -456,13 +458,33 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { entry = NULL; } - numBytesAvailableToWrite -= copy; - size_t copiedFrames = copy / mAudioSink->frameSize(); + numBytesAvailableToWrite -= written; + size_t copiedFrames = written / mAudioSink->frameSize(); mNumFramesWritten += copiedFrames; notifyIfMediaRenderingStarted(); - } + if (written != (ssize_t)copy) { + // A short count was received from AudioSink::write() + // + // AudioSink write should block until exactly the number of bytes are delivered. + // But it may return with a short count (without an error) when: + // + // 1) Size to be copied is not a multiple of the frame size. We consider this fatal. + // 2) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded. + + // (Case 1) + // Must be a multiple of the frame size. If it is not a multiple of a frame size, it + // needs to fail, as we should not carry over fractional frames between calls. + CHECK_EQ(copy % mAudioSink->frameSize(), 0); + + // (Case 2) + // Return early to the caller. + // Beware of calling immediately again as this may busy-loop if you are not careful. + ALOGW("AudioSink write short frame count %zd < %zu", written, copy); + break; + } + } notifyPosition(); return !mAudioQueue.empty(); -- cgit v1.1 From d354d8d1b09503c0166c1f3e626cda72a3eeb83c Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 20 Aug 2014 13:09:58 -0700 Subject: move cache prefill to GenericSource's message handler This allows prepareAsync to be terminated by reset promptly. It also makes it easier to do buffer update as GenericSource can access the cache status now. Bug: 16892748 Bug: 17182378 Change-Id: Ia55c04a810fd805041cb2025f6739afa5120b5ed --- .../nuplayer/GenericSource.cpp | 147 +++++++++++++++++---- .../libmediaplayerservice/nuplayer/GenericSource.h | 16 ++- media/libstagefright/DataSource.cpp | 77 +---------- 3 files changed, 142 insertions(+), 98 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 76e1d54..3706117 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -32,6 +32,7 @@ #include #include #include +#include "../../libstagefright/include/NuCachedSource2.h" #include "../../libstagefright/include/WVMExtractor.h" namespace android { @@ -47,7 +48,8 @@ NuPlayer::GenericSource::GenericSource( mAudioIsVorbis(false), mIsWidevine(false), mUIDValid(uidValid), - mUID(uid) { + mUID(uid), + mMetaDataSize(-1ll) { resetDataSource(); DataSource::RegisterDefaultSniffers(); } @@ -92,18 +94,18 @@ status_t NuPlayer::GenericSource::setDataSource( return OK; } -status_t NuPlayer::GenericSource::initFromDataSource( - const sp &dataSource, - const char* mime) { +status_t NuPlayer::GenericSource::initFromDataSource() { sp extractor; + CHECK(mDataSource != NULL); + if (mIsWidevine) { String8 mimeType; float confidence; sp dummy; bool success; - success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); + success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy); if (!success || strcasecmp( mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { @@ -111,14 +113,15 @@ status_t NuPlayer::GenericSource::initFromDataSource( return UNKNOWN_ERROR; } - sp wvmExtractor = new WVMExtractor(dataSource); + sp wvmExtractor = new WVMExtractor(mDataSource); wvmExtractor->setAdaptiveStreamingMode(true); if (mUIDValid) { wvmExtractor->setUID(mUID); } extractor = wvmExtractor; } else { - extractor = MediaExtractor::Create(dataSource, mime); + extractor = MediaExtractor::Create(mDataSource, + mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str()); } if (extractor == NULL) { @@ -213,34 +216,49 @@ void NuPlayer::GenericSource::prepareAsync() { void NuPlayer::GenericSource::onPrepareAsync() { // delayed data source creation - AString sniffedMIME; - sp dataSource; + if (mDataSource == NULL) { + if (!mUri.empty()) { + mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11); - if (!mUri.empty()) { - mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11); + mDataSource = DataSource::CreateFromURI( + mHTTPService, mUri.c_str(), &mUriHeaders, &mContentType); + } else { + // set to false first, if the extractor + // comes back as secure, set it to true then. + mIsWidevine = false; - dataSource = DataSource::CreateFromURI( - mHTTPService, mUri.c_str(), &mUriHeaders, &sniffedMIME); - } else { - // set to false first, if the extractor - // comes back as secure, set it to true then. - mIsWidevine = false; + mDataSource = new FileSource(mFd, mOffset, mLength); + } + + if (mDataSource == NULL) { + ALOGE("Failed to create data source!"); + notifyPreparedAndCleanup(UNKNOWN_ERROR); + return; + } - dataSource = new FileSource(mFd, mOffset, mLength); + if (mDataSource->flags() & DataSource::kIsCachingDataSource) { + mCachedSource = static_cast(mDataSource.get()); + } } - if (dataSource == NULL) { - ALOGE("Failed to create data source!"); - notifyPrepared(UNKNOWN_ERROR); + // check initial caching status + status_t err = prefillCacheIfNecessary(); + if (err != OK) { + if (err == -EAGAIN) { + (new AMessage(kWhatPrepareAsync, id()))->post(200000); + } else { + ALOGE("Failed to prefill data cache!"); + notifyPreparedAndCleanup(UNKNOWN_ERROR); + } return; } - status_t err = initFromDataSource( - dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); + // init extrator from data source + err = initFromDataSource(); if (err != OK) { ALOGE("Failed to init from data source!"); - notifyPrepared(err); + notifyPreparedAndCleanup(err); return; } @@ -258,6 +276,87 @@ void NuPlayer::GenericSource::onPrepareAsync() { notifyPrepared(); } +void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { + if (err != OK) { + mMetaDataSize = -1ll; + mContentType = ""; + mSniffedMIME = ""; + mDataSource.clear(); + mCachedSource.clear(); + } + notifyPrepared(err); +} + +status_t NuPlayer::GenericSource::prefillCacheIfNecessary() { + CHECK(mDataSource != NULL); + + if (mCachedSource == NULL) { + // no prefill if the data source is not cached + return OK; + } + + // We're not doing this for streams that appear to be audio-only + // streams to ensure that even low bandwidth streams start + // playing back fairly instantly. + if (!strncasecmp(mContentType.string(), "audio/", 6)) { + return OK; + } + + // We're going to prefill the cache before trying to instantiate + // the extractor below, as the latter is an operation that otherwise + // could block on the datasource for a significant amount of time. + // During that time we'd be unable to abort the preparation phase + // without this prefill. + + // Initially make sure we have at least 192 KB for the sniff + // to complete without blocking. + static const size_t kMinBytesForSniffing = 192 * 1024; + static const size_t kDefaultMetaSize = 200000; + + status_t finalStatus; + + size_t cachedDataRemaining = + mCachedSource->approxDataRemaining(&finalStatus); + + if (finalStatus != OK || (mMetaDataSize >= 0 + && (off64_t)cachedDataRemaining >= mMetaDataSize)) { + ALOGV("stop caching, status %d, " + "metaDataSize %lld, cachedDataRemaining %zu", + finalStatus, mMetaDataSize, cachedDataRemaining); + return OK; + } + + ALOGV("now cached %zu bytes of data", cachedDataRemaining); + + if (mMetaDataSize < 0 + && cachedDataRemaining >= kMinBytesForSniffing) { + String8 tmp; + float confidence; + sp meta; + if (!mCachedSource->sniff(&tmp, &confidence, &meta)) { + return UNKNOWN_ERROR; + } + + // We successfully identified the file's extractor to + // be, remember this mime type so we don't have to + // sniff it again when we call MediaExtractor::Create() + mSniffedMIME = tmp.string(); + + if (meta == NULL + || !meta->findInt64("meta-data-size", + reinterpret_cast(&mMetaDataSize))) { + mMetaDataSize = kDefaultMetaSize; + } + + if (mMetaDataSize < 0ll) { + ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize); + return UNKNOWN_ERROR; + } + } + + return -EAGAIN; +} + void NuPlayer::GenericSource::start() { ALOGI("start"); diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index d3081de..946307c 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -33,6 +33,7 @@ struct DataSource; struct IMediaHTTPService; struct MediaSource; class MediaBuffer; +struct NuCachedSource2; struct NuPlayer::GenericSource : public NuPlayer::Source { GenericSource(const sp ¬ify, bool uidValid, uid_t uid); @@ -105,14 +106,21 @@ private: int64_t mOffset; int64_t mLength; - sp mLooper; + sp mDataSource; + sp mCachedSource; + String8 mContentType; + AString mSniffedMIME; + off64_t mMetaDataSize; + sp mLooper; void resetDataSource(); - status_t initFromDataSource( - const sp &dataSource, - const char *mime); + status_t initFromDataSource(); + + status_t prefillCacheIfNecessary(); + + void notifyPreparedAndCleanup(status_t err); void onPrepareAsync(); diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 008da5a..9d6fd78 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -186,9 +186,9 @@ sp DataSource::CreateFromURI( const sp &httpService, const char *uri, const KeyedVector *headers, - AString *sniffedMIME) { - if (sniffedMIME != NULL) { - *sniffedMIME = ""; + String8 *contentType) { + if (contentType != NULL) { + *contentType = ""; } bool isWidevine = !strncasecmp("widevine://", uri, 11); @@ -226,77 +226,14 @@ sp DataSource::CreateFromURI( } if (!isWidevine) { - String8 contentType = httpSource->getMIMEType(); + if (contentType != NULL) { + *contentType = httpSource->getMIMEType(); + } - sp cachedSource = new NuCachedSource2( + source = new NuCachedSource2( httpSource, cacheConfig.isEmpty() ? NULL : cacheConfig.string(), disconnectAtHighwatermark); - - if (strncasecmp(contentType.string(), "audio/", 6)) { - // We're not doing this for streams that appear to be audio-only - // streams to ensure that even low bandwidth streams start - // playing back fairly instantly. - - // We're going to prefill the cache before trying to instantiate - // the extractor below, as the latter is an operation that otherwise - // could block on the datasource for a significant amount of time. - // During that time we'd be unable to abort the preparation phase - // without this prefill. - - // Initially make sure we have at least 192 KB for the sniff - // to complete without blocking. - static const size_t kMinBytesForSniffing = 192 * 1024; - - off64_t metaDataSize = -1ll; - for (;;) { - status_t finalStatus; - size_t cachedDataRemaining = - cachedSource->approxDataRemaining(&finalStatus); - - if (finalStatus != OK || (metaDataSize >= 0 - && (off64_t)cachedDataRemaining >= metaDataSize)) { - ALOGV("stop caching, status %d, " - "metaDataSize %lld, cachedDataRemaining %zu", - finalStatus, metaDataSize, cachedDataRemaining); - break; - } - - ALOGV("now cached %zu bytes of data", cachedDataRemaining); - - if (metaDataSize < 0 - && cachedDataRemaining >= kMinBytesForSniffing) { - String8 tmp; - float confidence; - sp meta; - if (!cachedSource->sniff(&tmp, &confidence, &meta)) { - return NULL; - } - - // We successfully identified the file's extractor to - // be, remember this mime type so we don't have to - // sniff it again when we call MediaExtractor::Create() - if (sniffedMIME != NULL) { - *sniffedMIME = tmp.string(); - } - - if (meta == NULL - || !meta->findInt64("meta-data-size", - reinterpret_cast(&metaDataSize))) { - metaDataSize = kDefaultMetaSize; - } - - if (metaDataSize < 0ll) { - ALOGE("invalid metaDataSize = %lld bytes", metaDataSize); - return NULL; - } - } - - usleep(200000); - } - } - - source = cachedSource; } else { // We do not want that prefetching, caching, datasource wrapper // in the widevine:// case. -- cgit v1.1 From 143a951f1f19161fa12ca97f3dee85094078365a Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 20 Aug 2014 18:17:03 -0700 Subject: SoftAAC2: allow reconfiguring output after multiple output buffers Bug: 17134697 Change-Id: Iaa8bdccbf1a8ccd3f898e48cfd22a0a443710fdd --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 09c6e69..b032f9c 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -720,16 +720,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { * Thus, we could not say for sure whether a stream is * AAC+/eAAC+ until the first data frame is decoded. */ - if (mOutputBufferCount > 1) { - if (mStreamInfo->sampleRate != prevSampleRate || - mStreamInfo->numChannels != prevNumChannels) { - ALOGE("can not reconfigure AAC output"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - return; - } - } - if (mInputBufferCount <= 2) { // TODO: <= 1 + if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1 if (mStreamInfo->sampleRate != prevSampleRate || mStreamInfo->numChannels != prevNumChannels) { ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", -- cgit v1.1 From 5f42113f21c31802e044f0a73351eef35e32feaf Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 21 Aug 2014 19:19:08 -0700 Subject: stagefright: allow to resubmit CSDs for SoftAAC2 Bug: 17118001 Change-Id: I45469b9aa6146edf3265b0f05f5ce3592b5daca6 --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 409 ++++++++++++------------ 1 file changed, 201 insertions(+), 208 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index b032f9c..90df607 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -493,6 +493,7 @@ int32_t SoftAAC2::outputDelayRingBufferSamplesLeft() { return mOutputDelayRingBufferSize - outputDelayRingBufferSamplesAvailable(); } + void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { if (mSignalledError || mOutputPortSettingsChange != NONE) { return; @@ -505,59 +506,55 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { List &inQueue = getPortQueue(0); List &outQueue = getPortQueue(1); - if (portIndex == 0 && mInputBufferCount == 0) { - BufferInfo *inInfo = *inQueue.begin(); - OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; + while ((!inQueue.empty() || mEndOfInput) && !outQueue.empty()) { + if (!inQueue.empty()) { + INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT]; + BufferInfo *inInfo = *inQueue.begin(); + OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; - inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; - inBufferLength[0] = inHeader->nFilledLen; + mEndOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0; + if (portIndex == 0 && + (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) { + BufferInfo *inInfo = *inQueue.begin(); + OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; - AAC_DECODER_ERROR decoderErr = - aacDecoder_ConfigRaw(mAACDecoder, - inBuffer, - inBufferLength); + inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; + inBufferLength[0] = inHeader->nFilledLen; - if (decoderErr != AAC_DEC_OK) { - ALOGW("aacDecoder_ConfigRaw decoderErr = 0x%4.4x", decoderErr); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - return; - } + AAC_DECODER_ERROR decoderErr = + aacDecoder_ConfigRaw(mAACDecoder, + inBuffer, + inBufferLength); - mInputBufferCount++; - mOutputBufferCount++; // fake increase of outputBufferCount to keep the counters aligned - - inInfo->mOwnedByUs = false; - inQueue.erase(inQueue.begin()); - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; - - configureDownmix(); - // Only send out port settings changed event if both sample rate - // and numChannels are valid. - if (mStreamInfo->sampleRate && mStreamInfo->numChannels) { - ALOGI("Initially configuring decoder: %d Hz, %d channels", - mStreamInfo->sampleRate, - mStreamInfo->numChannels); - - notify(OMX_EventPortSettingsChanged, 1, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; - } + if (decoderErr != AAC_DEC_OK) { + ALOGW("aacDecoder_ConfigRaw decoderErr = 0x%4.4x", decoderErr); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; + } - return; - } + mInputBufferCount++; + mOutputBufferCount++; // fake increase of outputBufferCount to keep the counters aligned - while ((!inQueue.empty() || mEndOfInput) && !outQueue.empty()) { - if (!inQueue.empty()) { - INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT]; - BufferInfo *inInfo = *inQueue.begin(); - OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; + inInfo->mOwnedByUs = false; + inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; - if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { - mEndOfInput = true; - } else { - mEndOfInput = false; + configureDownmix(); + // Only send out port settings changed event if both sample rate + // and numChannels are valid. + if (mStreamInfo->sampleRate && mStreamInfo->numChannels) { + ALOGI("Initially configuring decoder: %d Hz, %d channels", + mStreamInfo->sampleRate, + mStreamInfo->numChannels); + + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + } + return; } if (inHeader->nFilledLen == 0) { @@ -567,197 +564,193 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; - } else { - if (mIsADTS) { - size_t adtsHeaderSize = 0; - // skip 30 bits, aac_frame_length follows. - // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? + continue; + } - const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset; + if (mIsADTS) { + size_t adtsHeaderSize = 0; + // skip 30 bits, aac_frame_length follows. + // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? - bool signalError = false; - if (inHeader->nFilledLen < 7) { - ALOGE("Audio data too short to contain even the ADTS header. " - "Got %d bytes.", inHeader->nFilledLen); + const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset; + + bool signalError = false; + if (inHeader->nFilledLen < 7) { + ALOGE("Audio data too short to contain even the ADTS header. " + "Got %d bytes.", inHeader->nFilledLen); + hexdump(adtsHeader, inHeader->nFilledLen); + signalError = true; + } else { + bool protectionAbsent = (adtsHeader[1] & 1); + + unsigned aac_frame_length = + ((adtsHeader[3] & 3) << 11) + | (adtsHeader[4] << 3) + | (adtsHeader[5] >> 5); + + if (inHeader->nFilledLen < aac_frame_length) { + ALOGE("Not enough audio data for the complete frame. " + "Got %d bytes, frame size according to the ADTS " + "header is %u bytes.", + inHeader->nFilledLen, aac_frame_length); hexdump(adtsHeader, inHeader->nFilledLen); signalError = true; } else { - bool protectionAbsent = (adtsHeader[1] & 1); - - unsigned aac_frame_length = - ((adtsHeader[3] & 3) << 11) - | (adtsHeader[4] << 3) - | (adtsHeader[5] >> 5); - - if (inHeader->nFilledLen < aac_frame_length) { - ALOGE("Not enough audio data for the complete frame. " - "Got %d bytes, frame size according to the ADTS " - "header is %u bytes.", - inHeader->nFilledLen, aac_frame_length); - hexdump(adtsHeader, inHeader->nFilledLen); - signalError = true; - } else { - adtsHeaderSize = (protectionAbsent ? 7 : 9); - - inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize; - inBufferLength[0] = aac_frame_length - adtsHeaderSize; - - inHeader->nOffset += adtsHeaderSize; - inHeader->nFilledLen -= adtsHeaderSize; - } - } + adtsHeaderSize = (protectionAbsent ? 7 : 9); - if (signalError) { - mSignalledError = true; + inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize; + inBufferLength[0] = aac_frame_length - adtsHeaderSize; - notify(OMX_EventError, - OMX_ErrorStreamCorrupt, - ERROR_MALFORMED, - NULL); - - return; + inHeader->nOffset += adtsHeaderSize; + inHeader->nFilledLen -= adtsHeaderSize; } - } else { - inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; - inBufferLength[0] = inHeader->nFilledLen; } - // Fill and decode - bytesValid[0] = inBufferLength[0]; - - INT prevSampleRate = mStreamInfo->sampleRate; - INT prevNumChannels = mStreamInfo->numChannels; - - if (inHeader != mLastInHeader) { - mLastInHeader = inHeader; - mCurrentInputTime = inHeader->nTimeStamp; - } else { - if (mStreamInfo->sampleRate) { - mCurrentInputTime += mStreamInfo->aacSamplesPerFrame * - 1000000ll / mStreamInfo->sampleRate; - } else { - ALOGW("no sample rate yet"); - } - } - mAnchorTimes.add(mCurrentInputTime); - aacDecoder_Fill(mAACDecoder, - inBuffer, - inBufferLength, - bytesValid); - - // run DRC check - mDrcWrap.submitStreamData(mStreamInfo); - mDrcWrap.update(); - - AAC_DECODER_ERROR decoderErr = - aacDecoder_DecodeFrame(mAACDecoder, - tmpOutBuffer, - 2048 * MAX_CHANNEL_COUNT, - 0 /* flags */); - - if (decoderErr != AAC_DEC_OK) { - ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); - } - - if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { - ALOGE("AAC_DEC_NOT_ENOUGH_BITS should never happen"); + if (signalError) { mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL); return; } + } else { + inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; + inBufferLength[0] = inHeader->nFilledLen; + } - if (bytesValid[0] != 0) { - ALOGE("bytesValid[0] != 0 should never happen"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); - return; - } + // Fill and decode + bytesValid[0] = inBufferLength[0]; - size_t numOutBytes = - mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; + INT prevSampleRate = mStreamInfo->sampleRate; + INT prevNumChannels = mStreamInfo->numChannels; - if (decoderErr == AAC_DEC_OK) { - if (!outputDelayRingBufferPutSamples(tmpOutBuffer, - mStreamInfo->frameSize * mStreamInfo->numChannels)) { - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - return; - } - UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; - inHeader->nFilledLen -= inBufferUsedLength; - inHeader->nOffset += inBufferUsedLength; + if (inHeader != mLastInHeader) { + mLastInHeader = inHeader; + mCurrentInputTime = inHeader->nTimeStamp; + } else { + if (mStreamInfo->sampleRate) { + mCurrentInputTime += mStreamInfo->aacSamplesPerFrame * + 1000000ll / mStreamInfo->sampleRate; } else { - ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr); + ALOGW("no sample rate yet"); + } + } + mAnchorTimes.add(mCurrentInputTime); + aacDecoder_Fill(mAACDecoder, + inBuffer, + inBufferLength, + bytesValid); - memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow + // run DRC check + mDrcWrap.submitStreamData(mStreamInfo); + mDrcWrap.update(); - if (!outputDelayRingBufferPutSamples(tmpOutBuffer, - mStreamInfo->frameSize * mStreamInfo->numChannels)) { - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - return; - } + AAC_DECODER_ERROR decoderErr = + aacDecoder_DecodeFrame(mAACDecoder, + tmpOutBuffer, + 2048 * MAX_CHANNEL_COUNT, + 0 /* flags */); + + if (decoderErr != AAC_DEC_OK) { + ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); + } + + if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { + ALOGE("AAC_DEC_NOT_ENOUGH_BITS should never happen"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } - // Discard input buffer. - inHeader->nFilledLen = 0; + if (bytesValid[0] != 0) { + ALOGE("bytesValid[0] != 0 should never happen"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } - aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); + size_t numOutBytes = + mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; - // fall through + if (decoderErr == AAC_DEC_OK) { + if (!outputDelayRingBufferPutSamples(tmpOutBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels)) { + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; } + UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; + inHeader->nFilledLen -= inBufferUsedLength; + inHeader->nOffset += inBufferUsedLength; + } else { + ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr); - /* - * AAC+/eAAC+ streams can be signalled in two ways: either explicitly - * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual - * rate system and the sampling rate in the final output is actually - * doubled compared with the core AAC decoder sampling rate. - * - * Explicit signalling is done by explicitly defining SBR audio object - * type in the bitstream. Implicit signalling is done by embedding - * SBR content in AAC extension payload specific to SBR, and hence - * requires an AAC decoder to perform pre-checks on actual audio frames. - * - * Thus, we could not say for sure whether a stream is - * AAC+/eAAC+ until the first data frame is decoded. - */ - if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1 - if (mStreamInfo->sampleRate != prevSampleRate || - mStreamInfo->numChannels != prevNumChannels) { - ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", - prevSampleRate, mStreamInfo->sampleRate, - prevNumChannels, mStreamInfo->numChannels); - - notify(OMX_EventPortSettingsChanged, 1, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; - - if (inHeader->nFilledLen == 0) { - inInfo->mOwnedByUs = false; - mInputBufferCount++; - inQueue.erase(inQueue.begin()); - mLastInHeader = NULL; - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; - } - return; - } - } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { - ALOGW("Invalid AAC stream"); + memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow + + if (!outputDelayRingBufferPutSamples(tmpOutBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels)) { mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); return; } - if (inHeader->nFilledLen == 0) { - inInfo->mOwnedByUs = false; - mInputBufferCount++; - inQueue.erase(inQueue.begin()); - mLastInHeader = NULL; - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; - } else { - ALOGV("inHeader->nFilledLen = %d", inHeader->nFilledLen); + + // Discard input buffer. + inHeader->nFilledLen = 0; + + aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); + + // fall through + } + + /* + * AAC+/eAAC+ streams can be signalled in two ways: either explicitly + * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual + * rate system and the sampling rate in the final output is actually + * doubled compared with the core AAC decoder sampling rate. + * + * Explicit signalling is done by explicitly defining SBR audio object + * type in the bitstream. Implicit signalling is done by embedding + * SBR content in AAC extension payload specific to SBR, and hence + * requires an AAC decoder to perform pre-checks on actual audio frames. + * + * Thus, we could not say for sure whether a stream is + * AAC+/eAAC+ until the first data frame is decoded. + */ + if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1 + if (mStreamInfo->sampleRate != prevSampleRate || + mStreamInfo->numChannels != prevNumChannels) { + ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", + prevSampleRate, mStreamInfo->sampleRate, + prevNumChannels, mStreamInfo->numChannels); + + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + mInputBufferCount++; + inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } + return; } + } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { + ALOGW("Invalid AAC stream"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; + } + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + mInputBufferCount++; + inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } else { + ALOGV("inHeader->nFilledLen = %d", inHeader->nFilledLen); } } -- cgit v1.1 From 0560195a71ee26e8546075e56c49ff535fcf1767 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 20 Aug 2014 18:21:11 -0700 Subject: NuPlayerDriver: fix current position for stop and pause. When start() is called after EOS, it means restarting from the beginning of the stream. Fix racing conditon on accessing some members. Report seekTo position before any notifyPosition is called. Bug: 17031731 Bug: 17178928 Change-Id: I008b827288cf28d39e2a943373fe1e5d7d6c2595 --- .../nuplayer/NuPlayerDriver.cpp | 59 +++++++++++++++------- .../nuplayer/NuPlayerDriver.h | 2 + 2 files changed, 44 insertions(+), 17 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index c0091bf..60beb9d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -36,8 +36,8 @@ NuPlayerDriver::NuPlayerDriver() mAsyncResult(UNKNOWN_ERROR), mDurationUs(-1), mPositionUs(-1), - mNotifyTimeRealUs(0), - mPauseStartedTimeUs(0), + mNotifyTimeRealUs(-1), + mPauseStartedTimeUs(-1), mNumFramesTotal(0), mNumFramesDropped(0), mLooper(new ALooper), @@ -240,7 +240,14 @@ status_t NuPlayerDriver::start() { } case STATE_RUNNING: + { + if (mAtEOS) { + mPlayer->seekToAsync(0); + mAtEOS = false; + mPositionUs = -1; + } break; + } case STATE_PAUSED: case STATE_STOPPED_AND_PREPARED: @@ -255,6 +262,7 @@ status_t NuPlayerDriver::start() { } mState = STATE_RUNNING; + mPauseStartedTimeUs = -1; return OK; } @@ -268,7 +276,7 @@ status_t NuPlayerDriver::stop() { // fall through case STATE_PAUSED: - notifyListener(MEDIA_STOPPED); + notifyListener_l(MEDIA_STOPPED); // fall through case STATE_PREPARED: @@ -281,7 +289,7 @@ status_t NuPlayerDriver::stop() { default: return INVALID_OPERATION; } - mPauseStartedTimeUs = ALooper::GetNowUs(); + setPauseStartedTimeIfNeeded(); return OK; } @@ -295,7 +303,7 @@ status_t NuPlayerDriver::pause() { return OK; case STATE_RUNNING: - notifyListener(MEDIA_PAUSED); + notifyListener_l(MEDIA_PAUSED); mPlayer->pause(); break; @@ -303,7 +311,7 @@ status_t NuPlayerDriver::pause() { return INVALID_OPERATION; } - mPauseStartedTimeUs = ALooper::GetNowUs(); + setPauseStartedTimeIfNeeded(); mState = STATE_PAUSED; return OK; @@ -334,7 +342,7 @@ status_t NuPlayerDriver::seekTo(int msec) { { mAtEOS = false; // seeks can take a while, so we essentially paused - notifyListener(MEDIA_PAUSED); + notifyListener_l(MEDIA_PAUSED); mPlayer->seekToAsync(seekTimeUs); break; } @@ -343,6 +351,8 @@ status_t NuPlayerDriver::seekTo(int msec) { return INVALID_OPERATION; } + mPositionUs = seekTimeUs; + mNotifyTimeRealUs = -1; return OK; } @@ -351,10 +361,11 @@ status_t NuPlayerDriver::getCurrentPosition(int *msec) { if (mPositionUs < 0) { *msec = 0; + } else if (mNotifyTimeRealUs == -1) { + *msec = mPositionUs / 1000; } else { int64_t nowUs = - (mState != STATE_RUNNING ? - mPauseStartedTimeUs : ALooper::GetNowUs()); + (isPlaying() ? ALooper::GetNowUs() : mPauseStartedTimeUs); *msec = (mPositionUs + nowUs - mNotifyTimeRealUs + 500ll) / 1000; } @@ -388,7 +399,7 @@ status_t NuPlayerDriver::reset() { { CHECK(mIsAsyncPrepare); - notifyListener(MEDIA_PREPARED); + notifyListener_l(MEDIA_PREPARED); break; } @@ -397,7 +408,7 @@ status_t NuPlayerDriver::reset() { } if (mState != STATE_STOPPED) { - notifyListener(MEDIA_STOPPED); + notifyListener_l(MEDIA_STOPPED); } mState = STATE_RESET_IN_PROGRESS; @@ -552,10 +563,7 @@ void NuPlayerDriver::notifySeekComplete_l() { // no need to notify listener return; } - // note: notifyListener called with lock released - mLock.unlock(); - notifyListener(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED); - mLock.lock(); + notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED); } void NuPlayerDriver::notifyFrameStats( @@ -587,11 +595,19 @@ status_t NuPlayerDriver::dump( void NuPlayerDriver::notifyListener( int msg, int ext1, int ext2, const Parcel *in) { + Mutex::Autolock autoLock(mLock); + notifyListener_l(msg, ext1, ext2, in); +} + +void NuPlayerDriver::notifyListener_l( + int msg, int ext1, int ext2, const Parcel *in) { switch (msg) { case MEDIA_PLAYBACK_COMPLETE: { if (mLooping) { + mLock.unlock(); mPlayer->seekToAsync(0); + mLock.lock(); break; } // fall through @@ -600,6 +616,7 @@ void NuPlayerDriver::notifyListener( case MEDIA_ERROR: { mAtEOS = true; + setPauseStartedTimeIfNeeded(); break; } @@ -607,7 +624,9 @@ void NuPlayerDriver::notifyListener( break; } + mLock.unlock(); sendEvent(msg, ext1, ext2, in); + mLock.lock(); } void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) { @@ -637,12 +656,12 @@ void NuPlayerDriver::notifyPrepareCompleted(status_t err) { if (err == OK) { if (mIsAsyncPrepare) { - notifyListener(MEDIA_PREPARED); + notifyListener_l(MEDIA_PREPARED); } mState = STATE_PREPARED; } else { if (mIsAsyncPrepare) { - notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); + notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); } mState = STATE_UNPREPARED; } @@ -656,4 +675,10 @@ void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) { mPlayerFlags = flags; } +void NuPlayerDriver::setPauseStartedTimeIfNeeded() { + if (mPauseStartedTimeUs == -1) { + mPauseStartedTimeUs = ALooper::GetNowUs(); + } +} + } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index 076493d..b0a52ad 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -120,6 +120,8 @@ private: int64_t mStartupSeekTimeUs; status_t prepare_l(); + void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL); + void setPauseStartedTimeIfNeeded(); DISALLOW_EVIL_CONSTRUCTORS(NuPlayerDriver); }; -- cgit v1.1 From 2a3cc9a64330dd36e466fe5e1b634146f2d641c1 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 21 Aug 2014 17:48:26 -0700 Subject: add buffering update to GenericSource Bug: 17182378 Change-Id: Ib86f3f522d7ea635489edd2b512adb7f4b27e381 --- .../nuplayer/GenericSource.cpp | 98 ++++++++++++++++++++-- .../libmediaplayerservice/nuplayer/GenericSource.h | 10 +++ media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 9 ++ .../nuplayer/NuPlayerSource.h | 1 + 4 files changed, 112 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 3706117..cdb7e69 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -49,7 +49,9 @@ NuPlayer::GenericSource::GenericSource( mIsWidevine(false), mUIDValid(uidValid), mUID(uid), - mMetaDataSize(-1ll) { + mMetaDataSize(-1ll), + mBitrate(-1ll), + mPollBufferingGeneration(0) { resetDataSource(); DataSource::RegisterDefaultSniffers(); } @@ -113,12 +115,12 @@ status_t NuPlayer::GenericSource::initFromDataSource() { return UNKNOWN_ERROR; } - sp wvmExtractor = new WVMExtractor(mDataSource); - wvmExtractor->setAdaptiveStreamingMode(true); + mWVMExtractor = new WVMExtractor(mDataSource); + mWVMExtractor->setAdaptiveStreamingMode(true); if (mUIDValid) { - wvmExtractor->setUID(mUID); + mWVMExtractor->setUID(mUID); } - extractor = wvmExtractor; + extractor = mWVMExtractor; } else { extractor = MediaExtractor::Create(mDataSource, mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str()); @@ -136,6 +138,8 @@ status_t NuPlayer::GenericSource::initFromDataSource() { } } + int32_t totalBitrate = 0; + for (size_t i = 0; i < extractor->countTracks(); ++i) { sp meta = extractor->getTrackMetaData(i); @@ -180,9 +184,18 @@ status_t NuPlayer::GenericSource::initFromDataSource() { mDurationUs = durationUs; } } + + int32_t bitrate; + if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) { + totalBitrate += bitrate; + } else { + totalBitrate = -1; + } } } + mBitrate = totalBitrate; + return OK; } @@ -239,6 +252,10 @@ void NuPlayer::GenericSource::onPrepareAsync() { if (mDataSource->flags() & DataSource::kIsCachingDataSource) { mCachedSource = static_cast(mDataSource.get()); } + + if (mIsWidevine || mCachedSource != NULL) { + schedulePollBuffering(); + } } // check initial caching status @@ -283,6 +300,8 @@ void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { mSniffedMIME = ""; mDataSource.clear(); mCachedSource.clear(); + + cancelPollBuffering(); } notifyPrepared(err); } @@ -381,6 +400,65 @@ status_t NuPlayer::GenericSource::feedMoreTSData() { return OK; } +void NuPlayer::GenericSource::schedulePollBuffering() { + sp msg = new AMessage(kWhatPollBuffering, id()); + msg->setInt32("generation", mPollBufferingGeneration); + msg->post(1000000ll); +} + +void NuPlayer::GenericSource::cancelPollBuffering() { + ++mPollBufferingGeneration; +} + +void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) { + sp msg = dupNotify(); + msg->setInt32("what", kWhatBufferingUpdate); + msg->setInt32("percentage", percentage); + msg->post(); +} + +void NuPlayer::GenericSource::onPollBuffering() { + status_t finalStatus = UNKNOWN_ERROR; + int64_t cachedDurationUs = 0ll; + + if (mCachedSource != NULL) { + size_t cachedDataRemaining = + mCachedSource->approxDataRemaining(&finalStatus); + + if (finalStatus == OK) { + off64_t size; + int64_t bitrate = 0ll; + if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) { + bitrate = size * 8000000ll / mDurationUs; + } else if (mBitrate > 0) { + bitrate = mBitrate; + } + if (bitrate > 0) { + cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate; + } + } + } else if (mWVMExtractor != NULL) { + cachedDurationUs + = mWVMExtractor->getCachedDurationUs(&finalStatus); + } + + if (finalStatus == ERROR_END_OF_STREAM) { + notifyBufferingUpdate(100); + cancelPollBuffering(); + return; + } else if (cachedDurationUs > 0ll && mDurationUs > 0ll) { + int percentage = 100.0 * cachedDurationUs / mDurationUs; + if (percentage > 100) { + percentage = 100; + } + + notifyBufferingUpdate(percentage); + } + + schedulePollBuffering(); +} + + void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { switch (msg->what()) { case kWhatPrepareAsync: @@ -463,7 +541,15 @@ void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { break; } - + case kWhatPollBuffering: + { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + if (generation == mPollBufferingGeneration) { + onPollBuffering(); + } + break; + } default: Source::onMessageReceived(msg); break; diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 946307c..663bfae 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -34,6 +34,7 @@ struct IMediaHTTPService; struct MediaSource; class MediaBuffer; struct NuCachedSource2; +struct WVMExtractor; struct NuPlayer::GenericSource : public NuPlayer::Source { GenericSource(const sp ¬ify, bool uidValid, uid_t uid); @@ -77,6 +78,7 @@ private: kWhatSendSubtitleData, kWhatSendTimedTextData, kWhatChangeAVSource, + kWhatPollBuffering, }; Vector > mSources; @@ -108,9 +110,12 @@ private: sp mDataSource; sp mCachedSource; + sp mWVMExtractor; String8 mContentType; AString mSniffedMIME; off64_t mMetaDataSize; + int64_t mBitrate; + int32_t mPollBufferingGeneration; sp mLooper; @@ -141,6 +146,11 @@ private: media_track_type trackType, int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL, bool formatChange = false); + void schedulePollBuffering(); + void cancelPollBuffering(); + void onPollBuffering(); + void notifyBufferingUpdate(int percentage); + DISALLOW_EVIL_CONSTRUCTORS(GenericSource); }; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 0a9b65c..60f0b8c 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1797,6 +1797,15 @@ void NuPlayer::onSourceNotify(const sp &msg) { break; } + case Source::kWhatBufferingUpdate: + { + int32_t percentage; + CHECK(msg->findInt32("percentage", &percentage)); + + notifyListener(MEDIA_BUFFERING_UPDATE, percentage, 0); + break; + } + case Source::kWhatBufferingStart: { notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index 74892b6..45657c2 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -45,6 +45,7 @@ struct NuPlayer::Source : public AHandler { kWhatPrepared, kWhatFlagsChanged, kWhatVideoSizeChanged, + kWhatBufferingUpdate, kWhatBufferingStart, kWhatBufferingEnd, kWhatSubtitleData, -- cgit v1.1 From 3fb9f68dea5d991288f0ea8037742b50c7df5767 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 20 Aug 2014 14:30:09 -0700 Subject: ACodec: handle errors related to native window. Bug: 17068327 Bug: 13133027 Change-Id: I9875e524222a10d1be26be5a84b9633b4aaeb210 --- media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 7 +++++-- media/libstagefright/ACodec.cpp | 12 ++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 8fce2f4..37ecbf1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -478,10 +478,13 @@ void NuPlayer::Decoder::onShutdown() { if (mNativeWindow != NULL) { // reconnect to surface as MediaCodec disconnected from it - CHECK_EQ((int)NO_ERROR, + status_t error = native_window_api_connect( mNativeWindow->getNativeWindow().get(), - NATIVE_WINDOW_API_MEDIA)); + NATIVE_WINDOW_API_MEDIA); + ALOGW_IF(error != NO_ERROR, + "[%s] failed to connect to native window, error=%d", + mComponentName.c_str(), error); } mComponentName = "decoder"; } diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index b44d5cc..e4e463a 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -813,7 +813,10 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { for (OMX_U32 i = cancelStart; i < cancelEnd; i++) { BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i); - cancelBufferToNativeWindow(info); + status_t error = cancelBufferToNativeWindow(info); + if (err == 0) { + err = error; + } } return err; @@ -888,11 +891,12 @@ status_t ACodec::cancelBufferToNativeWindow(BufferInfo *info) { int err = mNativeWindow->cancelBuffer( mNativeWindow.get(), info->mGraphicBuffer.get(), -1); - CHECK_EQ(err, 0); + ALOGW_IF(err != 0, "[%s] can not return buffer %u to native window", + mComponentName.c_str(), info->mBufferID); info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW; - return OK; + return err; } ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() { @@ -992,7 +996,7 @@ status_t ACodec::freeBuffer(OMX_U32 portIndex, size_t i) { if (portIndex == kPortIndexOutput && mNativeWindow != NULL && info->mStatus == BufferInfo::OWNED_BY_US) { - CHECK_EQ((status_t)OK, cancelBufferToNativeWindow(info)); + cancelBufferToNativeWindow(info); } CHECK_EQ(mOMX->freeBuffer( -- cgit v1.1 From 13d6faa02087ce3bb0d4a02b8495f1822f211433 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Fri, 22 Aug 2014 15:35:28 -0700 Subject: wait for flush to finish before returning setSurface Bug: 17187598 Change-Id: I091219e57158a4532044ca49342b57277d6ecb15 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 7 +++++++ .../nuplayer/NuPlayerDriver.cpp | 20 ++++++++++++++++++++ .../libmediaplayerservice/nuplayer/NuPlayerDriver.h | 2 ++ 3 files changed, 29 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 0a9b65c..3dbc0a2 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1732,6 +1732,13 @@ void NuPlayer::performSetSurface(const sp &wrapper) { // XXX - ignore error from setVideoScalingMode for now setVideoScalingMode(mVideoScalingMode); + + if (mDriver != NULL) { + sp driver = mDriver.promote(); + if (driver != NULL) { + driver->notifySetSurfaceComplete(); + } + } } void NuPlayer::onSourceNotify(const sp &msg) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 60beb9d..2f60072 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -34,6 +34,7 @@ NuPlayerDriver::NuPlayerDriver() : mState(STATE_IDLE), mIsAsyncPrepare(false), mAsyncResult(UNKNOWN_ERROR), + mSetSurfaceInProgress(false), mDurationUs(-1), mPositionUs(-1), mNotifyTimeRealUs(-1), @@ -136,6 +137,10 @@ status_t NuPlayerDriver::setVideoSurfaceTexture( const sp &bufferProducer) { Mutex::Autolock autoLock(mLock); + if (mSetSurfaceInProgress) { + return INVALID_OPERATION; + } + switch (mState) { case STATE_SET_DATASOURCE_PENDING: case STATE_RESET_IN_PROGRESS: @@ -145,8 +150,14 @@ status_t NuPlayerDriver::setVideoSurfaceTexture( break; } + mSetSurfaceInProgress = true; + mPlayer->setVideoSurfaceTextureAsync(bufferProducer); + while (mSetSurfaceInProgress) { + mCondition.wait(mLock); + } + return OK; } @@ -533,6 +544,15 @@ void NuPlayerDriver::notifyResetComplete() { mCondition.broadcast(); } +void NuPlayerDriver::notifySetSurfaceComplete() { + Mutex::Autolock autoLock(mLock); + + CHECK(mSetSurfaceInProgress); + mSetSurfaceInProgress = false; + + mCondition.broadcast(); +} + void NuPlayerDriver::notifyDuration(int64_t durationUs) { Mutex::Autolock autoLock(mLock); mDurationUs = durationUs; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index b0a52ad..e81d605 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -66,6 +66,7 @@ struct NuPlayerDriver : public MediaPlayerInterface { void notifySetDataSourceCompleted(status_t err); void notifyPrepareCompleted(status_t err); void notifyResetComplete(); + void notifySetSurfaceComplete(); void notifyDuration(int64_t durationUs); void notifyPosition(int64_t positionUs); void notifySeekComplete(); @@ -102,6 +103,7 @@ private: // The following are protected through "mLock" // >>> + bool mSetSurfaceInProgress; int64_t mDurationUs; int64_t mPositionUs; int64_t mNotifyTimeRealUs; -- cgit v1.1 From 5530f7a7f9dff5280be84f2675b3be081beb5540 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 20 Aug 2014 11:49:40 -0700 Subject: MediaCodec: handle errors during flushing. Bug: 17068327 Bug: 13133027 Change-Id: I06caf79b90ebf55d6d7561cb82516c0b6c66f0e4 --- media/libstagefright/MediaCodec.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 814adab..76f730f 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -722,7 +722,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { mFlags |= kFlagSawMediaServerDie; } - bool sendErrorReponse = true; + bool sendErrorResponse = true; switch (mState) { case INITIALIZING: @@ -749,7 +749,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { // Ignore the error, assuming we'll still get // the shutdown complete notification. - sendErrorReponse = false; + sendErrorResponse = false; if (mFlags & kFlagSawMediaServerDie) { // MediaServer died, there definitely won't @@ -780,7 +780,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { case FLUSHED: case STARTED: { - sendErrorReponse = false; + sendErrorResponse = false; setStickyError(err); postActivityNotificationIfPossible(); @@ -805,7 +805,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { default: { - sendErrorReponse = false; + sendErrorResponse = false; setStickyError(err); postActivityNotificationIfPossible(); @@ -831,7 +831,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { } } - if (sendErrorReponse) { + if (sendErrorResponse) { PostReplyWithError(mReplyID, err); } break; @@ -1118,7 +1118,11 @@ void MediaCodec::onMessageReceived(const sp &msg) { case CodecBase::kWhatFlushCompleted: { - CHECK_EQ(mState, FLUSHING); + if (mState != FLUSHING) { + ALOGW("received FlushCompleted message in state %d", + mState); + break; + } if (mFlags & kFlagIsAsync) { setState(FLUSHED); -- cgit v1.1 From 34febc9654ba3b447239b7761ce4c93ca9a20b5f Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 22 Aug 2014 23:58:05 -0700 Subject: stagefright: process CSD regardless of what port was last queued CSD is always on the input port, so it does not matter which port a buffer was last queued to. Bug: 17216852 Change-Id: I6d00eb4bf3c2e9b9cc3c9918229de958bc465693 --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 90df607..8b4dd6f 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -494,7 +494,7 @@ int32_t SoftAAC2::outputDelayRingBufferSamplesLeft() { } -void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { +void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError || mOutputPortSettingsChange != NONE) { return; } @@ -513,8 +513,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; mEndOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0; - if (portIndex == 0 && - (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) { + if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) { BufferInfo *inInfo = *inQueue.begin(); OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; -- cgit v1.1 From 87603c0dd1f4e62e52feffa8d6e960ad21f68893 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 20 Aug 2014 19:25:30 -0700 Subject: NuPlayer: remember and resubmit CSDs after flush Bug: 17118001 Change-Id: I09bbefd4c05de0db1c593e8d6d38859358a20ebb --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 65 +++++++++++++++++----- media/libmediaplayerservice/nuplayer/NuPlayer.h | 9 ++- .../nuplayer/NuPlayerDecoder.cpp | 57 +++++++++++++++++-- .../nuplayer/NuPlayerDecoder.h | 7 ++- 4 files changed, 117 insertions(+), 21 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index b79a5dd..f4cd02c 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -756,7 +756,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { ALOGV("initiating %s decoder shutdown", audio ? "audio" : "video"); - (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown(); + getDecoder(audio)->initiateShutdown(); if (audio) { mFlushingAudio = SHUTTING_DOWN_DECODER; @@ -1292,7 +1292,24 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { mTimeDiscontinuityPending = mTimeDiscontinuityPending || timeChange; - if (mFlushingAudio == NONE && mFlushingVideo == NONE) { + bool seamlessFormatChange = false; + sp newFormat = mSource->getFormat(audio); + if (formatChange) { + seamlessFormatChange = + getDecoder(audio)->supportsSeamlessFormatChange(newFormat); + // treat seamless format change separately + formatChange = !seamlessFormatChange; + } + bool shutdownOrFlush = formatChange || timeChange; + + // We want to queue up scan-sources only once per discontinuity. + // We control this by doing it only if neither audio nor video are + // flushing or shutting down. (After handling 1st discontinuity, one + // of the flushing states will not be NONE.) + // No need to scan sources if this discontinuity does not result + // in a flush or shutdown, as the flushing state will stay NONE. + if (mFlushingAudio == NONE && mFlushingVideo == NONE && + shutdownOrFlush) { // And we'll resume scanning sources once we're done // flushing. mDeferredActions.push_front( @@ -1300,16 +1317,17 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { &NuPlayer::performScanSources)); } - if (formatChange || timeChange) { - - sp newFormat = mSource->getFormat(audio); - sp &decoder = audio ? mAudioDecoder : mVideoDecoder; - if (formatChange && !decoder->supportsSeamlessFormatChange(newFormat)) { - flushDecoder(audio, /* needShutdown = */ true); - } else { - flushDecoder(audio, /* needShutdown = */ false); - err = OK; - } + if (formatChange /* not seamless */) { + // must change decoder + flushDecoder(audio, /* needShutdown = */ true); + } else if (timeChange) { + // need to flush + flushDecoder(audio, /* needShutdown = */ false, newFormat); + err = OK; + } else if (seamlessFormatChange) { + // reuse existing decoder and don't flush + updateDecoderFormatWithoutFlush(audio, newFormat); + err = OK; } else { // This stream is unaffected by the discontinuity return -EWOULDBLOCK; @@ -1488,20 +1506,23 @@ void NuPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *in) { driver->notifyListener(msg, ext1, ext2, in); } -void NuPlayer::flushDecoder(bool audio, bool needShutdown) { +void NuPlayer::flushDecoder( + bool audio, bool needShutdown, const sp &newFormat) { ALOGV("[%s] flushDecoder needShutdown=%d", audio ? "audio" : "video", needShutdown); - if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) { + const sp &decoder = getDecoder(audio); + if (decoder == NULL) { ALOGI("flushDecoder %s without decoder present", audio ? "audio" : "video"); + return; } // Make sure we don't continue to scan sources until we finish flushing. ++mScanSourcesGeneration; mScanSourcesPending = false; - (audio ? mAudioDecoder : mVideoDecoder)->signalFlush(); + decoder->signalFlush(newFormat); mRenderer->flush(audio); FlushStatus newStatus = @@ -1518,6 +1539,20 @@ void NuPlayer::flushDecoder(bool audio, bool needShutdown) { } } +void NuPlayer::updateDecoderFormatWithoutFlush( + bool audio, const sp &format) { + ALOGV("[%s] updateDecoderFormatWithoutFlush", audio ? "audio" : "video"); + + const sp &decoder = getDecoder(audio); + if (decoder == NULL) { + ALOGI("updateDecoderFormatWithoutFlush %s without decoder present", + audio ? "audio" : "video"); + return; + } + + decoder->signalUpdateFormat(format); +} + void NuPlayer::queueDecoderShutdown( bool audio, bool video, const sp &reply) { ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 96306db..511d752 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -25,6 +25,7 @@ namespace android { struct ABuffer; +struct AMessage; struct MetaData; struct NuPlayerDriver; @@ -169,6 +170,10 @@ private: bool mStarted; + inline const sp &getDecoder(bool audio) { + return audio ? mAudioDecoder : mVideoDecoder; + } + void openAudioSink(const sp &format, bool offloadOnly); void closeAudioSink(); @@ -185,7 +190,9 @@ private: void finishFlushIfPossible(); - void flushDecoder(bool audio, bool needShutdown); + void flushDecoder( + bool audio, bool needShutdown, const sp &newFormat = NULL); + void updateDecoderFormatWithoutFlush(bool audio, const sp &format); static bool IsFlushingState(FlushStatus state, bool *needShutdown = NULL); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 47c46d6..d1aac50 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -71,6 +71,19 @@ status_t PostAndAwaitResponse( return err; } +void NuPlayer::Decoder::rememberCodecSpecificData(const sp &format) { + mCSDsForCurrentFormat.clear(); + for (int32_t i = 0; ; ++i) { + AString tag = "csd-"; + tag.append(i); + sp buffer; + if (!format->findBuffer(tag.c_str(), &buffer)) { + break; + } + mCSDsForCurrentFormat.push(buffer); + } +} + void NuPlayer::Decoder::onConfigure(const sp &format) { CHECK(mCodec == NULL); @@ -123,6 +136,8 @@ void NuPlayer::Decoder::onConfigure(const sp &format) { handleError(err); return; } + rememberCodecSpecificData(format); + // the following should work in configured state CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat)); CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat)); @@ -189,6 +204,12 @@ void NuPlayer::Decoder::configure(const sp &format) { msg->post(); } +void NuPlayer::Decoder::signalUpdateFormat(const sp &format) { + sp msg = new AMessage(kWhatUpdateFormat, id()); + msg->setMessage("format", format); + msg->post(); +} + status_t NuPlayer::Decoder::getInputBuffers(Vector > *buffers) const { sp msg = new AMessage(kWhatGetInputBuffers, id()); msg->setPointer("buffers", buffers); @@ -229,6 +250,15 @@ bool NuPlayer::Decoder::handleAnInputBuffer() { reply->setSize("buffer-ix", bufferIx); reply->setInt32("generation", mBufferGeneration); + if (!mCSDsToSubmit.isEmpty()) { + sp buffer = mCSDsToSubmit.itemAt(0); + ALOGI("[%s] resubmitting CSD", mComponentName.c_str()); + reply->setBuffer("buffer", buffer); + mCSDsToSubmit.removeAt(0); + reply->post(); + return true; + } + sp notify = mNotify->dup(); notify->setInt32("what", kWhatFillThisBuffer); notify->setBuffer("buffer", mInputBuffers[bufferIx]); @@ -312,10 +342,12 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { uint32_t flags = 0; CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); - int32_t eos; - // we do not expect CODECCONFIG or SYNCFRAME for decoder + int32_t eos, csd; + // we do not expect SYNCFRAME for decoder if (buffer->meta()->findInt32("eos", &eos) && eos) { flags |= MediaCodec::BUFFER_FLAG_EOS; + } else if (buffer->meta()->findInt32("csd", &csd) && csd) { + flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG; } // copy into codec buffer @@ -448,6 +480,7 @@ void NuPlayer::Decoder::onFlush() { status_t err = OK; if (mCodec != NULL) { err = mCodec->flush(); + mCSDsToSubmit = mCSDsForCurrentFormat; // copy operator ++mBufferGeneration; } @@ -515,6 +548,14 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { break; } + case kWhatUpdateFormat: + { + sp format; + CHECK(msg->findMessage("format", &format)); + rememberCodecSpecificData(format); + break; + } + case kWhatGetInputBuffers: { uint32_t replyID; @@ -566,6 +607,10 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { case kWhatFlush: { + sp format; + if (msg->findMessage("new-format", &format)) { + rememberCodecSpecificData(format); + } onFlush(); break; } @@ -588,8 +633,12 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { } } -void NuPlayer::Decoder::signalFlush() { - (new AMessage(kWhatFlush, id()))->post(); +void NuPlayer::Decoder::signalFlush(const sp &format) { + sp msg = new AMessage(kWhatFlush, id()); + if (format != NULL) { + msg->setMessage("new-format", format); + } + msg->post(); } void NuPlayer::Decoder::signalResume() { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index c6fc237..67bddb8 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -36,7 +36,8 @@ struct NuPlayer::Decoder : public AHandler { virtual void init(); status_t getInputBuffers(Vector > *dstBuffers) const; - virtual void signalFlush(); + virtual void signalFlush(const sp &format = NULL); + virtual void signalUpdateFormat(const sp &format); virtual void signalResume(); virtual void initiateShutdown(); @@ -67,6 +68,7 @@ private: kWhatRenderBuffer = 'rndr', kWhatFlush = 'flus', kWhatShutdown = 'shuD', + kWhatUpdateFormat = 'uFmt', }; sp mNotify; @@ -80,6 +82,8 @@ private: Vector > mInputBuffers; Vector > mOutputBuffers; + Vector > mCSDsForCurrentFormat; + Vector > mCSDsToSubmit; Vector mInputBufferIsDequeued; Vector mMediaBuffers; @@ -103,6 +107,7 @@ private: AString mComponentName; bool supportsSeamlessAudioFormatChange(const sp &targetFormat) const; + void rememberCodecSpecificData(const sp &format); DISALLOW_EVIL_CONSTRUCTORS(Decoder); }; -- cgit v1.1 From da65048e8e6f65ed9b3f23cda3f4554025c76fc4 Mon Sep 17 00:00:00 2001 From: Rachad Alao Date: Mon, 25 Aug 2014 21:46:34 +0000 Subject: Revert "disable AwesomePlayer for Ogg vorbis" Temporarily revert commit 9b48f5d780757ffb81709df3633d06b62edaf39f as a workaround for b/17173673 Bug: 17173673 Change-Id: Iec52289e77485a58ce28cc515d6a5b8e7b2d328a --- media/libmediaplayerservice/MediaPlayerFactory.cpp | 25 ++++++++++------------ media/libmediaplayerservice/MediaPlayerFactory.h | 1 + 2 files changed, 12 insertions(+), 14 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp index 3e0fc0d..dacb144 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.cpp +++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp @@ -60,7 +60,7 @@ status_t MediaPlayerFactory::registerFactory_l(IFactory* factory, return OK; } -static player_type getDefaultPlayerType() { +player_type MediaPlayerFactory::getDefaultPlayerType() { char value[PROPERTY_VALUE_MAX]; if (property_get("media.stagefright.use-awesome", value, NULL) && (!strcmp("1", value) || !strcasecmp("true", value))) { @@ -181,19 +181,16 @@ class StagefrightPlayerFactory : int64_t offset, int64_t /*length*/, float /*curScore*/) { - if (getDefaultPlayerType() - == STAGEFRIGHT_PLAYER) { - char buf[20]; - lseek(fd, offset, SEEK_SET); - read(fd, buf, sizeof(buf)); - lseek(fd, offset, SEEK_SET); - - uint32_t ident = *((uint32_t*)buf); - - // Ogg vorbis? - if (ident == 0x5367674f) // 'OggS' - return 1.0; - } + char buf[20]; + lseek(fd, offset, SEEK_SET); + read(fd, buf, sizeof(buf)); + lseek(fd, offset, SEEK_SET); + + uint32_t ident = *((uint32_t*)buf); + + // Ogg vorbis? + if (ident == 0x5367674f) // 'OggS' + return 1.0; return 0.0; } diff --git a/media/libmediaplayerservice/MediaPlayerFactory.h b/media/libmediaplayerservice/MediaPlayerFactory.h index 55ff918..5ddde19 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.h +++ b/media/libmediaplayerservice/MediaPlayerFactory.h @@ -71,6 +71,7 @@ class MediaPlayerFactory { static status_t registerFactory_l(IFactory* factory, player_type type); + static player_type getDefaultPlayerType(); static Mutex sLock; static tFactoryMap sFactoryMap; -- cgit v1.1 From afc0a87cc92a474bb14fb2a4093c74d04e4efd1b Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 26 Aug 2014 09:56:52 -0700 Subject: do string compare with mime immediately after we get the value Bug: 17210803 Change-Id: I4d20dd4b95d18251c18a371bd8f89b1320b38879 --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 76e1d54..5a4d131 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -134,13 +134,17 @@ status_t NuPlayer::GenericSource::initFromDataSource( } for (size_t i = 0; i < extractor->countTracks(); ++i) { + sp track = extractor->getTrack(i); + sp meta = extractor->getTrackMetaData(i); const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); - sp track = extractor->getTrack(i); - + // Do the string compare immediately with "mime", + // we can't assume "mime" would stay valid after another + // extractor operation, some extractors might modify meta + // during getTrack() and make it invalid. if (!strncasecmp(mime, "audio/", 6)) { if (mAudioTrack.mSource == NULL) { mAudioTrack.mIndex = i; -- cgit v1.1 From 2a79c3274e11b91675a509e16cb3b157df141fac Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 26 Aug 2014 13:57:32 -0700 Subject: Fix SoundPool lockup NuPlayerDriver needs to update its internal state before calling its listener, so that when the listener calls back into NuPlayerDriver, NuPlayerDriver has the right state. Bug: 14057920 Change-Id: I224882c427f5e3c9d4bf96c5d68075e235062401 --- media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 2f60072..c4bbcdf 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -287,8 +287,9 @@ status_t NuPlayerDriver::stop() { // fall through case STATE_PAUSED: + mState = STATE_STOPPED; notifyListener_l(MEDIA_STOPPED); - // fall through + break; case STATE_PREPARED: case STATE_STOPPED: @@ -314,6 +315,8 @@ status_t NuPlayerDriver::pause() { return OK; case STATE_RUNNING: + setPauseStartedTimeIfNeeded(); + mState = STATE_PAUSED; notifyListener_l(MEDIA_PAUSED); mPlayer->pause(); break; @@ -322,9 +325,6 @@ status_t NuPlayerDriver::pause() { return INVALID_OPERATION; } - setPauseStartedTimeIfNeeded(); - mState = STATE_PAUSED; - return OK; } @@ -675,15 +675,17 @@ void NuPlayerDriver::notifyPrepareCompleted(status_t err) { mAsyncResult = err; if (err == OK) { + // update state before notifying client, so that if client calls back into NuPlayerDriver + // in response, NuPlayerDriver has the right state + mState = STATE_PREPARED; if (mIsAsyncPrepare) { notifyListener_l(MEDIA_PREPARED); } - mState = STATE_PREPARED; } else { + mState = STATE_UNPREPARED; if (mIsAsyncPrepare) { notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); } - mState = STATE_UNPREPARED; } mCondition.broadcast(); -- cgit v1.1 From 9c03a40367c149526c31ddf14a518ba2036195a5 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Tue, 26 Aug 2014 15:24:43 -0700 Subject: NuPlayer: set controlledByApp to true when creating Surface. This fixes hang when trying to dequeue buffer from native window followed by a flush. Bug: 16303659 Bug: 17250931 Change-Id: Ib87ae558b020f5ce82b4192ec63339c93a72a2e9 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index f4cd02c..2b7457b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -280,7 +280,7 @@ void NuPlayer::setVideoSurfaceTextureAsync( msg->setObject( "native-window", new NativeWindowWrapper( - new Surface(bufferProducer))); + new Surface(bufferProducer, true /* controlledByApp */))); } msg->post(); -- cgit v1.1 From 5095d7091874cb9e9c95ecc4fe762076ed05e624 Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Wed, 27 Aug 2014 12:05:48 -0700 Subject: AudioPlayback: delay the post of EOS based on pending playout. Bug: 16840522 Change-Id: Icdc8888f5a8a77e2e5ebeb8a6934c7d79bd9e71a --- .../nuplayer/NuPlayerRenderer.cpp | 38 ++++++++++------------ .../nuplayer/NuPlayerRenderer.h | 3 +- 2 files changed, 19 insertions(+), 22 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index a3c976d..bf6b3df 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -410,8 +410,11 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { if (entry->mBuffer == NULL) { // EOS - - notifyEOS(true /* audio */, entry->mFinalResult); + int64_t postEOSDelayUs = 0; + if (mAudioSink->needsTrailingPadding()) { + postEOSDelayUs = getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency(); + } + notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs); mAudioQueue.erase(mAudioQueue.begin()); entry = NULL; @@ -421,26 +424,11 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { if (entry->mOffset == 0) { int64_t mediaTimeUs; CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); - ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); - mAnchorTimeMediaUs = mediaTimeUs; - uint32_t numFramesPlayed; - CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); - - uint32_t numFramesPendingPlayout = - mNumFramesWritten - numFramesPlayed; - - int64_t realTimeOffsetUs = - (mAudioSink->latency() / 2 /* XXX */ - + numFramesPendingPlayout - * mAudioSink->msecsPerFrame()) * 1000ll; - - // ALOGI("realTimeOffsetUs = %lld us", realTimeOffsetUs); - - mAnchorTimeRealUs = - ALooper::GetNowUs() + realTimeOffsetUs; + mAnchorTimeRealUs = ALooper::GetNowUs() + + getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency() / 2; } size_t copy = entry->mBuffer->size() - entry->mOffset; @@ -494,6 +482,14 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { return !mAudioQueue.empty(); } +int64_t NuPlayer::Renderer::getAudioPendingPlayoutUs() { + uint32_t numFramesPlayed; + CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); + + uint32_t numFramesPendingPlayout = mNumFramesWritten - numFramesPlayed; + return numFramesPendingPlayout * mAudioSink->msecsPerFrame() * 1000; +} + void NuPlayer::Renderer::postDrainVideoQueue() { if (mDrainVideoQueuePending || mSyncQueues || mPaused) { return; @@ -607,12 +603,12 @@ void NuPlayer::Renderer::notifyVideoRenderingStart() { notify->post(); } -void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult) { +void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) { sp notify = mNotify->dup(); notify->setInt32("what", kWhatEOS); notify->setInt32("audio", static_cast(audio)); notify->setInt32("finalResult", finalResult); - notify->post(); + notify->post(delayUs); } void NuPlayer::Renderer::notifyAudioOffloadTearDown() { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 1cba1a0..8da6458 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -129,6 +129,7 @@ private: size_t fillAudioBuffer(void *buffer, size_t size); bool onDrainAudioQueue(); + int64_t getAudioPendingPlayoutUs(); void postDrainAudioQueue_l(int64_t delayUs = 0); void onDrainVideoQueue(); @@ -146,7 +147,7 @@ private: void onResume(); void onAudioOffloadTearDown(); - void notifyEOS(bool audio, status_t finalResult); + void notifyEOS(bool audio, status_t finalResult, int64_t delayUs = 0); void notifyFlushComplete(bool audio); void notifyPosition(); void notifyVideoLateBy(int64_t lateByUs); -- cgit v1.1 From 75c672fc376ef9b3ceff61a96513242b0e5ebd60 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 27 Aug 2014 15:20:45 -0700 Subject: Fix potential deadlock in unregisterStaleHandlers() The scenario is that a call to unregisterStaleHandlers() is in progress, and is holding a temporary sp reference to an active ALooper inside of the loop. At this point the only other remaining external reference to the ALooper goes away, so the temporary sp in the loop is now the only reference keeping that object alive. When the loop iterates and the sp<> goes out of scope, the ALooper destructor is called, which in turn calls unregisterStaleHandlers again, resulting in a recursive lock. Bug: 17300093 Change-Id: I116f2ffab4ae7c43b6bcf54a367ae6f9d77c9626 --- media/libstagefright/foundation/ALooperRoster.cpp | 26 +++++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp index 0c181ff..0f44b52 100644 --- a/media/libstagefright/foundation/ALooperRoster.cpp +++ b/media/libstagefright/foundation/ALooperRoster.cpp @@ -72,15 +72,27 @@ void ALooperRoster::unregisterHandler(ALooper::handler_id handlerID) { } void ALooperRoster::unregisterStaleHandlers() { - Mutex::Autolock autoLock(mLock); - for (size_t i = mHandlers.size(); i-- > 0;) { - const HandlerInfo &info = mHandlers.valueAt(i); + Vector > activeLoopers; + { + Mutex::Autolock autoLock(mLock); - sp looper = info.mLooper.promote(); - if (looper == NULL) { - ALOGV("Unregistering stale handler %d", mHandlers.keyAt(i)); - mHandlers.removeItemsAt(i); + for (size_t i = mHandlers.size(); i-- > 0;) { + const HandlerInfo &info = mHandlers.valueAt(i); + + sp looper = info.mLooper.promote(); + if (looper == NULL) { + ALOGV("Unregistering stale handler %d", mHandlers.keyAt(i)); + mHandlers.removeItemsAt(i); + } else { + // At this point 'looper' might be the only sp<> keeping + // the object alive. To prevent it from going out of scope + // and having ~ALooper call this method again recursively + // and then deadlocking because of the Autolock above, add + // it to a Vector which will go out of scope after the lock + // has been released. + activeLoopers.add(looper); + } } } } -- cgit v1.1 From 031be0f358b07732092a4d1bf02fc99f109a63c4 Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Fri, 22 Aug 2014 12:49:26 -0700 Subject: Add adaptive playback support to VPX decoder. Bug: 13842676 Change-Id: I9c054ea489fd3a71b3b2394f15a85b84d42edb5a --- .../libstagefright/codecs/avc/enc/SoftAVCEncoder.h | 4 -- .../codecs/m4v_h263/enc/SoftMPEG4Encoder.h | 4 -- media/libstagefright/codecs/on2/dec/SoftVPX.cpp | 59 ++++++++++++++-------- .../libstagefright/codecs/on2/enc/SoftVPXEncoder.h | 4 -- .../include/SimpleSoftOMXComponent.h | 5 ++ .../include/SoftVideoDecoderOMXComponent.h | 5 ++ .../omx/SoftVideoDecoderOMXComponent.cpp | 41 +++++++++++++-- 7 files changed, 87 insertions(+), 35 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h index 23d5ff1..cfa9ca5 100644 --- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h +++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h @@ -67,10 +67,6 @@ private: kNumBuffers = 2, }; - enum { - kStoreMetaDataExtensionIndex = OMX_IndexVendorStartUnused + 1 - }; - // OMX input buffer's timestamp and flags typedef struct { int64_t mTimeUs; diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h index cc4ea8f..c59a1b9 100644 --- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h +++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h @@ -56,10 +56,6 @@ private: kNumBuffers = 2, }; - enum { - kStoreMetaDataExtensionIndex = OMX_IndexVendorStartUnused + 1 - }; - // OMX input buffer's timestamp and flags typedef struct { int64_t mTimeUs; diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp index 423a057..a4258dd 100644 --- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp +++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp @@ -143,11 +143,24 @@ void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) { mWidth = width; mHeight = height; - updatePortDefinitions(); - - notify(OMX_EventPortSettingsChanged, 1, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; - return; + if (!mIsAdaptive || width > mAdaptiveMaxWidth || height > mAdaptiveMaxHeight) { + if (mIsAdaptive) { + if (width > mAdaptiveMaxWidth) { + mAdaptiveMaxWidth = width; + } + if (height > mAdaptiveMaxHeight) { + mAdaptiveMaxHeight = height; + } + } + updatePortDefinitions(); + notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + return; + } else { + updatePortDefinitions(); + notify(OMX_EventPortSettingsChanged, kOutputPortIndex, + OMX_IndexConfigCommonOutputCrop, NULL); + } } outHeader->nOffset = 0; @@ -155,29 +168,35 @@ void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) { outHeader->nFlags = EOSseen ? OMX_BUFFERFLAG_EOS : 0; outHeader->nTimeStamp = inHeader->nTimeStamp; + uint32_t buffer_stride = mIsAdaptive ? mAdaptiveMaxWidth : mWidth; + uint32_t buffer_height = mIsAdaptive ? mAdaptiveMaxHeight : mHeight; + const uint8_t *srcLine = (const uint8_t *)img->planes[PLANE_Y]; uint8_t *dst = outHeader->pBuffer; - for (size_t i = 0; i < img->d_h; ++i) { - memcpy(dst, srcLine, img->d_w); - - srcLine += img->stride[PLANE_Y]; - dst += img->d_w; + for (size_t i = 0; i < buffer_height; ++i) { + if (i < img->d_h) { + memcpy(dst, srcLine, img->d_w); + srcLine += img->stride[PLANE_Y]; + } + dst += buffer_stride; } srcLine = (const uint8_t *)img->planes[PLANE_U]; - for (size_t i = 0; i < img->d_h / 2; ++i) { - memcpy(dst, srcLine, img->d_w / 2); - - srcLine += img->stride[PLANE_U]; - dst += img->d_w / 2; + for (size_t i = 0; i < buffer_height / 2; ++i) { + if (i < img->d_h / 2) { + memcpy(dst, srcLine, img->d_w / 2); + srcLine += img->stride[PLANE_U]; + } + dst += buffer_stride / 2; } srcLine = (const uint8_t *)img->planes[PLANE_V]; - for (size_t i = 0; i < img->d_h / 2; ++i) { - memcpy(dst, srcLine, img->d_w / 2); - - srcLine += img->stride[PLANE_V]; - dst += img->d_w / 2; + for (size_t i = 0; i < buffer_height / 2; ++i) { + if (i < img->d_h / 2) { + memcpy(dst, srcLine, img->d_w / 2); + srcLine += img->stride[PLANE_V]; + } + dst += buffer_stride / 2; } outInfo->mOwnedByUs = false; diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h index c5a83d1..5b4c954 100644 --- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h +++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h @@ -91,10 +91,6 @@ protected: const char *name, OMX_INDEXTYPE *index); private: - enum { - kStoreMetaDataExtensionIndex = OMX_IndexVendorStartUnused + 1, - }; - enum TemporalReferences { // For 1 layer case: reference all (last, golden, and alt ref), but only // update last. diff --git a/media/libstagefright/include/SimpleSoftOMXComponent.h b/media/libstagefright/include/SimpleSoftOMXComponent.h index f8c61eb..591b38e 100644 --- a/media/libstagefright/include/SimpleSoftOMXComponent.h +++ b/media/libstagefright/include/SimpleSoftOMXComponent.h @@ -58,6 +58,11 @@ protected: } mTransition; }; + enum { + kStoreMetaDataExtensionIndex = OMX_IndexVendorStartUnused + 1, + kPrepareForAdaptivePlaybackIndex, + }; + void addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def); virtual OMX_ERRORTYPE internalGetParameter( diff --git a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h index 7f200dd..ee553d9 100644 --- a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h +++ b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h @@ -55,6 +55,9 @@ protected: virtual OMX_ERRORTYPE getConfig( OMX_INDEXTYPE index, OMX_PTR params); + virtual OMX_ERRORTYPE getExtensionIndex( + const char *name, OMX_INDEXTYPE *index); + void initPorts(OMX_U32 numInputBuffers, OMX_U32 inputBufferSize, OMX_U32 numOutputBuffers, @@ -68,6 +71,8 @@ protected: kMaxPortIndex = 1, }; + bool mIsAdaptive; + uint32_t mAdaptiveMaxWidth, mAdaptiveMaxHeight; uint32_t mWidth, mHeight; uint32_t mCropLeft, mCropTop, mCropWidth, mCropHeight; diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp index 1c383f7..69b572e 100644 --- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp +++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp @@ -22,6 +22,7 @@ #include "include/SoftVideoDecoderOMXComponent.h" +#include #include #include #include @@ -50,6 +51,9 @@ SoftVideoDecoderOMXComponent::SoftVideoDecoderOMXComponent( OMX_PTR appData, OMX_COMPONENTTYPE **component) : SimpleSoftOMXComponent(name, callbacks, appData, component), + mIsAdaptive(false), + mAdaptiveMaxWidth(0), + mAdaptiveMaxHeight(0), mWidth(width), mHeight(height), mCropLeft(0), @@ -127,8 +131,8 @@ void SoftVideoDecoderOMXComponent::updatePortDefinitions() { def->format.video.nSliceHeight = def->format.video.nFrameHeight; def = &editPortInfo(kOutputPortIndex)->mDef; - def->format.video.nFrameWidth = mWidth; - def->format.video.nFrameHeight = mHeight; + def->format.video.nFrameWidth = mIsAdaptive ? mAdaptiveMaxWidth : mWidth; + def->format.video.nFrameHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight; def->format.video.nStride = def->format.video.nFrameWidth; def->format.video.nSliceHeight = def->format.video.nFrameHeight; @@ -199,7 +203,10 @@ OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalGetParameter( OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalSetParameter( OMX_INDEXTYPE index, const OMX_PTR params) { - switch (index) { + // Include extension index OMX_INDEXEXTTYPE. + const int32_t indexFull = index; + + switch (indexFull) { case OMX_IndexParamStandardComponentRole: { const OMX_PARAM_COMPONENTROLETYPE *roleParams = @@ -230,6 +237,24 @@ OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalSetParameter( return OMX_ErrorNone; } + case kPrepareForAdaptivePlaybackIndex: + { + const PrepareForAdaptivePlaybackParams* adaptivePlaybackParams = + (const PrepareForAdaptivePlaybackParams *)params; + mIsAdaptive = adaptivePlaybackParams->bEnable; + if (mIsAdaptive) { + mAdaptiveMaxWidth = adaptivePlaybackParams->nMaxFrameWidth; + mAdaptiveMaxHeight = adaptivePlaybackParams->nMaxFrameHeight; + mWidth = mAdaptiveMaxWidth; + mHeight = mAdaptiveMaxHeight; + } else { + mAdaptiveMaxWidth = 0; + mAdaptiveMaxHeight = 0; + } + updatePortDefinitions(); + return OMX_ErrorNone; + } + default: return SimpleSoftOMXComponent::internalSetParameter(index, params); } @@ -259,6 +284,16 @@ OMX_ERRORTYPE SoftVideoDecoderOMXComponent::getConfig( } } +OMX_ERRORTYPE SoftVideoDecoderOMXComponent::getExtensionIndex( + const char *name, OMX_INDEXTYPE *index) { + if (!strcmp(name, "OMX.google.android.index.prepareForAdaptivePlayback")) { + *(int32_t*)index = kPrepareForAdaptivePlaybackIndex; + return OMX_ErrorNone; + } + + return SimpleSoftOMXComponent::getExtensionIndex(name, index); +} + void SoftVideoDecoderOMXComponent::onReset() { mOutputPortSettingsChange = NONE; } -- cgit v1.1 From 047dd13ca42ff7cea10821ef64eb09229fa3e751 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 28 Aug 2014 10:49:08 -0700 Subject: Fix more potential deadlocks in ALooperRoster Bug: 17059501 Change-Id: I242f2859527bed2d6e275c27de94fb19f4dcdc28 --- media/libstagefright/foundation/ALooperRoster.cpp | 41 +++++++---------------- 1 file changed, 12 insertions(+), 29 deletions(-) (limited to 'media') diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp index 0f44b52..e0dc768 100644 --- a/media/libstagefright/foundation/ALooperRoster.cpp +++ b/media/libstagefright/foundation/ALooperRoster.cpp @@ -99,35 +99,13 @@ void ALooperRoster::unregisterStaleHandlers() { status_t ALooperRoster::postMessage( const sp &msg, int64_t delayUs) { - Mutex::Autolock autoLock(mLock); - return postMessage_l(msg, delayUs); -} - -status_t ALooperRoster::postMessage_l( - const sp &msg, int64_t delayUs) { - ssize_t index = mHandlers.indexOfKey(msg->target()); - if (index < 0) { - ALOGW("failed to post message '%s'. Target handler not registered.", - msg->debugString().c_str()); - return -ENOENT; - } - - const HandlerInfo &info = mHandlers.valueAt(index); - - sp looper = info.mLooper.promote(); + sp looper = findLooper(msg->target()); if (looper == NULL) { - ALOGW("failed to post message. " - "Target handler %d still registered, but object gone.", - msg->target()); - - mHandlers.removeItemsAt(index); return -ENOENT; } - looper->post(msg, delayUs); - return OK; } @@ -181,18 +159,23 @@ sp ALooperRoster::findLooper(ALooper::handler_id handlerID) { status_t ALooperRoster::postAndAwaitResponse( const sp &msg, sp *response) { + sp looper = findLooper(msg->target()); + + if (looper == NULL) { + ALOGW("failed to post message. " + "Target handler %d still registered, but object gone.", + msg->target()); + response->clear(); + return -ENOENT; + } + Mutex::Autolock autoLock(mLock); uint32_t replyID = mNextReplyID++; msg->setInt32("replyID", replyID); - status_t err = postMessage_l(msg, 0 /* delayUs */); - - if (err != OK) { - response->clear(); - return err; - } + looper->post(msg, 0 /* delayUs */); ssize_t index; while ((index = mReplies.indexOfKey(replyID)) < 0) { -- cgit v1.1 From 0b0f6075377260e006e860e3ba296f5504a6c891 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 28 Aug 2014 12:40:34 -0700 Subject: Move stale handler cleanup to constructor This avoids the potential side effect of deleting more ALoopers inside the cleanup loop. Bug: 17059501 Change-Id: I41efaf490449b95fedfe01175f3b19067d50da24 --- media/libstagefright/foundation/ALooper.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp index ebf9d8d..88b1c92 100644 --- a/media/libstagefright/foundation/ALooper.cpp +++ b/media/libstagefright/foundation/ALooper.cpp @@ -68,14 +68,14 @@ int64_t ALooper::GetNowUs() { ALooper::ALooper() : mRunningLocally(false) { + // clean up stale AHandlers. Doing it here instead of in the destructor avoids + // the side effect of objects being deleted from the unregister function recursively. + gLooperRoster.unregisterStaleHandlers(); } ALooper::~ALooper() { stop(); - - // Since this looper is "dead" (or as good as dead by now), - // have ALooperRoster unregister any handlers still registered for it. - gLooperRoster.unregisterStaleHandlers(); + // stale AHandlers are now cleaned up in the constructor of the next ALooper to come along } void ALooper::setName(const char *name) { -- cgit v1.1 From 39f5874c4040bec6fdbf0c0912daffcb10010df8 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 28 Aug 2014 15:18:53 -0700 Subject: PlaylistFetcher: add lower bound check when starting live streams Avoid false 'missed the boat' alarms that cause us to queue a bogus discontinuity before even starting. Bug: 17303166 Change-Id: I5003934fc695f30db2df9a0803b8fe960d77a458 --- media/libstagefright/httplive/PlaylistFetcher.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'media') diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 80cb2d0..4d5d79e 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -754,6 +754,9 @@ void PlaylistFetcher::onDownloadNext() { if (!mPlaylist->isComplete() && !mPlaylist->isEvent()) { // If this is a live session, start 3 segments from the end on connect mSeqNumber = lastSeqNumberInPlaylist - 3; + if (mSeqNumber < firstSeqNumberInPlaylist) { + mSeqNumber = firstSeqNumberInPlaylist; + } } else { mSeqNumber = getSeqNumberForTime(mStartTimeUs); mStartTimeUs -= getSegmentStartTimeUs(mSeqNumber); -- cgit v1.1 From a90cff5f7091bfb50c57e2d87bad3fc3f103f397 Mon Sep 17 00:00:00 2001 From: Hochi Huang Date: Sat, 23 Aug 2014 09:19:27 +0800 Subject: [AU]Sync libmedia/Android.mk modification from KLP-Sprout Bug: 17322146 Change-Id: If29fbd87252710bd794f2e0bb270bc846380ef1d Signed-off-by: Hochi Huang --- media/libmedia/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index 3be0651..37bc418 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -70,7 +70,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_STATIC_LIBRARIES += libinstantssq -LOCAL_WHOLE_STATIC_LIBRARY := libmedia_helper +LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper LOCAL_MODULE:= libmedia -- cgit v1.1 From 97827bd7c7e64dec22c8fe0f9e734a3c432ad7ee Mon Sep 17 00:00:00 2001 From: Rachad Date: Thu, 28 Aug 2014 19:08:45 -0700 Subject: Tunneled Video Playback: Changed AudioHwSync token to int32_t to match Audio stack api. Bug: 17112525 Change-Id: I673819495c2e7b540e8d7572cc95796bddbf63bb --- media/libstagefright/ACodec.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index e4e463a..19a5908 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -1245,13 +1245,13 @@ status_t ACodec::configureCodec( tunneled != 0) { ALOGI("Configuring TUNNELED video playback."); - int64_t audioHwSync = 0; - if (!msg->findInt64("audio-hw-sync", &audioHwSync)) { + int32_t audioHwSync = 0; + if (!msg->findInt32("audio-hw-sync", &audioHwSync)) { ALOGW("No Audio HW Sync provided for video tunnel"); } err = configureTunneledVideoPlayback(audioHwSync, nativeWindow); if (err != OK) { - ALOGE("configureTunneledVideoPlayback(%" PRId64 ",%p) failed!", + ALOGE("configureTunneledVideoPlayback(%d,%p) failed!", audioHwSync, nativeWindow.get()); return err; } @@ -1898,7 +1898,7 @@ status_t ACodec::setupRawAudioFormat( } status_t ACodec::configureTunneledVideoPlayback( - int64_t audioHwSync, const sp &nativeWindow) { + int32_t audioHwSync, const sp &nativeWindow) { native_handle_t* sidebandHandle; status_t err = mOMX->configureVideoTunnelMode( -- cgit v1.1 From 802768790c131f8237364906fd13981a6bb91193 Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Thu, 28 Aug 2014 15:50:29 -0700 Subject: GenericSource: set DRM playback status. Bug: 17307158 Change-Id: I36b801a9b67831b618930cf1241756bb9644b4fd --- media/libmediaplayerservice/Android.mk | 1 + .../nuplayer/GenericSource.cpp | 73 ++++++++++++++++++++++ .../libmediaplayerservice/nuplayer/GenericSource.h | 13 ++++ media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 6 ++ .../nuplayer/NuPlayerSource.h | 1 + 5 files changed, 94 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index 0c7e590..adc066d 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -28,6 +28,7 @@ LOCAL_SHARED_LIBRARIES := \ libcamera_client \ libcrypto \ libcutils \ + libdrmframework \ liblog \ libdl \ libgui \ diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index cdb7e69..3691c85 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -32,6 +32,7 @@ #include #include #include +#include "../../libstagefright/include/DRMExtractor.h" #include "../../libstagefright/include/NuCachedSource2.h" #include "../../libstagefright/include/WVMExtractor.h" @@ -49,6 +50,7 @@ NuPlayer::GenericSource::GenericSource( mIsWidevine(false), mUIDValid(uidValid), mUID(uid), + mDrmManagerClient(NULL), mMetaDataSize(-1ll), mBitrate(-1ll), mPollBufferingGeneration(0) { @@ -57,12 +59,18 @@ NuPlayer::GenericSource::GenericSource( } void NuPlayer::GenericSource::resetDataSource() { + mAudioTimeUs = 0; + mVideoTimeUs = 0; mHTTPService.clear(); mUri.clear(); mUriHeaders.clear(); mFd = -1; mOffset = 0; mLength = 0; + setDrmPlaybackStatusIfNeeded(Playback::STOP, 0); + mDecryptHandle = NULL; + mDrmManagerClient = NULL; + mStarted = false; } status_t NuPlayer::GenericSource::setDataSource( @@ -130,6 +138,10 @@ status_t NuPlayer::GenericSource::initFromDataSource() { return UNKNOWN_ERROR; } + if (extractor->getDrmFlag()) { + checkDrmStatus(mDataSource); + } + sp fileMeta = extractor->getMetaData(); if (fileMeta != NULL) { int64_t duration; @@ -199,6 +211,28 @@ status_t NuPlayer::GenericSource::initFromDataSource() { return OK; } +void NuPlayer::GenericSource::checkDrmStatus(const sp& dataSource) { + dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); + if (mDecryptHandle != NULL) { + CHECK(mDrmManagerClient); + if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { + sp msg = dupNotify(); + msg->setInt32("what", kWhatDrmNoLicense); + msg->post(); + } + } +} + +int64_t NuPlayer::GenericSource::getLastReadPosition() { + if (mAudioTrack.mSource != NULL) { + return mAudioTimeUs; + } else if (mVideoTrack.mSource != NULL) { + return mVideoTimeUs; + } else { + return 0; + } +} + status_t NuPlayer::GenericSource::setBuffers( bool audio, Vector &buffers) { if (mIsWidevine && !audio) { @@ -394,6 +428,33 @@ void NuPlayer::GenericSource::start() { readBuffer(MEDIA_TRACK_TYPE_VIDEO); } + + setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000); + mStarted = true; +} + +void NuPlayer::GenericSource::stop() { + // nothing to do, just account for DRM playback status + setDrmPlaybackStatusIfNeeded(Playback::STOP, 0); + mStarted = false; +} + +void NuPlayer::GenericSource::pause() { + // nothing to do, just account for DRM playback status + setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0); + mStarted = false; +} + +void NuPlayer::GenericSource::resume() { + // nothing to do, just account for DRM playback status + setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000); + mStarted = true; +} + +void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) { + if (mDecryptHandle != NULL) { + mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position); + } } status_t NuPlayer::GenericSource::feedMoreTSData() { @@ -868,6 +929,10 @@ status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs); } + setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000); + if (!mStarted) { + setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0); + } return OK; } @@ -985,6 +1050,14 @@ void NuPlayer::GenericSource::readBuffer( options.clearSeekTo(); if (err == OK) { + int64_t timeUs; + CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); + if (trackType == MEDIA_TRACK_TYPE_AUDIO) { + mAudioTimeUs = timeUs; + } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) { + mVideoTimeUs = timeUs; + } + // formatChange && seeking: track whose source is changed during selection // formatChange && !seeking: track whose source is not changed during selection // !formatChange: normal seek diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 663bfae..1f13120 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -27,6 +27,8 @@ namespace android { +class DecryptHandle; +class DrmManagerClient; struct AnotherPacketSource; struct ARTSPController; struct DataSource; @@ -49,6 +51,9 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual void prepareAsync(); virtual void start(); + virtual void stop(); + virtual void pause(); + virtual void resume(); virtual status_t feedMoreTSData(); @@ -90,7 +95,9 @@ private: }; Track mAudioTrack; + int64_t mAudioTimeUs; Track mVideoTrack; + int64_t mVideoTimeUs; Track mSubtitleTrack; Track mTimedTextTrack; @@ -111,6 +118,9 @@ private: sp mDataSource; sp mCachedSource; sp mWVMExtractor; + DrmManagerClient *mDrmManagerClient; + sp mDecryptHandle; + bool mStarted; String8 mContentType; AString mSniffedMIME; off64_t mMetaDataSize; @@ -122,6 +132,9 @@ private: void resetDataSource(); status_t initFromDataSource(); + void checkDrmStatus(const sp& dataSource); + int64_t getLastReadPosition(); + void setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position); status_t prefillCacheIfNecessary(); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index f4cd02c..bc7bf44 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1915,6 +1915,12 @@ void NuPlayer::onSourceNotify(const sp &msg) { break; } + case Source::kWhatDrmNoLicense: + { + notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); + break; + } + default: TRESPASS(); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index 45657c2..7ccf3b1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -51,6 +51,7 @@ struct NuPlayer::Source : public AHandler { kWhatSubtitleData, kWhatTimedTextData, kWhatQueueDecoderShutdown, + kWhatDrmNoLicense, }; // The provides message is used to notify the player about various -- cgit v1.1 From 73ddd210ea572375198cac1d4960df793745fb4b Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Fri, 29 Aug 2014 16:33:49 -0700 Subject: NuPlayerRenderer: stop feeding AudioSink when paused. NuPlayerDriver: current position is updated only in running state. Bug: 17141882 Change-Id: Ia88551cc29ef8f0e7ef0600a214feb5633389b6e --- media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 6 ++++-- media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp | 7 +++---- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index c4bbcdf..2423f5f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -560,8 +560,10 @@ void NuPlayerDriver::notifyDuration(int64_t durationUs) { void NuPlayerDriver::notifyPosition(int64_t positionUs) { Mutex::Autolock autoLock(mLock); - mPositionUs = positionUs; - mNotifyTimeRealUs = ALooper::GetNowUs(); + if (isPlaying()) { + mPositionUs = positionUs; + mNotifyTimeRealUs = ALooper::GetNowUs(); + } } void NuPlayerDriver::notifySeekComplete() { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index bf6b3df..49941f8 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -315,7 +315,7 @@ size_t NuPlayer::Renderer::AudioSinkCallback( size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { Mutex::Autolock autoLock(mLock); - if (!offloadingAudio()) { + if (!offloadingAudio() || mPaused) { return 0; } @@ -887,6 +887,7 @@ void NuPlayer::Renderer::onPause() { ++mAudioQueueGeneration; ++mVideoQueueGeneration; prepareForMediaRenderingStart(); + mPaused = true; } mDrainAudioQueuePending = false; @@ -898,8 +899,6 @@ void NuPlayer::Renderer::onPause() { ALOGV("now paused audio queue has %d entries, video has %d entries", mAudioQueue.size(), mVideoQueue.size()); - - mPaused = true; } void NuPlayer::Renderer::onResume() { @@ -911,9 +910,9 @@ void NuPlayer::Renderer::onResume() { mAudioSink->start(); } + Mutex::Autolock autoLock(mLock); mPaused = false; - Mutex::Autolock autoLock(mLock); if (!mAudioQueue.empty()) { postDrainAudioQueue_l(); } -- cgit v1.1 From c22c695660ed9edaba0d4cd7c0ab3a794216fe80 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Fri, 29 Aug 2014 14:47:50 -0700 Subject: MediaCodec: set state to UNINITIALIZED when receiving fatal error. NuPlayerDecoder: release MediaCodec when handling an error. Bug: 16661923 Change-Id: I1b6fd7ee5cc1136b3f289135e5360cd3d98f9799 --- media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 2 ++ media/libstagefright/MediaCodec.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index d1aac50..5aaf48c 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -220,6 +220,8 @@ status_t NuPlayer::Decoder::getInputBuffers(Vector > *buffers) const void NuPlayer::Decoder::handleError(int32_t err) { + mCodec->release(); + sp notify = mNotify->dup(); notify->setInt32("what", kWhatError); notify->setInt32("err", err); diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 76f730f..fc2dd30 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -733,13 +733,15 @@ void MediaCodec::onMessageReceived(const sp &msg) { case CONFIGURING: { - setState(INITIALIZED); + setState(actionCode == ACTION_CODE_FATAL ? + UNINITIALIZED : INITIALIZED); break; } case STARTING: { - setState(CONFIGURED); + setState(actionCode == ACTION_CODE_FATAL ? + UNINITIALIZED : CONFIGURED); break; } -- cgit v1.1 From 34581f44cde67960fbac3ba1f191a2c063ea5145 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 29 Aug 2014 16:00:28 -0700 Subject: Use CharacterEncodingDetector in metadataretriever instead of media scanner. This way the java MediaMetadataRetriever API will give the same result as the media scanner. Also apply some tweaks to the encoding detector to improve handling of ISO-8859-1 tags. Bug: 16302581, 17205395 Change-Id: I1682a7a6a8bf04cffaa455044ba72dd7fd152d49 --- media/libmedia/Android.mk | 5 +- media/libmedia/CharacterEncodingDetector.cpp | 54 +++++++++++--- media/libmedia/CharacterEncodingDetector.h | 63 ---------------- media/libmedia/MediaScannerClient.cpp | 29 ++------ media/libmedia/StringArray.h | 83 ---------------------- media/libstagefright/Android.mk | 3 + .../StagefrightMetadataRetriever.cpp | 59 ++++++++++----- 7 files changed, 97 insertions(+), 199 deletions(-) delete mode 100644 media/libmedia/CharacterEncodingDetector.h delete mode 100644 media/libmedia/StringArray.h (limited to 'media') diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index 3be0651..ffadb23 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -76,9 +76,10 @@ LOCAL_MODULE:= libmedia LOCAL_C_INCLUDES := \ $(TOP)/frameworks/native/include/media/openmax \ + $(TOP)/frameworks/av/include/media/ \ $(TOP)/frameworks/av/media/libstagefright \ - external/icu/icu4c/source/common \ - external/icu/icu4c/source/i18n \ + $(TOP)/external/icu/icu4c/source/common \ + $(TOP)/external/icu/icu4c/source/i18n \ $(call include-path-for, audio-effects) \ $(call include-path-for, audio-utils) diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp index 7d1ddfd..41994dc 100644 --- a/media/libmedia/CharacterEncodingDetector.cpp +++ b/media/libmedia/CharacterEncodingDetector.cpp @@ -18,7 +18,7 @@ #define LOG_TAG "CharacterEncodingDector" #include -#include "CharacterEncodingDetector.h" +#include #include "CharacterEncodingDetectorTables.h" #include "utils/Vector.h" @@ -118,10 +118,12 @@ void CharacterEncodingDetector::detectAndConvert() { int32_t matches; const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status); bool goodmatch = true; + int highest = 0; const UCharsetMatch* bestCombinedMatch = getPreferred(buf, strlen(buf), - ucma, matches, &goodmatch); + ucma, matches, &goodmatch, &highest); - if (!goodmatch && strlen(buf) < 20) { + ALOGV("goodmatch: %s, highest: %d", goodmatch ? "true" : "false", highest); + if (!goodmatch && (highest < 15 || strlen(buf) < 20)) { ALOGV("not a good match, trying with more data"); // This string might be too short for ICU to do anything useful with. // (real world example: "Björk" in ISO-8859-1 might be detected as GB18030, because @@ -146,9 +148,10 @@ void CharacterEncodingDetector::detectAndConvert() { ucsdet_setText(csd, buf, strlen(buf), &status); ucma = ucsdet_detectAll(csd, &matches, &status); bestCombinedMatch = getPreferred(buf, strlen(buf), - ucma, matches, &goodmatch); - if (!goodmatch) { + ucma, matches, &goodmatch, &highest); + if (!goodmatch && highest <= 15) { ALOGV("still not a good match after adding printable tags"); + bestCombinedMatch = NULL; } } else { ALOGV("no printable tags to add"); @@ -157,6 +160,8 @@ void CharacterEncodingDetector::detectAndConvert() { if (bestCombinedMatch != NULL) { combinedenc = ucsdet_getName(bestCombinedMatch, &status); + } else { + combinedenc = "ISO-8859-1"; } } @@ -199,10 +204,17 @@ void CharacterEncodingDetector::detectAndConvert() { if (strcmp(enc,"UTF-8") != 0) { // only convert if the source encoding isn't already UTF-8 ALOGV("@@@ using converter %s for %s", enc, mNames.getEntry(i)); + status = U_ZERO_ERROR; UConverter *conv = ucnv_open(enc, &status); if (U_FAILURE(status)) { - ALOGE("could not create UConverter for %s", enc); - continue; + ALOGW("could not create UConverter for %s (%d), falling back to ISO-8859-1", + enc, status); + status = U_ZERO_ERROR; + conv = ucnv_open("ISO-8859-1", &status); + if (U_FAILURE(status)) { + ALOGW("could not create UConverter for ISO-8859-1 either"); + continue; + } } // convert from native encoding to UTF-8 @@ -224,7 +236,16 @@ void CharacterEncodingDetector::detectAndConvert() { } else { // zero terminate *target = 0; - mValues.setEntry(i, buffer); + // strip trailing spaces + while (--target > buffer && *target == ' ') { + *target = 0; + } + // skip leading spaces + char *start = buffer; + while (*start == ' ') { + start++; + } + mValues.setEntry(i, start); } delete[] buffer; @@ -261,7 +282,7 @@ void CharacterEncodingDetector::detectAndConvert() { const UCharsetMatch *CharacterEncodingDetector::getPreferred( const char *input, size_t len, const UCharsetMatch** ucma, size_t nummatches, - bool *goodmatch) { + bool *goodmatch, int *highestmatch) { *goodmatch = false; Vector matches; @@ -316,11 +337,17 @@ const UCharsetMatch *CharacterEncodingDetector::getPreferred( } ALOGV("%zu: %s %d", i, encname, confidence); + status = U_ZERO_ERROR; UConverter *conv = ucnv_open(encname, &status); + int demerit = 0; + if (U_FAILURE(status)) { + ALOGV("failed to open %s: %d", encname, status); + confidence = 0; + demerit += 1000; + } const char *source = input; const char *sourceLimit = input + len; status = U_ZERO_ERROR; - int demerit = 0; int frequentchars = 0; int totalchars = 0; while (true) { @@ -337,7 +364,8 @@ const UCharsetMatch *CharacterEncodingDetector::getPreferred( if (c < 0x20 || (c >= 0x7f && c <= 0x009f)) { ALOGV("control character %x", c); demerit += 100; - } else if ((c >= 0xa0 && c <= 0xbe) // symbols, superscripts + } else if ((c == 0xa0) // no-break space + || (c >= 0xa2 && c <= 0xbe) // symbols, superscripts || (c == 0xd7) || (c == 0xf7) // multiplication and division signs || (c >= 0x2000 && c <= 0x209f)) { // punctuation, superscripts ALOGV("unlikely character %x", c); @@ -408,10 +436,14 @@ const UCharsetMatch *CharacterEncodingDetector::getPreferred( } else { ALOGV("runner up: '%s' w/ %d confidence", ucsdet_getName(matches[runnerupidx], &status), runnerup); + if (runnerup < 0) { + runnerup = 0; + } if ((highest - runnerup) > 15) { *goodmatch = true; } } + *highestmatch = highest; return matches[highestidx]; } diff --git a/media/libmedia/CharacterEncodingDetector.h b/media/libmedia/CharacterEncodingDetector.h deleted file mode 100644 index 7b5ed86..0000000 --- a/media/libmedia/CharacterEncodingDetector.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2013 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 _CHARACTER_ENCODING_DETECTOR_H -#define _CHARACTER_ENCODING_DETECTOR_H - -#include - -#include "StringArray.h" - -#include "unicode/ucnv.h" -#include "unicode/ucsdet.h" -#include "unicode/ustring.h" - -namespace android { - -class CharacterEncodingDetector { - - public: - CharacterEncodingDetector(); - ~CharacterEncodingDetector(); - - void addTag(const char *name, const char *value); - size_t size(); - - void detectAndConvert(); - status_t getTag(int index, const char **name, const char**value); - - private: - const UCharsetMatch *getPreferred( - const char *input, size_t len, - const UCharsetMatch** ucma, size_t matches, - bool *goodmatch); - - bool isFrequent(const uint16_t *values, uint32_t c); - - // cached name and value strings, for native encoding support. - // TODO: replace these with byte blob arrays that don't require the data to be - // singlenullbyte-terminated - StringArray mNames; - StringArray mValues; - - UConverter* mUtf8Conv; -}; - - - -}; // namespace android - -#endif diff --git a/media/libmedia/MediaScannerClient.cpp b/media/libmedia/MediaScannerClient.cpp index 1661f04..9f803cb 100644 --- a/media/libmedia/MediaScannerClient.cpp +++ b/media/libmedia/MediaScannerClient.cpp @@ -25,14 +25,10 @@ namespace android { -MediaScannerClient::MediaScannerClient() - : mEncodingDetector(NULL) -{ +MediaScannerClient::MediaScannerClient() { } -MediaScannerClient::~MediaScannerClient() -{ - delete mEncodingDetector; +MediaScannerClient::~MediaScannerClient() { } void MediaScannerClient::setLocale(const char* locale) @@ -40,31 +36,16 @@ void MediaScannerClient::setLocale(const char* locale) mLocale = locale; // not currently used } -void MediaScannerClient::beginFile() -{ - delete mEncodingDetector; - mEncodingDetector = new CharacterEncodingDetector(); +void MediaScannerClient::beginFile() { } status_t MediaScannerClient::addStringTag(const char* name, const char* value) { - mEncodingDetector->addTag(name, value); + handleStringTag(name, value); return OK; } -void MediaScannerClient::endFile() -{ - mEncodingDetector->detectAndConvert(); - - int size = mEncodingDetector->size(); - if (size) { - for (int i = 0; i < size; i++) { - const char *name; - const char *value; - mEncodingDetector->getTag(i, &name, &value); - handleStringTag(name, value); - } - } +void MediaScannerClient::endFile() { } } // namespace android diff --git a/media/libmedia/StringArray.h b/media/libmedia/StringArray.h deleted file mode 100644 index ae47085..0000000 --- a/media/libmedia/StringArray.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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. - */ - -// -// Sortable array of strings. STL-ish, but STL-free. -// -#ifndef _LIBS_MEDIA_STRING_ARRAY_H -#define _LIBS_MEDIA_STRING_ARRAY_H - -#include -#include - -namespace android { - -// -// An expanding array of strings. Add, get, sort, delete. -// -class StringArray { -public: - StringArray(); - virtual ~StringArray(); - - // - // Add a string. A copy of the string is made. - // - bool push_back(const char* str); - - // - // Delete an entry. - // - void erase(int idx); - - // - // Sort the array. - // - void sort(int (*compare)(const void*, const void*)); - - // - // Pass this to the sort routine to do an ascending alphabetical sort. - // - static int cmpAscendingAlpha(const void* pstr1, const void* pstr2); - - // - // Get the #of items in the array. - // - inline int size(void) const { return mCurrent; } - - // - // Return entry N. - // [should use operator[] here] - // - const char* getEntry(int idx) const { - return (unsigned(idx) >= unsigned(mCurrent)) ? NULL : mArray[idx]; - } - - // - // Set entry N to specified string. - // [should use operator[] here] - // - void setEntry(int idx, const char* str); - -private: - int mMax; - int mCurrent; - char** mArray; -}; - -}; // namespace android - -#endif // _LIBS_MEDIA_STRING_ARRAY_H diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index be9af5e..193f8a7 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -62,6 +62,7 @@ LOCAL_SRC_FILES:= \ avc_utils.cpp \ LOCAL_C_INCLUDES:= \ + $(TOP)/frameworks/av/include/media/ \ $(TOP)/frameworks/av/include/media/stagefright/timedtext \ $(TOP)/frameworks/native/include/media/hardware \ $(TOP)/frameworks/native/include/media/openmax \ @@ -70,6 +71,8 @@ LOCAL_C_INCLUDES:= \ $(TOP)/external/openssl/include \ $(TOP)/external/libvpx/libwebm \ $(TOP)/system/netd/include \ + $(TOP)/external/icu/icu4c/source/common \ + $(TOP)/external/icu/icu4c/source/i18n \ LOCAL_SHARED_LIBRARIES := \ libbinder \ diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index 8cc41e7..101fc8a 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -32,6 +32,7 @@ #include #include #include +#include namespace android { @@ -450,32 +451,58 @@ void StagefrightMetadataRetriever::parseMetaData() { struct Map { int from; int to; + const char *name; }; static const Map kMap[] = { - { kKeyMIMEType, METADATA_KEY_MIMETYPE }, - { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER }, - { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER }, - { kKeyAlbum, METADATA_KEY_ALBUM }, - { kKeyArtist, METADATA_KEY_ARTIST }, - { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST }, - { kKeyAuthor, METADATA_KEY_AUTHOR }, - { kKeyComposer, METADATA_KEY_COMPOSER }, - { kKeyDate, METADATA_KEY_DATE }, - { kKeyGenre, METADATA_KEY_GENRE }, - { kKeyTitle, METADATA_KEY_TITLE }, - { kKeyYear, METADATA_KEY_YEAR }, - { kKeyWriter, METADATA_KEY_WRITER }, - { kKeyCompilation, METADATA_KEY_COMPILATION }, - { kKeyLocation, METADATA_KEY_LOCATION }, + { kKeyMIMEType, METADATA_KEY_MIMETYPE, NULL }, + { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER, "tracknumber" }, + { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER, "discnumber" }, + { kKeyAlbum, METADATA_KEY_ALBUM, "album" }, + { kKeyArtist, METADATA_KEY_ARTIST, "artist" }, + { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST, "albumartist" }, + { kKeyAuthor, METADATA_KEY_AUTHOR, NULL }, + { kKeyComposer, METADATA_KEY_COMPOSER, "composer" }, + { kKeyDate, METADATA_KEY_DATE, NULL }, + { kKeyGenre, METADATA_KEY_GENRE, "genre" }, + { kKeyTitle, METADATA_KEY_TITLE, "title" }, + { kKeyYear, METADATA_KEY_YEAR, "year" }, + { kKeyWriter, METADATA_KEY_WRITER, "writer" }, + { kKeyCompilation, METADATA_KEY_COMPILATION, "compilation" }, + { kKeyLocation, METADATA_KEY_LOCATION, NULL }, }; + static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]); + CharacterEncodingDetector *detector = new CharacterEncodingDetector(); + for (size_t i = 0; i < kNumMapEntries; ++i) { const char *value; if (meta->findCString(kMap[i].from, &value)) { - mMetaData.add(kMap[i].to, String8(value)); + if (kMap[i].name) { + // add to charset detector + detector->addTag(kMap[i].name, value); + } else { + // directly add to output list + mMetaData.add(kMap[i].to, String8(value)); + } + } + } + + detector->detectAndConvert(); + int size = detector->size(); + if (size) { + for (int i = 0; i < size; i++) { + const char *name; + const char *value; + detector->getTag(i, &name, &value); + for (size_t j = 0; j < kNumMapEntries; ++j) { + if (kMap[j].name && !strcmp(kMap[j].name, name)) { + mMetaData.add(kMap[j].to, String8(value)); + } + } } } + delete detector; const void *data; uint32_t type; -- cgit v1.1 From fbe8bef8bcf7aed97f0332908a817b0e6d91b9ba Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Fri, 29 Aug 2014 18:34:17 -0700 Subject: render one video frame after flush even when we're paused allows the video to get some update when user seeks while paused. Bug: 17140448 Change-Id: I064806bfd566585eeb4150a508422c9775e08f99 --- .../nuplayer/NuPlayerRenderer.cpp | 43 ++++++++++++++-------- .../nuplayer/NuPlayerRenderer.h | 1 + 2 files changed, 29 insertions(+), 15 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index bf6b3df..e642dc2 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -58,7 +58,8 @@ NuPlayer::Renderer::Renderer( mVideoRenderingStartGeneration(0), mAudioRenderingStartGeneration(0), mLastPositionUpdateUs(-1ll), - mVideoLateByUs(0ll) { + mVideoLateByUs(0ll), + mVideoSampleReceived(false) { } NuPlayer::Renderer::~Renderer() { @@ -491,7 +492,9 @@ int64_t NuPlayer::Renderer::getAudioPendingPlayoutUs() { } void NuPlayer::Renderer::postDrainVideoQueue() { - if (mDrainVideoQueuePending || mSyncQueues || mPaused) { + if (mDrainVideoQueuePending + || mSyncQueues + || (mPaused && mVideoSampleReceived)) { return; } @@ -570,16 +573,22 @@ void NuPlayer::Renderer::onDrainVideoQueue() { realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs; } - mVideoLateByUs = ALooper::GetNowUs() - realTimeUs; - bool tooLate = (mVideoLateByUs > 40000); + bool tooLate = false; - if (tooLate) { - ALOGV("video late by %lld us (%.2f secs)", - mVideoLateByUs, mVideoLateByUs / 1E6); + if (!mPaused) { + mVideoLateByUs = ALooper::GetNowUs() - realTimeUs; + tooLate = (mVideoLateByUs > 40000); + + if (tooLate) { + ALOGV("video late by %lld us (%.2f secs)", + mVideoLateByUs, mVideoLateByUs / 1E6); + } else { + ALOGV("rendering video at media time %.2f secs", + (mFlags & FLAG_REAL_TIME ? realTimeUs : + (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6); + } } else { - ALOGV("rendering video at media time %.2f secs", - (mFlags & FLAG_REAL_TIME ? realTimeUs : - (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6); + mVideoLateByUs = 0ll; } entry->mNotifyConsumed->setInt32("render", !tooLate); @@ -587,12 +596,15 @@ void NuPlayer::Renderer::onDrainVideoQueue() { mVideoQueue.erase(mVideoQueue.begin()); entry = NULL; - if (!mVideoRenderingStarted) { - mVideoRenderingStarted = true; - notifyVideoRenderingStart(); - } + mVideoSampleReceived = true; - notifyIfMediaRenderingStarted(); + if (!mPaused) { + if (!mVideoRenderingStarted) { + mVideoRenderingStarted = true; + notifyVideoRenderingStart(); + } + notifyIfMediaRenderingStarted(); + } notifyPosition(); } @@ -791,6 +803,7 @@ void NuPlayer::Renderer::onFlush(const sp &msg) { prepareForMediaRenderingStart(); } + mVideoSampleReceived = false; notifyFlushComplete(audio); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 8da6458..5c7d2d7 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -119,6 +119,7 @@ private: bool mSyncQueues; bool mPaused; + bool mVideoSampleReceived; bool mVideoRenderingStarted; int32_t mVideoRenderingStartGeneration; int32_t mAudioRenderingStartGeneration; -- cgit v1.1 From ac428aa54d2489705091dd38372bbaade281a92e Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Tue, 2 Sep 2014 19:01:34 -0700 Subject: NuPlayer: add seek operation when change video texture surface. Bug: 17278770 Change-Id: I9fd5207e1eccb91e64644d2d1da4183d4bf7ac2c --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 4 ++++ media/libmediaplayerservice/nuplayer/NuPlayer.h | 1 + 2 files changed, 5 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 76d25de..ae22123 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -145,6 +145,7 @@ private: NuPlayer::NuPlayer() : mUIDValid(false), mSourceFlags(0), + mCurrentPositionUs(0), mVideoIsAVC(false), mOffloadAudio(false), mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER), @@ -540,6 +541,8 @@ void NuPlayer::onMessageReceived(const sp &msg) { static_cast(obj.get()))); if (obj != NULL) { + mDeferredActions.push_back(new SeekAction(mCurrentPositionUs)); + // If there is a new surface texture, instantiate decoders // again if possible. mDeferredActions.push_back( @@ -860,6 +863,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { } else if (what == Renderer::kWhatPosition) { int64_t positionUs; CHECK(msg->findInt64("positionUs", &positionUs)); + mCurrentPositionUs = positionUs; CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs)); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 511d752..0c7f531 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -121,6 +121,7 @@ private: sp mSource; uint32_t mSourceFlags; sp mNativeWindow; + int64_t mCurrentPositionUs; sp mAudioSink; sp mVideoDecoder; bool mVideoIsAVC; -- cgit v1.1 From 50f939d655a5156157564cb91434f1cce424b2dd Mon Sep 17 00:00:00 2001 From: hkuang Date: Tue, 2 Sep 2014 13:57:31 -0700 Subject: Fix the bug that same video frame has been decoded twice during port reconfig. This does not hurt normal video playback. But in adaptive playback, this will lead to a little bit delay for some clips. Bug: 17202935 Change-Id: I5af0a5911e28a1597c74d79960fac25faf72c9d2 --- media/libstagefright/codecs/on2/dec/SoftVPX.cpp | 64 ++++++++++++------------- media/libstagefright/codecs/on2/dec/SoftVPX.h | 6 +++ 2 files changed, 38 insertions(+), 32 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp index a4258dd..2f63bdd 100644 --- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp +++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp @@ -23,9 +23,6 @@ #include #include -#include "vpx/vpx_decoder.h" -#include "vpx/vpx_codec.h" -#include "vpx/vp8dx.h" namespace android { @@ -41,7 +38,8 @@ SoftVPX::SoftVPX( NULL /* profileLevels */, 0 /* numProfileLevels */, 320 /* width */, 240 /* height */, callbacks, appData, component), mMode(codingType == OMX_VIDEO_CodingVP8 ? MODE_VP8 : MODE_VP9), - mCtx(NULL) { + mCtx(NULL), + mImg(NULL) { initPorts(kNumBuffers, 768 * 1024 /* inputBufferSize */, kNumBuffers, codingType == OMX_VIDEO_CodingVP8 ? MEDIA_MIMETYPE_VIDEO_VP8 : MEDIA_MIMETYPE_VIDEO_VP9); @@ -118,26 +116,27 @@ void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) { } } - if (vpx_codec_decode( - (vpx_codec_ctx_t *)mCtx, - inHeader->pBuffer + inHeader->nOffset, - inHeader->nFilledLen, - NULL, - 0)) { - ALOGE("on2 decoder failed to decode frame."); + if (mImg == NULL) { + if (vpx_codec_decode( + (vpx_codec_ctx_t *)mCtx, + inHeader->pBuffer + inHeader->nOffset, + inHeader->nFilledLen, + NULL, + 0)) { + ALOGE("on2 decoder failed to decode frame."); - notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); - return; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } + vpx_codec_iter_t iter = NULL; + mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter); } - vpx_codec_iter_t iter = NULL; - vpx_image_t *img = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter); - - if (img != NULL) { - CHECK_EQ(img->fmt, IMG_FMT_I420); + if (mImg != NULL) { + CHECK_EQ(mImg->fmt, IMG_FMT_I420); - uint32_t width = img->d_w; - uint32_t height = img->d_h; + uint32_t width = mImg->d_w; + uint32_t height = mImg->d_h; if (width != mWidth || height != mHeight) { mWidth = width; @@ -171,34 +170,35 @@ void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) { uint32_t buffer_stride = mIsAdaptive ? mAdaptiveMaxWidth : mWidth; uint32_t buffer_height = mIsAdaptive ? mAdaptiveMaxHeight : mHeight; - const uint8_t *srcLine = (const uint8_t *)img->planes[PLANE_Y]; + const uint8_t *srcLine = (const uint8_t *)mImg->planes[PLANE_Y]; uint8_t *dst = outHeader->pBuffer; for (size_t i = 0; i < buffer_height; ++i) { - if (i < img->d_h) { - memcpy(dst, srcLine, img->d_w); - srcLine += img->stride[PLANE_Y]; + if (i < mImg->d_h) { + memcpy(dst, srcLine, mImg->d_w); + srcLine += mImg->stride[PLANE_Y]; } dst += buffer_stride; } - srcLine = (const uint8_t *)img->planes[PLANE_U]; + srcLine = (const uint8_t *)mImg->planes[PLANE_U]; for (size_t i = 0; i < buffer_height / 2; ++i) { - if (i < img->d_h / 2) { - memcpy(dst, srcLine, img->d_w / 2); - srcLine += img->stride[PLANE_U]; + if (i < mImg->d_h / 2) { + memcpy(dst, srcLine, mImg->d_w / 2); + srcLine += mImg->stride[PLANE_U]; } dst += buffer_stride / 2; } - srcLine = (const uint8_t *)img->planes[PLANE_V]; + srcLine = (const uint8_t *)mImg->planes[PLANE_V]; for (size_t i = 0; i < buffer_height / 2; ++i) { - if (i < img->d_h / 2) { - memcpy(dst, srcLine, img->d_w / 2); - srcLine += img->stride[PLANE_V]; + if (i < mImg->d_h / 2) { + memcpy(dst, srcLine, mImg->d_w / 2); + srcLine += mImg->stride[PLANE_V]; } dst += buffer_stride / 2; } + mImg = NULL; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.h b/media/libstagefright/codecs/on2/dec/SoftVPX.h index cd5eb28..8f68693 100644 --- a/media/libstagefright/codecs/on2/dec/SoftVPX.h +++ b/media/libstagefright/codecs/on2/dec/SoftVPX.h @@ -20,6 +20,10 @@ #include "SoftVideoDecoderOMXComponent.h" +#include "vpx/vpx_decoder.h" +#include "vpx/vpx_codec.h" +#include "vpx/vp8dx.h" + namespace android { struct SoftVPX : public SoftVideoDecoderOMXComponent { @@ -47,6 +51,8 @@ private: void *mCtx; + vpx_image_t *mImg; + status_t initDecoder(); DISALLOW_EVIL_CONSTRUCTORS(SoftVPX); -- cgit v1.1 From 48f36a07d1faa1b8ec0af5d12d3c18fbfcb9eb65 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Wed, 3 Sep 2014 23:28:52 +0000 Subject: Revert "Revert "disable AwesomePlayer for Ogg vorbis"" This reverts commit da65048e8e6f65ed9b3f23cda3f4554025c76fc4. Deadlock audio issues for NuPlayer have been resolved. Change-Id: I1853d367dc771a9396a9b2d48ff34e50c78c112c --- media/libmediaplayerservice/MediaPlayerFactory.cpp | 25 ++++++++++++---------- media/libmediaplayerservice/MediaPlayerFactory.h | 1 - 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp index dacb144..3e0fc0d 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.cpp +++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp @@ -60,7 +60,7 @@ status_t MediaPlayerFactory::registerFactory_l(IFactory* factory, return OK; } -player_type MediaPlayerFactory::getDefaultPlayerType() { +static player_type getDefaultPlayerType() { char value[PROPERTY_VALUE_MAX]; if (property_get("media.stagefright.use-awesome", value, NULL) && (!strcmp("1", value) || !strcasecmp("true", value))) { @@ -181,16 +181,19 @@ class StagefrightPlayerFactory : int64_t offset, int64_t /*length*/, float /*curScore*/) { - char buf[20]; - lseek(fd, offset, SEEK_SET); - read(fd, buf, sizeof(buf)); - lseek(fd, offset, SEEK_SET); - - uint32_t ident = *((uint32_t*)buf); - - // Ogg vorbis? - if (ident == 0x5367674f) // 'OggS' - return 1.0; + if (getDefaultPlayerType() + == STAGEFRIGHT_PLAYER) { + char buf[20]; + lseek(fd, offset, SEEK_SET); + read(fd, buf, sizeof(buf)); + lseek(fd, offset, SEEK_SET); + + uint32_t ident = *((uint32_t*)buf); + + // Ogg vorbis? + if (ident == 0x5367674f) // 'OggS' + return 1.0; + } return 0.0; } diff --git a/media/libmediaplayerservice/MediaPlayerFactory.h b/media/libmediaplayerservice/MediaPlayerFactory.h index 5ddde19..55ff918 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.h +++ b/media/libmediaplayerservice/MediaPlayerFactory.h @@ -71,7 +71,6 @@ class MediaPlayerFactory { static status_t registerFactory_l(IFactory* factory, player_type type); - static player_type getDefaultPlayerType(); static Mutex sLock; static tFactoryMap sFactoryMap; -- cgit v1.1 From 0f9a3cf9962b6859cfee9d4bf4676b5aafca79cb Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 29 Aug 2014 18:57:34 -0700 Subject: PlaylistFetcher: do not reset mStartTimeUs if we are resuming Bug: 17376049 Change-Id: Ie519bdf7128841172df41e6512d624e99d9853d6 --- media/libstagefright/httplive/PlaylistFetcher.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 4d5d79e..82a4c39 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -490,11 +490,11 @@ status_t PlaylistFetcher::onStart(const sp &msg) { mStreamTypeMask = streamTypeMask; - mStartTimeUs = startTimeUs; mSegmentStartTimeUs = segmentStartTimeUs; mDiscontinuitySeq = startDiscontinuitySeq; - if (mStartTimeUs >= 0ll) { + if (startTimeUs >= 0) { + mStartTimeUs = startTimeUs; mSeqNumber = -1; mStartup = true; mPrepared = false; -- cgit v1.1 From 17f6dd64cd749f4e38e12b672b551047f4cbe9b4 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 20 Aug 2014 17:00:21 -0700 Subject: GenericSource: refactor track selection for dedicated looper - move getFormatMeta, getSelectedTrack, selectTrack, and seekTo to dedicated looper - start & dequeueAccessUnit posts readBuffer requests instead of reading directly - call internal doGetFormatMeta in onPrepareAsync Bug: 16892748 Change-Id: I5d5e34381f1dfceca655c52a201627b53454ad22 --- .../nuplayer/GenericSource.cpp | 186 +++++++++++++++++++-- .../libmediaplayerservice/nuplayer/GenericSource.h | 19 +++ 2 files changed, 189 insertions(+), 16 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index f257ef3..8e1987a 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "../../libstagefright/include/DRMExtractor.h" #include "../../libstagefright/include/NuCachedSource2.h" #include "../../libstagefright/include/WVMExtractor.h" @@ -318,7 +319,14 @@ void NuPlayer::GenericSource::onPrepareAsync() { } if (mVideoTrack.mSource != NULL) { - notifyVideoSizeChanged(getFormat(false /* audio */)); + sp meta = doGetFormatMeta(false /* audio */); + sp msg = new AMessage; + err = convertMetaDataToMessage(meta, &msg); + if(err != OK) { + notifyPreparedAndCleanup(err); + return; + } + notifyVideoSizeChanged(msg); } notifyFlagsChanged( @@ -422,7 +430,7 @@ void NuPlayer::GenericSource::start() { mAudioTrack.mPackets = new AnotherPacketSource(mAudioTrack.mSource->getFormat()); - readBuffer(MEDIA_TRACK_TYPE_AUDIO); + postReadBuffer(MEDIA_TRACK_TYPE_AUDIO); } if (mVideoTrack.mSource != NULL) { @@ -430,7 +438,7 @@ void NuPlayer::GenericSource::start() { mVideoTrack.mPackets = new AnotherPacketSource(mVideoTrack.mSource->getFormat()); - readBuffer(MEDIA_TRACK_TYPE_VIDEO); + postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); } setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000); @@ -459,6 +467,8 @@ void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, i if (mDecryptHandle != NULL) { mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position); } + mSubtitleTrack.mPackets = new AnotherPacketSource(NULL); + mTimedTextTrack.mPackets = new AnotherPacketSource(NULL); } status_t NuPlayer::GenericSource::feedMoreTSData() { @@ -615,6 +625,37 @@ void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { } break; } + + case kWhatGetFormat: + { + onGetFormatMeta(msg); + break; + } + + case kWhatGetSelectedTrack: + { + onGetSelectedTrack(msg); + break; + } + + case kWhatSelectTrack: + { + onSelectTrack(msg); + break; + } + + case kWhatSeek: + { + onSeek(msg); + break; + } + + case kWhatReadBuffer: + { + onReadBuffer(msg); + break; + } + default: Source::onMessageReceived(msg); break; @@ -690,6 +731,34 @@ void NuPlayer::GenericSource::sendTextData( } sp NuPlayer::GenericSource::getFormatMeta(bool audio) { + sp msg = new AMessage(kWhatGetFormat, id()); + msg->setInt32("audio", audio); + + sp response; + void *format; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findPointer("format", &format)); + return (MetaData *)format; + } else { + return NULL; + } +} + +void NuPlayer::GenericSource::onGetFormatMeta(sp msg) const { + int32_t audio; + CHECK(msg->findInt32("audio", &audio)); + + sp response = new AMessage; + sp format = doGetFormatMeta(audio); + response->setPointer("format", format.get()); + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + response->postReply(replyID); +} + +sp NuPlayer::GenericSource::doGetFormatMeta(bool audio) const { sp source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; if (source == NULL) { @@ -709,7 +778,7 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( if (mIsWidevine && !audio) { // try to read a buffer as we may not have been able to the last time - readBuffer(MEDIA_TRACK_TYPE_VIDEO, -1ll); + postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); } status_t finalResult; @@ -720,18 +789,7 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( status_t result = track->mPackets->dequeueAccessUnit(accessUnit); if (!track->mPackets->hasBufferAvailable(&finalResult)) { - readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll); - } - - if (mSubtitleTrack.mSource == NULL && mTimedTextTrack.mSource == NULL) { - return result; - } - - if (mSubtitleTrack.mSource != NULL) { - CHECK(mSubtitleTrack.mPackets != NULL); - } - if (mTimedTextTrack.mSource != NULL) { - CHECK(mTimedTextTrack.mPackets != NULL); + postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); } if (result != OK) { @@ -825,6 +883,35 @@ sp NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { } ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { + sp msg = new AMessage(kWhatGetSelectedTrack, id()); + msg->setInt32("type", type); + + sp response; + int32_t index; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("index", &index)); + return index; + } else { + return -1; + } +} + +void NuPlayer::GenericSource::onGetSelectedTrack(sp msg) const { + int32_t tmpType; + CHECK(msg->findInt32("type", &tmpType)); + media_track_type type = (media_track_type)tmpType; + + sp response = new AMessage; + ssize_t index = doGetSelectedTrack(type); + response->setInt32("index", index); + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + response->postReply(replyID); +} + +ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const { const Track *track = NULL; switch (type) { case MEDIA_TRACK_TYPE_VIDEO: @@ -852,6 +939,34 @@ ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); + sp msg = new AMessage(kWhatSelectTrack, id()); + msg->setInt32("trackIndex", trackIndex); + msg->setInt32("select", trackIndex); + + sp response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + } + + return err; +} + +void NuPlayer::GenericSource::onSelectTrack(sp msg) { + int32_t trackIndex, select; + CHECK(msg->findInt32("trackIndex", &trackIndex)); + CHECK(msg->findInt32("select", &select)); + + sp response = new AMessage; + status_t err = doSelectTrack(trackIndex, select); + response->setInt32("err", err); + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + response->postReply(replyID); +} + +status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select) { if (trackIndex >= mSources.size()) { return BAD_INDEX; } @@ -922,6 +1037,32 @@ status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { } status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { + sp msg = new AMessage(kWhatSeek, id()); + msg->setInt64("seekTimeUs", seekTimeUs); + + sp response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + } + + return err; +} + +void NuPlayer::GenericSource::onSeek(sp msg) { + int64_t seekTimeUs; + CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); + + sp response = new AMessage; + status_t err = doSeek(seekTimeUs); + response->setInt32("err", err); + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + response->postReply(replyID); +} + +status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) { if (mVideoTrack.mSource != NULL) { int64_t actualTimeUs; readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs); @@ -1006,6 +1147,19 @@ sp NuPlayer::GenericSource::mediaBufferToABuffer( return ab; } +void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) { + sp msg = new AMessage(kWhatReadBuffer, id()); + msg->setInt32("trackType", trackType); + msg->post(); +} + +void NuPlayer::GenericSource::onReadBuffer(sp msg) { + int32_t tmpType; + CHECK(msg->findInt32("trackType", &tmpType)); + media_track_type trackType = (media_track_type)tmpType; + readBuffer(trackType); +} + void NuPlayer::GenericSource::readBuffer( media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) { Track *track; diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 1f13120..50ff98a 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -84,6 +84,11 @@ private: kWhatSendTimedTextData, kWhatChangeAVSource, kWhatPollBuffering, + kWhatGetFormat, + kWhatGetSelectedTrack, + kWhatSelectTrack, + kWhatSeek, + kWhatReadBuffer, }; Vector > mSources; @@ -140,6 +145,18 @@ private: void notifyPreparedAndCleanup(status_t err); + void onGetFormatMeta(sp msg) const; + sp doGetFormatMeta(bool audio) const; + + void onGetSelectedTrack(sp msg) const; + ssize_t doGetSelectedTrack(media_track_type type) const; + + void onSelectTrack(sp msg); + status_t doSelectTrack(size_t trackIndex, bool select); + + void onSeek(sp msg); + status_t doSeek(int64_t seekTimeUs); + void onPrepareAsync(); void fetchTextData( @@ -155,6 +172,8 @@ private: media_track_type trackType, int64_t *actualTimeUs = NULL); + void postReadBuffer(media_track_type trackType); + void onReadBuffer(sp msg); void readBuffer( media_track_type trackType, int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL, bool formatChange = false); -- cgit v1.1 From b86e68f834b7040518b99d1d0245d5f2e5cb9c86 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Fri, 1 Aug 2014 13:46:53 -0700 Subject: Split CEA-608 Closed caption into 4 tracks CC1~CC4 Bug: 16463078 Change-Id: Ib3073090934232016e535fbb8fa56cdf9d7ab6eb --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 4 + .../nuplayer/NuPlayerDecoder.cpp | 185 ++++++++++++++------- .../nuplayer/NuPlayerDecoder.h | 12 +- 3 files changed, 134 insertions(+), 67 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index ae22123..bfe2710 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1540,6 +1540,10 @@ void NuPlayer::flushDecoder( ALOGE_IF(mFlushingVideo != NONE, "video flushDecoder() is called in state %d", mFlushingVideo); mFlushingVideo = newStatus; + + if (mCCDecoder != NULL) { + mCCDecoder->flush(); + } } } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 5aaf48c..8ce7baf 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -716,72 +716,28 @@ bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp &targetF return seamless; } -struct NuPlayer::CCDecoder::CCData { +struct CCData { CCData(uint8_t type, uint8_t data1, uint8_t data2) : mType(type), mData1(data1), mData2(data2) { } + bool getChannel(size_t *channel) const { + if (mData1 >= 0x10 && mData1 <= 0x1f) { + *channel = (mData1 >= 0x18 ? 1 : 0) + (mType ? 2 : 0); + return true; + } + return false; + } uint8_t mType; uint8_t mData1; uint8_t mData2; }; -NuPlayer::CCDecoder::CCDecoder(const sp ¬ify) - : mNotify(notify), - mTrackCount(0), - mSelectedTrack(-1) { -} - -size_t NuPlayer::CCDecoder::getTrackCount() const { - return mTrackCount; -} - -sp NuPlayer::CCDecoder::getTrackInfo(size_t index) const { - CHECK(index == 0); - - sp format = new AMessage(); - - format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE); - format->setString("language", "und"); - format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608); - format->setInt32("auto", 1); - format->setInt32("default", 1); - format->setInt32("forced", 0); - - return format; -} - -status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) { - CHECK(index < mTrackCount); - - if (select) { - if (mSelectedTrack == (ssize_t)index) { - ALOGE("track %zu already selected", index); - return BAD_VALUE; - } - ALOGV("selected track %zu", index); - mSelectedTrack = index; - } else { - if (mSelectedTrack != (ssize_t)index) { - ALOGE("track %zu is not selected", index); - return BAD_VALUE; - } - ALOGV("unselected track %zu", index); - mSelectedTrack = -1; - } - - return OK; -} - -bool NuPlayer::CCDecoder::isSelected() const { - return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)mTrackCount; -} - -bool NuPlayer::CCDecoder::isNullPad(CCData *cc) const { +static bool isNullPad(CCData *cc) { return cc->mData1 < 0x10 && cc->mData2 < 0x10; } -void NuPlayer::CCDecoder::dumpBytePair(const sp &ccBuf) const { +static void dumpBytePair(const sp &ccBuf) { size_t offset = 0; AString out; @@ -843,6 +799,78 @@ void NuPlayer::CCDecoder::dumpBytePair(const sp &ccBuf) const { ALOGI("%s", out.c_str()); } +NuPlayer::CCDecoder::CCDecoder(const sp ¬ify) + : mNotify(notify), + mCurrentChannel(0), + mSelectedTrack(-1) { + for (size_t i = 0; i < sizeof(mTrackIndices)/sizeof(mTrackIndices[0]); ++i) { + mTrackIndices[i] = -1; + } +} + +size_t NuPlayer::CCDecoder::getTrackCount() const { + return mFoundChannels.size(); +} + +sp NuPlayer::CCDecoder::getTrackInfo(size_t index) const { + if (!isTrackValid(index)) { + return NULL; + } + + sp format = new AMessage(); + + format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE); + format->setString("language", "und"); + format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608); + //CC1, field 0 channel 0 + bool isDefaultAuto = (mFoundChannels[index] == 0); + format->setInt32("auto", isDefaultAuto); + format->setInt32("default", isDefaultAuto); + format->setInt32("forced", 0); + + return format; +} + +status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) { + if (!isTrackValid(index)) { + return BAD_VALUE; + } + + if (select) { + if (mSelectedTrack == (ssize_t)index) { + ALOGE("track %zu already selected", index); + return BAD_VALUE; + } + ALOGV("selected track %zu", index); + mSelectedTrack = index; + } else { + if (mSelectedTrack != (ssize_t)index) { + ALOGE("track %zu is not selected", index); + return BAD_VALUE; + } + ALOGV("unselected track %zu", index); + mSelectedTrack = -1; + } + + return OK; +} + +bool NuPlayer::CCDecoder::isSelected() const { + return mSelectedTrack >= 0 && mSelectedTrack < (int32_t) getTrackCount(); +} + +bool NuPlayer::CCDecoder::isTrackValid(size_t index) const { + return index < getTrackCount(); +} + +int32_t NuPlayer::CCDecoder::getTrackIndex(size_t channel) const { + if (channel < sizeof(mTrackIndices)/sizeof(mTrackIndices[0])) { + return mTrackIndices[channel]; + } + return -1; +} + +// returns true if a new CC track is found bool NuPlayer::CCDecoder::extractFromSEI(const sp &accessUnit) { int64_t timeUs; CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); @@ -852,7 +880,7 @@ bool NuPlayer::CCDecoder::extractFromSEI(const sp &accessUnit) { return false; } - bool hasCC = false; + bool trackAdded = false; NALBitReader br(sei->data() + 1, sei->size() - 1); // sei_message() @@ -887,8 +915,6 @@ bool NuPlayer::CCDecoder::extractFromSEI(const sp &accessUnit) { && itu_t_t35_provider_code == 0x0031 && user_identifier == 'GA94' && user_data_type_code == 0x3) { - hasCC = true; - // MPEG_cc_data() // ATSC A/53 Part 4: 6.2.3.1 br.skipBits(1); //process_em_data_flag @@ -918,6 +944,12 @@ bool NuPlayer::CCDecoder::extractFromSEI(const sp &accessUnit) { && (cc_type == 0 || cc_type == 1)) { CCData cc(cc_type, cc_data_1, cc_data_2); if (!isNullPad(&cc)) { + size_t channel; + if (cc.getChannel(&channel) && getTrackIndex(channel) < 0) { + mTrackIndices[channel] = mFoundChannels.size(); + mFoundChannels.push_back(channel); + trackAdded = true; + } memcpy(ccBuf->data() + ccBuf->size(), (void *)&cc, sizeof(cc)); ccBuf->setRange(0, ccBuf->size() + sizeof(CCData)); @@ -940,13 +972,33 @@ bool NuPlayer::CCDecoder::extractFromSEI(const sp &accessUnit) { br.skipBits(payload_size * 8); } - return hasCC; + return trackAdded; } -void NuPlayer::CCDecoder::decode(const sp &accessUnit) { - if (extractFromSEI(accessUnit) && mTrackCount == 0) { - mTrackCount++; +sp NuPlayer::CCDecoder::filterCCBuf( + const sp &ccBuf, size_t index) { + sp filteredCCBuf = new ABuffer(ccBuf->size()); + filteredCCBuf->setRange(0, 0); + + size_t cc_count = ccBuf->size() / sizeof(CCData); + const CCData* cc_data = (const CCData*)ccBuf->data(); + for (size_t i = 0; i < cc_count; ++i) { + size_t channel; + if (cc_data[i].getChannel(&channel)) { + mCurrentChannel = channel; + } + if (mCurrentChannel == mFoundChannels[index]) { + memcpy(filteredCCBuf->data() + filteredCCBuf->size(), + (void *)&cc_data[i], sizeof(CCData)); + filteredCCBuf->setRange(0, filteredCCBuf->size() + sizeof(CCData)); + } + } + + return filteredCCBuf; +} +void NuPlayer::CCDecoder::decode(const sp &accessUnit) { + if (extractFromSEI(accessUnit)) { ALOGI("Found CEA-608 track"); sp msg = mNotify->dup(); msg->setInt32("what", kWhatTrackAdded); @@ -956,13 +1008,18 @@ void NuPlayer::CCDecoder::decode(const sp &accessUnit) { } void NuPlayer::CCDecoder::display(int64_t timeUs) { + if (!isTrackValid(mSelectedTrack)) { + ALOGE("Could not find current track(index=%d)", mSelectedTrack); + return; + } + ssize_t index = mCCMap.indexOfKey(timeUs); if (index < 0) { ALOGV("cc for timestamp %" PRId64 " not found", timeUs); return; } - sp &ccBuf = mCCMap.editValueAt(index); + sp ccBuf = filterCCBuf(mCCMap.valueAt(index), mSelectedTrack); if (ccBuf->size() > 0) { #if 0 @@ -983,5 +1040,9 @@ void NuPlayer::CCDecoder::display(int64_t timeUs) { mCCMap.removeItemsAt(0, index + 1); } +void NuPlayer::CCDecoder::flush() { + mCCMap.clear(); +} + } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index 67bddb8..cc1bdff 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -126,18 +126,20 @@ struct NuPlayer::CCDecoder : public RefBase { bool isSelected() const; void decode(const sp &accessUnit); void display(int64_t timeUs); + void flush(); private: - struct CCData; - sp mNotify; KeyedVector > mCCMap; - size_t mTrackCount; + size_t mCurrentChannel; int32_t mSelectedTrack; + int32_t mTrackIndices[4]; + Vector mFoundChannels; - bool isNullPad(CCData *cc) const; - void dumpBytePair(const sp &ccBuf) const; + bool isTrackValid(size_t index) const; + int32_t getTrackIndex(size_t channel) const; bool extractFromSEI(const sp &accessUnit); + sp filterCCBuf(const sp &ccBuf, size_t index); DISALLOW_EVIL_CONSTRUCTORS(CCDecoder); }; -- cgit v1.1 From 5da491bb05009e2062d8a98a153594bb3ff15188 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 4 Sep 2014 11:45:26 -0700 Subject: stagefright: allow P-frames spacing of 0 and 1 Bug: 17387418 Change-Id: Ib966496b4ca220d96fb3741c29002c13cd2db848 --- media/libstagefright/ACodec.cpp | 1 - media/libstagefright/OMXCodec.cpp | 1 - 2 files changed, 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 19a5908..9b03b71 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -2313,7 +2313,6 @@ static OMX_U32 setPFramesSpacing(int32_t iFramesInterval, int32_t frameRate) { return 0; } OMX_U32 ret = frameRate * iFramesInterval; - CHECK(ret > 1); return ret; } diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 78758da..a8806c8 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -994,7 +994,6 @@ static OMX_U32 setPFramesSpacing(int32_t iFramesInterval, int32_t frameRate) { return 0; } OMX_U32 ret = frameRate * iFramesInterval - 1; - CHECK(ret > 1); return ret; } -- cgit v1.1 From adf34bf9b7925f990259b1b6f4c69b8668f76ead Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Wed, 3 Sep 2014 18:22:22 -0700 Subject: NuPlayer: Discard seeks when source and decoders are NULL Problem occurs when loop mode asynchronously seeks to the start of the source after a MediaPlayer::reset(). Bug: 17379148 Change-Id: I50bfe65a753afffb1d478db54c76067a9c61a0ae --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 8 ++++++++ media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index ae22123..cf4757e 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1665,6 +1665,14 @@ void NuPlayer::performSeek(int64_t seekTimeUs) { seekTimeUs, seekTimeUs / 1E6); + if (mSource == NULL) { + // This happens when reset occurs right before the loop mode + // asynchronously seeks to the start of the stream. + LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL, + "mSource is NULL and decoders not NULL audio(%p) video(%p)", + mAudioDecoder.get(), mVideoDecoder.get()); + return; + } mSource->seekTo(seekTimeUs); ++mTimedTextGeneration; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 2423f5f..09324ae 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -626,7 +626,7 @@ void NuPlayerDriver::notifyListener_l( switch (msg) { case MEDIA_PLAYBACK_COMPLETE: { - if (mLooping) { + if (mLooping && mState != STATE_RESET_IN_PROGRESS) { mLock.unlock(); mPlayer->seekToAsync(0); mLock.lock(); -- cgit v1.1 From 4f418f9705d6c247b645cbcf255a3f56e665d216 Mon Sep 17 00:00:00 2001 From: Hyejin Kim Date: Fri, 5 Sep 2014 15:50:03 +0900 Subject: Fix to parse audio_source_t member of audio_attributes_t When unmarshalling audio_attributes_t typed data, it didn't parse the audio_source_t member between content_type and flags. Bug: 16906307 Change-Id: Ia0d8df9b5c31441d34dc82678bceccd8ce31423d --- media/libmediaplayerservice/MediaPlayerService.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index b5bd988..c8cb7ed 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -204,6 +204,8 @@ const int32_t kAudioAttributesMarshallTagFlattenTags = 1; // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | content_type | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | source | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | flags | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | kAudioAttributesMarshallTagFlattenTags | // ignore tags if not found @@ -219,6 +221,7 @@ void unmarshallAudioAttributes(const Parcel& parcel, audio_attributes_t *attribu { attributes->usage = (audio_usage_t) parcel.readInt32(); attributes->content_type = (audio_content_type_t) parcel.readInt32(); + attributes->source = (audio_source_t) parcel.readInt32(); attributes->flags = (audio_flags_mask_t) parcel.readInt32(); const bool hasFlattenedTag = (parcel.readInt32() == kAudioAttributesMarshallTagFlattenTags); if (hasFlattenedTag) { -- cgit v1.1 From 7353585789513466d5887986620e8734a325b3eb Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Fri, 5 Sep 2014 11:42:58 -0700 Subject: NuPlayer: Restrict seek on video texture changes MediaPlayer::setVideoSurfaceTexture() should generate seek to refresh display only if player is started and has video. Bug: 17379148 Bug: 17404923 Change-Id: I5f55dc40943e4419d08be6fdab964b8a2c5ee519 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index cf4757e..d2518a8 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -541,7 +541,13 @@ void NuPlayer::onMessageReceived(const sp &msg) { static_cast(obj.get()))); if (obj != NULL) { - mDeferredActions.push_back(new SeekAction(mCurrentPositionUs)); + if (mStarted && mVideoDecoder != NULL) { + // Issue a seek to refresh the video screen only if started otherwise + // the extractor may not yet be started and will assert. + // If the video decoder is not set (perhaps audio only in this case) + // do not perform a seek as it is not needed. + mDeferredActions.push_back(new SeekAction(mCurrentPositionUs)); + } // If there is a new surface texture, instantiate decoders // again if possible. -- cgit v1.1 From 640adb3cf89cc9b826372009fad8c9b3d120482e Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Fri, 5 Sep 2014 11:20:11 -0700 Subject: Cache audio attributes when player not available Cache the audio attributes stored in a Parcel in the client-side MediaPlayer object if they are set through setParameter() before the server-side MediaPlayer is available. Apply them when the player is prepared. Bug 17280746 Change-Id: I72f1a7fc4e2b076fae8cbdede77a2f74e98b2a03 --- media/libmedia/mediaplayer.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 6cd377a..9611ac7 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -50,6 +50,7 @@ MediaPlayer::MediaPlayer() mListener = NULL; mCookie = NULL; mStreamType = AUDIO_STREAM_MUSIC; + mAudioAttributesParcel = NULL; mCurrentPosition = -1; mSeekPosition = -1; mCurrentState = MEDIA_PLAYER_IDLE; @@ -68,6 +69,10 @@ MediaPlayer::MediaPlayer() MediaPlayer::~MediaPlayer() { ALOGV("destructor"); + if (mAudioAttributesParcel != NULL) { + delete mAudioAttributesParcel; + mAudioAttributesParcel = NULL; + } AudioSystem::releaseAudioSessionId(mAudioSessionId, -1); disconnect(); IPCThreadState::self()->flushCommands(); @@ -237,6 +242,9 @@ status_t MediaPlayer::prepareAsync_l() { if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) { mPlayer->setAudioStreamType(mStreamType); + if (mAudioAttributesParcel != NULL) { + mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel); + } mCurrentState = MEDIA_PLAYER_PREPARING; return mPlayer->prepareAsync(); } @@ -662,8 +670,17 @@ status_t MediaPlayer::setParameter(int key, const Parcel& request) if (mPlayer != NULL) { return mPlayer->setParameter(key, request); } - ALOGV("setParameter: no active player"); - return INVALID_OPERATION; + switch (key) { + case KEY_PARAMETER_AUDIO_ATTRIBUTES: + // no player, save the marshalled audio attributes + if (mAudioAttributesParcel != NULL) { delete mAudioAttributesParcel; }; + mAudioAttributesParcel = new Parcel(); + mAudioAttributesParcel->appendFrom(&request, 0, request.dataSize()); + return OK; + default: + ALOGV("setParameter: no active player"); + return INVALID_OPERATION; + } } status_t MediaPlayer::getParameter(int key, Parcel *reply) -- cgit v1.1 From 4ec6746804ad8172c8b1c4eb3e6deb19a0920734 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Fri, 5 Sep 2014 14:58:59 -0700 Subject: NuPlayerDriver: put player in paused state when reaching EOS. Bug: 17352759 Change-Id: I19b183e0a86b712524f79ec7c35e32b5a5b47bc6 --- media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 09324ae..35cd514 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -627,11 +627,11 @@ void NuPlayerDriver::notifyListener_l( case MEDIA_PLAYBACK_COMPLETE: { if (mLooping && mState != STATE_RESET_IN_PROGRESS) { - mLock.unlock(); mPlayer->seekToAsync(0); - mLock.lock(); break; } + mPlayer->pause(); + mState = STATE_PAUSED; // fall through } -- cgit v1.1 From 3abc2ded40066f3b1df23aceb553f22d569c5cd3 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 5 Sep 2014 16:45:52 -0700 Subject: Make IPowerManager native conform to .aidl for oneway But provide a temporary escape hatch for AudioFlinger. This oneway option will be removed as soon as possible. Bug: 16408906 Change-Id: I058a50906af810787e444a96819cb781b7f639ad --- media/libstagefright/TimedEventQueue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp index da50c56..1fdb244 100644 --- a/media/libstagefright/TimedEventQueue.cpp +++ b/media/libstagefright/TimedEventQueue.cpp @@ -338,7 +338,7 @@ void TimedEventQueue::acquireWakeLock_l() status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK, binder, String16("TimedEventQueue"), - String16("media")); + String16("media")); // not oneway IPCThreadState::self()->restoreCallingIdentity(token); if (status == NO_ERROR) { mWakeLockToken = binder; @@ -363,7 +363,7 @@ void TimedEventQueue::releaseWakeLock_l(bool force) CHECK(mWakeLockToken != 0); if (mPowerManager != 0) { int64_t token = IPCThreadState::self()->clearCallingIdentity(); - mPowerManager->releaseWakeLock(mWakeLockToken, 0); + mPowerManager->releaseWakeLock(mWakeLockToken, 0); // not oneway IPCThreadState::self()->restoreCallingIdentity(token); } mWakeLockToken.clear(); -- cgit v1.1 From 45452ffeb3827dd3c955aca1b4ab3522b70cf8cc Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 16 May 2014 12:22:35 -0700 Subject: DO NOT MERGE - MPEG4Extractor: parse csd correctly; workaround malformed csd Bug: 14895152 Change-Id: Ibfee9e176459099507589c26a5eca6c61caabd1c (cherry picked from commit bc413f6ad0023f7ad451a0129a07fc31dbc65665) --- media/libstagefright/MPEG4Extractor.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 0064293..1729f93 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -2810,7 +2810,6 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio( { if (objectType == AOT_SBR || objectType == AOT_PS) { - const int32_t extensionSamplingFrequency = br.getBits(4); objectType = br.getBits(5); if (objectType == AOT_ESCAPE) { @@ -2828,9 +2827,30 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio( const int32_t coreCoderDelay = br.getBits(14); } - const int32_t extensionFlag = br.getBits(1); + int32_t extensionFlag = -1; + if (br.numBitsLeft() > 0) { + extensionFlag = br.getBits(1); + } else { + switch (objectType) { + // 14496-3 4.5.1.1 extensionFlag + case AOT_AAC_LC: + extensionFlag = 0; + break; + case AOT_ER_AAC_LC: + case AOT_ER_AAC_SCAL: + case AOT_ER_BSAC: + case AOT_ER_AAC_LD: + extensionFlag = 1; + break; + default: + TRESPASS(); + break; + } + ALOGW("csd missing extension flag; assuming %d for object type %u.", + extensionFlag, objectType); + } - if (numChannels == 0 ) { + if (numChannels == 0) { int32_t channelsEffectiveNum = 0; int32_t channelsNum = 0; const int32_t ElementInstanceTag = br.getBits(4); -- cgit v1.1 From fa20a1db4be377a004efd756887f8b212e31d670 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 5 Sep 2014 09:28:24 -0700 Subject: Fix AAC timestamps for multiple aac frames per input buffer Support multiple aac frames per input buffer also for non-ADTS streams. Bug: 16715379 Change-Id: I84f33d9bb65b6821b2a697f6750356cea98777c4 --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 317 ++++++++++++++---------- media/libstagefright/codecs/aacdec/SoftAAC2.h | 5 +- 2 files changed, 194 insertions(+), 128 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 8b4dd6f..6dd9b92 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#define LOG_TAG "SoftAAC2" //#define LOG_NDEBUG 0 +#define LOG_TAG "SoftAAC2" #include #include "SoftAAC2.h" @@ -68,7 +68,6 @@ SoftAAC2::SoftAAC2( mOutputBufferCount(0), mSignalledError(false), mLastInHeader(NULL), - mCurrentInputTime(0), mOutputPortSettingsChange(NONE) { initPorts(); CHECK_EQ(initDecoder(), (status_t)OK); @@ -610,9 +609,24 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL); return; } + + // insert buffer size and time stamp + mBufferSizes.add(inBufferLength[0]); + if (mLastInHeader != inHeader) { + mBufferTimestamps.add(inHeader->nTimeStamp); + mLastInHeader = inHeader; + } else { + int64_t currentTime = mBufferTimestamps.top(); + currentTime += mStreamInfo->aacSamplesPerFrame * + 1000000ll / mStreamInfo->sampleRate; + mBufferTimestamps.add(currentTime); + } } else { inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; inBufferLength[0] = inHeader->nFilledLen; + mLastInHeader = inHeader; + mBufferTimestamps.add(inHeader->nTimeStamp); + mBufferSizes.add(inHeader->nFilledLen); } // Fill and decode @@ -621,136 +635,130 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { INT prevSampleRate = mStreamInfo->sampleRate; INT prevNumChannels = mStreamInfo->numChannels; - if (inHeader != mLastInHeader) { - mLastInHeader = inHeader; - mCurrentInputTime = inHeader->nTimeStamp; - } else { - if (mStreamInfo->sampleRate) { - mCurrentInputTime += mStreamInfo->aacSamplesPerFrame * - 1000000ll / mStreamInfo->sampleRate; - } else { - ALOGW("no sample rate yet"); - } - } - mAnchorTimes.add(mCurrentInputTime); aacDecoder_Fill(mAACDecoder, inBuffer, inBufferLength, bytesValid); - // run DRC check - mDrcWrap.submitStreamData(mStreamInfo); - mDrcWrap.update(); + // run DRC check + mDrcWrap.submitStreamData(mStreamInfo); + mDrcWrap.update(); - AAC_DECODER_ERROR decoderErr = - aacDecoder_DecodeFrame(mAACDecoder, - tmpOutBuffer, - 2048 * MAX_CHANNEL_COUNT, - 0 /* flags */); + UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; + inHeader->nFilledLen -= inBufferUsedLength; + inHeader->nOffset += inBufferUsedLength; - if (decoderErr != AAC_DEC_OK) { - ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); - } + AAC_DECODER_ERROR decoderErr; + do { + int numconsumed = mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes; + decoderErr = aacDecoder_DecodeFrame(mAACDecoder, + tmpOutBuffer, + 2048 * MAX_CHANNEL_COUNT, + 0 /* flags */); - if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { - ALOGE("AAC_DEC_NOT_ENOUGH_BITS should never happen"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); - return; - } + numconsumed = (mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes) - numconsumed; + if (numconsumed != 0) { + mDecodedSizes.add(numconsumed); + } - if (bytesValid[0] != 0) { - ALOGE("bytesValid[0] != 0 should never happen"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); - return; - } + if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { + break; + } - size_t numOutBytes = - mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; + if (decoderErr != AAC_DEC_OK) { + ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); + } - if (decoderErr == AAC_DEC_OK) { - if (!outputDelayRingBufferPutSamples(tmpOutBuffer, - mStreamInfo->frameSize * mStreamInfo->numChannels)) { + if (bytesValid[0] != 0) { + ALOGE("bytesValid[0] != 0 should never happen"); mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); return; } - UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; - inHeader->nFilledLen -= inBufferUsedLength; - inHeader->nOffset += inBufferUsedLength; - } else { - ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr); - memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow + size_t numOutBytes = + mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; - if (!outputDelayRingBufferPutSamples(tmpOutBuffer, - mStreamInfo->frameSize * mStreamInfo->numChannels)) { - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - return; - } + if (decoderErr == AAC_DEC_OK) { + if (!outputDelayRingBufferPutSamples(tmpOutBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels)) { + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; + } + } else { + ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr); - // Discard input buffer. - inHeader->nFilledLen = 0; - - aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); - - // fall through - } - - /* - * AAC+/eAAC+ streams can be signalled in two ways: either explicitly - * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual - * rate system and the sampling rate in the final output is actually - * doubled compared with the core AAC decoder sampling rate. - * - * Explicit signalling is done by explicitly defining SBR audio object - * type in the bitstream. Implicit signalling is done by embedding - * SBR content in AAC extension payload specific to SBR, and hence - * requires an AAC decoder to perform pre-checks on actual audio frames. - * - * Thus, we could not say for sure whether a stream is - * AAC+/eAAC+ until the first data frame is decoded. - */ - if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1 - if (mStreamInfo->sampleRate != prevSampleRate || - mStreamInfo->numChannels != prevNumChannels) { - ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", - prevSampleRate, mStreamInfo->sampleRate, - prevNumChannels, mStreamInfo->numChannels); + memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow - notify(OMX_EventPortSettingsChanged, 1, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; + if (!outputDelayRingBufferPutSamples(tmpOutBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels)) { + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; + } + + // Discard input buffer. + inHeader->nFilledLen = 0; + + aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); - if (inHeader->nFilledLen == 0) { - inInfo->mOwnedByUs = false; - mInputBufferCount++; - inQueue.erase(inQueue.begin()); - mLastInHeader = NULL; - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; + // fall through + } + + /* + * AAC+/eAAC+ streams can be signalled in two ways: either explicitly + * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual + * rate system and the sampling rate in the final output is actually + * doubled compared with the core AAC decoder sampling rate. + * + * Explicit signalling is done by explicitly defining SBR audio object + * type in the bitstream. Implicit signalling is done by embedding + * SBR content in AAC extension payload specific to SBR, and hence + * requires an AAC decoder to perform pre-checks on actual audio frames. + * + * Thus, we could not say for sure whether a stream is + * AAC+/eAAC+ until the first data frame is decoded. + */ + if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1 + if (mStreamInfo->sampleRate != prevSampleRate || + mStreamInfo->numChannels != prevNumChannels) { + ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", + prevSampleRate, mStreamInfo->sampleRate, + prevNumChannels, mStreamInfo->numChannels); + + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + mInputBufferCount++; + inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } + return; } + } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { + ALOGW("Invalid AAC stream"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); return; } - } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { - ALOGW("Invalid AAC stream"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - return; - } - if (inHeader->nFilledLen == 0) { - inInfo->mOwnedByUs = false; - mInputBufferCount++; - inQueue.erase(inQueue.begin()); - mLastInHeader = NULL; - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; - } else { - ALOGV("inHeader->nFilledLen = %d", inHeader->nFilledLen); - } + if (inHeader && inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + mInputBufferCount++; + inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } else { + ALOGV("inHeader->nFilledLen = %d", inHeader ? inHeader->nFilledLen : 0); + } + } while (decoderErr == AAC_DEC_OK); } int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels; @@ -809,8 +817,9 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { INT_PCM *outBuffer = reinterpret_cast(outHeader->pBuffer + outHeader->nOffset); + int samplesize = mStreamInfo->numChannels * sizeof(int16_t); if (outHeader->nOffset - + mStreamInfo->frameSize * mStreamInfo->numChannels * sizeof(int16_t) + + mStreamInfo->frameSize * samplesize > outHeader->nAllocLen) { ALOGE("buffer overflow"); mSignalledError = true; @@ -818,17 +827,67 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { return; } - int32_t ns = outputDelayRingBufferGetSamples(outBuffer, - mStreamInfo->frameSize * mStreamInfo->numChannels); // TODO: check for overflow - if (ns != mStreamInfo->frameSize * mStreamInfo->numChannels) { - ALOGE("not a complete frame of samples available"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); - return; + + int available = outputDelayRingBufferSamplesAvailable(); + int numSamples = outHeader->nAllocLen / samplesize; + if (numSamples > available) { + numSamples = available; + } + int64_t currentTime = 0; + if (available) { + + int numFrames = numSamples / (mStreamInfo->frameSize * mStreamInfo->numChannels); + numSamples = numFrames * (mStreamInfo->frameSize * mStreamInfo->numChannels); + + ALOGV("%d samples available (%d), or %d frames", + numSamples, available, numFrames); + int64_t *nextTimeStamp = &mBufferTimestamps.editItemAt(0); + currentTime = *nextTimeStamp; + int32_t *currentBufLeft = &mBufferSizes.editItemAt(0); + for (int i = 0; i < numFrames; i++) { + int32_t decodedSize = mDecodedSizes.itemAt(0); + mDecodedSizes.removeAt(0); + ALOGV("decoded %d of %d", decodedSize, *currentBufLeft); + if (*currentBufLeft > decodedSize) { + // adjust/interpolate next time stamp + *currentBufLeft -= decodedSize; + *nextTimeStamp += mStreamInfo->aacSamplesPerFrame * + 1000000ll / mStreamInfo->sampleRate; + ALOGV("adjusted nextTimeStamp/size to %lld/%d", + *nextTimeStamp, *currentBufLeft); + } else { + // move to next timestamp in list + if (mBufferTimestamps.size() > 0) { + mBufferTimestamps.removeAt(0); + nextTimeStamp = &mBufferTimestamps.editItemAt(0); + mBufferSizes.removeAt(0); + currentBufLeft = &mBufferSizes.editItemAt(0); + ALOGV("moved to next time/size: %lld/%d", + *nextTimeStamp, *currentBufLeft); + } + // try to limit output buffer size to match input buffers + // (e.g when an input buffer contained 4 "sub" frames, output + // at most 4 decoded units in the corresponding output buffer) + // This is optional. Remove the next three lines to fill the output + // buffer with as many units as available. + numFrames = i + 1; + numSamples = numFrames * mStreamInfo->frameSize * mStreamInfo->numChannels; + break; + } + } + + ALOGV("getting %d from ringbuffer", numSamples); + int32_t ns = outputDelayRingBufferGetSamples(outBuffer, numSamples); + if (ns != numSamples) { + ALOGE("not a complete frame of samples available"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } } - outHeader->nFilledLen = mStreamInfo->frameSize * mStreamInfo->numChannels - * sizeof(int16_t); + outHeader->nFilledLen = numSamples * sizeof(int16_t); + if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) { outHeader->nFlags = OMX_BUFFERFLAG_EOS; mEndOfOutput = true; @@ -836,13 +895,13 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { outHeader->nFlags = 0; } - outHeader->nTimeStamp = mAnchorTimes.isEmpty() ? 0 : mAnchorTimes.itemAt(0); - mAnchorTimes.removeAt(0); + outHeader->nTimeStamp = currentTime; mOutputBufferCount++; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; + ALOGV("out timestamp %lld / %d", outHeader->nTimeStamp, outHeader->nFilledLen); notifyFillBufferDone(outHeader); outHeader = NULL; } @@ -877,8 +936,10 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { outHeader->nFilledLen = 0; outHeader->nFlags = OMX_BUFFERFLAG_EOS; - outHeader->nTimeStamp = mAnchorTimes.itemAt(0); - mAnchorTimes.removeAt(0); + outHeader->nTimeStamp = mBufferTimestamps.itemAt(0); + mBufferTimestamps.clear(); + mBufferSizes.clear(); + mDecodedSizes.clear(); mOutputBufferCount++; outInfo->mOwnedByUs = false; @@ -899,7 +960,9 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { // depend on fragments from the last one decoded. // drain all existing data drainDecoder(); - mAnchorTimes.clear(); + mBufferTimestamps.clear(); + mBufferSizes.clear(); + mDecodedSizes.clear(); mLastInHeader = NULL; } else { while (outputDelayRingBufferSamplesAvailable() > 0) { @@ -955,7 +1018,9 @@ void SoftAAC2::onReset() { mOutputDelayRingBufferReadPos = 0; mEndOfInput = false; mEndOfOutput = false; - mAnchorTimes.clear(); + mBufferTimestamps.clear(); + mBufferSizes.clear(); + mDecodedSizes.clear(); mLastInHeader = NULL; // To make the codec behave the same before and after a reset, we need to invalidate the diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h index 865bd15..9fcb598 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.h +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h @@ -59,8 +59,9 @@ private: size_t mOutputBufferCount; bool mSignalledError; OMX_BUFFERHEADERTYPE *mLastInHeader; - int64_t mCurrentInputTime; - Vector mAnchorTimes; + Vector mBufferSizes; + Vector mDecodedSizes; + Vector mBufferTimestamps; CDrcPresModeWrapper mDrcWrap; -- cgit v1.1 From 0e2c09d56bb1d7d33b0de2f446fe0cf2d5b59fcb Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 29 Aug 2014 18:48:52 -0700 Subject: PlaylistFetcher: avoid repeated fetch when we run off the edge of live playlists Bug: 17416658 Change-Id: I1d07ce03a293206c48ff9ee11dc78b815ba367a4 --- media/libstagefright/httplive/PlaylistFetcher.cpp | 6 ------ 1 file changed, 6 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 82a4c39..3ef0f06 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -737,12 +737,6 @@ void PlaylistFetcher::onDownloadNext() { const int32_t lastSeqNumberInPlaylist = firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1; - if (mStartup && mSeqNumber >= 0 - && (mSeqNumber < firstSeqNumberInPlaylist || mSeqNumber > lastSeqNumberInPlaylist)) { - // in case we guessed wrong during reconfiguration, try fetching the latest content. - mSeqNumber = lastSeqNumberInPlaylist; - } - if (mDiscontinuitySeq < 0) { mDiscontinuitySeq = mPlaylist->getDiscontinuitySeq(); } -- cgit v1.1 From 9f5264958557c45e942eabab8b32db2544d6c498 Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Wed, 3 Sep 2014 15:04:12 -0700 Subject: [audio][nuplayer] Aggregate buffers to reduce power. Combine audio data from multiple buffers into one. This reduces churn between threads and saves battery power. Only use buffer aggregation when offloading the decoder. Pend buffer if it won't fit in the bigger buffer. Bug: 15094301 Change-Id: Iad3dac90b5d6b0fa43432b0e6776652ee2eafaa1 Signed-off-by: Phil Burk --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 95 ++++++++++++++++++++++- media/libmediaplayerservice/nuplayer/NuPlayer.h | 3 + 2 files changed, 94 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 76d25de..2bffed1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -984,6 +984,8 @@ void NuPlayer::finishFlushIfPossible() { ALOGV("both audio and video are flushed now."); + mPendingAudioAccessUnit.clear(); + if (mTimeDiscontinuityPending) { mRenderer->signalTimeDiscontinuity(); mTimeDiscontinuityPending = false; @@ -1240,14 +1242,48 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { sp accessUnit; + // Aggregate smaller buffers into a larger buffer. + // The goal is to reduce power consumption. + // Unfortunately this does not work with the software AAC decoder. + // TODO optimize buffer size for power consumption + // The offload read buffer size is 32 KB but 24 KB uses less power. + const int kAudioBigBufferSizeBytes = 24 * 1024; + bool doBufferAggregation = (audio && mOffloadAudio); + sp biggerBuffer; + bool needMoreData = false; + int numSmallBuffers = 0; + bool gotTime = false; + bool dropAccessUnit; do { - status_t err = mSource->dequeueAccessUnit(audio, &accessUnit); + status_t err; + // Did we save an accessUnit earlier because of a discontinuity? + if (audio && (mPendingAudioAccessUnit != NULL)) { + accessUnit = mPendingAudioAccessUnit; + mPendingAudioAccessUnit.clear(); + err = mPendingAudioErr; + ALOGV("feedDecoderInputData() use mPendingAudioAccessUnit"); + } else { + err = mSource->dequeueAccessUnit(audio, &accessUnit); + } if (err == -EWOULDBLOCK) { - return err; + ALOGD("feedDecoderInputData() got EWOULDBLOCK"); + if (biggerBuffer == NULL) { + return err; + } else { + break; // Reply with data that we already have. + } } else if (err != OK) { if (err == INFO_DISCONTINUITY) { + if (biggerBuffer != NULL) { + // We already have some data so save this for later. + mPendingAudioErr = err; + mPendingAudioAccessUnit = accessUnit; + accessUnit.clear(); + ALOGD("feedDecoderInputData() save discontinuity for later"); + break; + } int32_t type; CHECK(accessUnit->meta()->findInt32("discontinuity", &type)); @@ -1352,7 +1388,52 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { dropAccessUnit = true; ++mNumFramesDropped; } - } while (dropAccessUnit); + + size_t smallSize = accessUnit->size(); + needMoreData = false; + if (doBufferAggregation && (biggerBuffer == NULL) + // Don't bother if only room for a few small buffers. + && (smallSize < (kAudioBigBufferSizeBytes / 3))) { + // Create a larger buffer for combining smaller buffers from the extractor. + biggerBuffer = new ABuffer(kAudioBigBufferSizeBytes); + biggerBuffer->setRange(0, 0); // start empty + } + + if (biggerBuffer != NULL) { + int64_t timeUs; + bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs); + // Will the smaller buffer fit? + size_t bigSize = biggerBuffer->size(); + size_t roomLeft = biggerBuffer->capacity() - bigSize; + // Should we save this small buffer for the next big buffer? + // If the first small buffer did not have a timestamp then save + // any buffer that does have a timestamp until the next big buffer. + if ((smallSize > roomLeft) + || (!gotTime && (numSmallBuffers > 0) && smallTimestampValid)) { + mPendingAudioErr = err; + mPendingAudioAccessUnit = accessUnit; + accessUnit.clear(); + } else { + // Append small buffer to the bigger buffer. + memcpy(biggerBuffer->base() + bigSize, accessUnit->data(), smallSize); + bigSize += smallSize; + biggerBuffer->setRange(0, bigSize); + + // Keep looping until we run out of room in the biggerBuffer. + needMoreData = true; + + // Grab time from first small buffer if available. + if ((numSmallBuffers == 0) && smallTimestampValid) { + biggerBuffer->meta()->setInt64("timeUs", timeUs); + gotTime = true; + } + + ALOGV("feedDecoderInputData() #%d, smallSize = %zu, bigSize = %zu, capacity = %zu", + numSmallBuffers, smallSize, bigSize, biggerBuffer->capacity()); + numSmallBuffers++; + } + } + } while (dropAccessUnit || needMoreData); // ALOGV("returned a valid buffer of %s data", audio ? "audio" : "video"); @@ -1368,7 +1449,13 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { mCCDecoder->decode(accessUnit); } - reply->setBuffer("buffer", accessUnit); + if (biggerBuffer != NULL) { + ALOGV("feedDecoderInputData() reply with aggregated buffer, %d", numSmallBuffers); + reply->setBuffer("buffer", biggerBuffer); + } else { + reply->setBuffer("buffer", accessUnit); + } + reply->post(); return OK; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 511d752..b318cfe 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -157,6 +157,9 @@ private: // notion of time has changed. bool mTimeDiscontinuityPending; + sp mPendingAudioAccessUnit; + status_t mPendingAudioErr; + FlushStatus mFlushingAudio; FlushStatus mFlushingVideo; -- cgit v1.1 From b445375f50a1a619b2d7518d32387d5ea77ceb70 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Mon, 8 Sep 2014 11:47:24 -0700 Subject: Fix potential deadlock between AudioPolicyService and AudioSystem Bug: 17109761 Change-Id: I315c1c5066f62b05e1c13b04fae1272b5fbce977 --- media/libmedia/AudioSystem.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 3486d21..1742fbe 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -582,9 +582,13 @@ const sp& AudioSystem::get_audio_policy_service() } binder->linkToDeath(gAudioPolicyServiceClient); gAudioPolicyService = interface_cast(binder); - gAudioPolicyService->registerClient(gAudioPolicyServiceClient); gLock.unlock(); + // Registering the client takes the AudioPolicyService lock. + // Don't hold the AudioSystem lock at the same time. + gAudioPolicyService->registerClient(gAudioPolicyServiceClient); } else { + // There exists a benign race condition where gAudioPolicyService + // is set, but gAudioPolicyServiceClient is not yet registered. gLock.unlock(); } return gAudioPolicyService; -- cgit v1.1 From f702d0415be7d5cb8c1801953b74adc1065c015e Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Tue, 9 Sep 2014 12:08:47 -0700 Subject: NuPlayer: check mSource before deferencing it. Bug: 17428608 Change-Id: I7b264d1288ed3c495434aedeeeef2fbfc3ca2f16 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 4a5d18a..35cc1ee 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1242,7 +1242,8 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { CHECK(msg->findMessage("reply", &reply)); if ((audio && mFlushingAudio != NONE) - || (!audio && mFlushingVideo != NONE)) { + || (!audio && mFlushingVideo != NONE) + || mSource == NULL) { reply->setInt32("err", INFO_DISCONTINUITY); reply->post(); return OK; -- cgit v1.1 From 8592dbbdf5339890db2b14f83bcd6da2ffb023d2 Mon Sep 17 00:00:00 2001 From: Rachad Date: Tue, 9 Sep 2014 13:10:28 -0700 Subject: NuPlayer::Renderer::onPause() - Converted CHECK(!mPaused) to a warning. Bug: 17436451 Change-Id: I7e9e0c48bbdd8ab65c5f4a587699a28435bd03f4 --- media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index aad6e93..067784b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -893,8 +893,10 @@ void NuPlayer::Renderer::notifyPosition() { } void NuPlayer::Renderer::onPause() { - CHECK(!mPaused); - + if (mPaused) { + ALOGW("Renderer::onPause() called while already paused!"); + return; + } { Mutex::Autolock autoLock(mLock); ++mAudioQueueGeneration; -- cgit v1.1 From 1008e1c9eb9ec7aeefffa4d9907f890a8eab7668 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Tue, 9 Sep 2014 14:49:08 -0700 Subject: NuPlayer: make previous decoders obsolete when reset is done. Bug: 17428608 Change-Id: I724174d65f8e00bfecb51e6f690ae709ed2cf442 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index a44de98..59766c8 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1833,6 +1833,9 @@ void NuPlayer::performReset() { ++mScanSourcesGeneration; mScanSourcesPending = false; + ++mAudioDecoderGeneration; + ++mVideoDecoderGeneration; + if (mRendererLooper != NULL) { if (mRenderer != NULL) { mRendererLooper->unregisterHandler(mRenderer->id()); -- cgit v1.1 From cbe165a6f68c90bbdd2b1593387d4072bd80b924 Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Tue, 9 Sep 2014 11:46:18 -0700 Subject: [media][nuplayer] Remove debug message EWOULDBLOCK A debug message that was silent during testing is now spewing messages. It was removed. Bug: 17438882 Change-Id: I9c61409cac77c7bc1fd1088815823207094606f2 Signed-off-by: Phil Burk --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index a44de98..4004ddf 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1279,7 +1279,6 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { } if (err == -EWOULDBLOCK) { - ALOGD("feedDecoderInputData() got EWOULDBLOCK"); if (biggerBuffer == NULL) { return err; } else { -- cgit v1.1 From 9520aa609c505cf8a9ee105bd78dc186cfb7770b Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Tue, 9 Sep 2014 16:18:31 -0700 Subject: CamcorderProfile: Add QUALITY_HIGH_SPEED_2160P Bug: 17059255 Change-Id: Ic6b272e4ceec8fc852c9eb787370f4d366dad0ac --- media/libmedia/MediaProfiles.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'media') diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp index d2e181b..e2e6042 100644 --- a/media/libmedia/MediaProfiles.cpp +++ b/media/libmedia/MediaProfiles.cpp @@ -87,6 +87,7 @@ const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = { {"highspeed480p", CAMCORDER_QUALITY_HIGH_SPEED_480P}, {"highspeed720p", CAMCORDER_QUALITY_HIGH_SPEED_720P}, {"highspeed1080p", CAMCORDER_QUALITY_HIGH_SPEED_1080P}, + {"highspeed2160p", CAMCORDER_QUALITY_HIGH_SPEED_2160P}, }; #if LOG_NDEBUG -- cgit v1.1 From 178e506350ef41609daaf307f598ef0bc4f82c71 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Tue, 9 Sep 2014 20:08:39 -0700 Subject: mediaplayer: limit number of outstanding buffer requests Bug: 14679336 Change-Id: I94a20ada30a9a25065329a85fc884d32d154d029 --- .../nuplayer/NuPlayerDecoderPassThrough.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp index c9be0dd..ab7906a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp @@ -115,9 +115,12 @@ void NuPlayer::DecoderPassThrough::requestABuffer() { notify->post(); mPendingBuffers++; - sp message = new AMessage(kWhatRequestABuffer, id()); - message->setInt32("generation", mBufferGeneration); - message->post(); + // pending buffers will already result in requestABuffer + if (mPendingBuffers < kMaxPendingBuffers) { + sp message = new AMessage(kWhatRequestABuffer, id()); + message->setInt32("generation", mBufferGeneration); + message->post(); + } return; } @@ -155,9 +158,7 @@ void android::NuPlayer::DecoderPassThrough::onInputBufferFilled( void NuPlayer::DecoderPassThrough::onBufferConsumed(int32_t size) { mPendingBuffers--; mCachedBytes -= size; - sp message = new AMessage(kWhatRequestABuffer, id()); - message->setInt32("generation", mBufferGeneration); - message->post(); + requestABuffer(); } void NuPlayer::DecoderPassThrough::onFlush() { -- cgit v1.1 From 7ea429295a2eb31f2d9256c36c1ef53a195456ac Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 27 Aug 2014 09:02:47 -0700 Subject: stagefright: don't use AAtomizer in AMessage Bug: 15094301 Change-Id: Ib82fb6d8fb6b48402d81f411123b3d924368eb93 --- media/libstagefright/foundation/AMessage.cpp | 123 ++++++++++++++++++++------- 1 file changed, 93 insertions(+), 30 deletions(-) (limited to 'media') diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp index d268aa4..bc3e3fb 100644 --- a/media/libstagefright/foundation/AMessage.cpp +++ b/media/libstagefright/foundation/AMessage.cpp @@ -14,6 +14,11 @@ * limitations under the License. */ +#define LOG_TAG "AMessage" +//#define LOG_NDEBUG 0 +//#define DUMP_STATS +#include + #include "AMessage.h" #include @@ -60,12 +65,14 @@ ALooper::handler_id AMessage::target() const { void AMessage::clear() { for (size_t i = 0; i < mNumItems; ++i) { Item *item = &mItems[i]; - freeItem(item); + delete[] item->mName; + item->mName = NULL; + freeItemValue(item); } mNumItems = 0; } -void AMessage::freeItem(Item *item) { +void AMessage::freeItemValue(Item *item) { switch (item->mType) { case kTypeString: { @@ -88,25 +95,85 @@ void AMessage::freeItem(Item *item) { } } -AMessage::Item *AMessage::allocateItem(const char *name) { - name = AAtomizer::Atomize(name); +#ifdef DUMP_STATS +#include + +Mutex gLock; +static int32_t gFindItemCalls = 1; +static int32_t gDupCalls = 1; +static int32_t gAverageNumItems = 0; +static int32_t gAverageNumChecks = 0; +static int32_t gAverageNumMemChecks = 0; +static int32_t gAverageDupItems = 0; +static int32_t gLastChecked = -1; + +static void reportStats() { + int32_t time = (ALooper::GetNowUs() / 1000); + if (time / 1000 != gLastChecked / 1000) { + gLastChecked = time; + ALOGI("called findItemIx %zu times (for len=%.1f i=%.1f/%.1f mem) dup %zu times (for len=%.1f)", + gFindItemCalls, + gAverageNumItems / (float)gFindItemCalls, + gAverageNumChecks / (float)gFindItemCalls, + gAverageNumMemChecks / (float)gFindItemCalls, + gDupCalls, + gAverageDupItems / (float)gDupCalls); + gFindItemCalls = gDupCalls = 1; + gAverageNumItems = gAverageNumChecks = gAverageNumMemChecks = gAverageDupItems = 0; + gLastChecked = time; + } +} +#endif +inline size_t AMessage::findItemIndex(const char *name, size_t len) const { +#ifdef DUMP_STATS + size_t memchecks = 0; +#endif size_t i = 0; - while (i < mNumItems && mItems[i].mName != name) { - ++i; + for (; i < mNumItems; i++) { + if (len != mItems[i].mNameLength) { + continue; + } +#ifdef DUMP_STATS + ++memchecks; +#endif + if (!memcmp(mItems[i].mName, name, len)) { + break; + } + } +#ifdef DUMP_STATS + { + Mutex::Autolock _l(gLock); + ++gFindItemCalls; + gAverageNumItems += mNumItems; + gAverageNumMemChecks += memchecks; + gAverageNumChecks += i; + reportStats(); } +#endif + return i; +} + +// assumes item's name was uninitialized or NULL +void AMessage::Item::setName(const char *name, size_t len) { + mNameLength = len; + mName = new char[len + 1]; + memcpy((void*)mName, name, len + 1); +} +AMessage::Item *AMessage::allocateItem(const char *name) { + size_t len = strlen(name); + size_t i = findItemIndex(name, len); Item *item; if (i < mNumItems) { item = &mItems[i]; - freeItem(item); + freeItemValue(item); } else { CHECK(mNumItems < kMaxNumItems); i = mNumItems++; item = &mItems[i]; - - item->mName = name; + item->setName(name, len); } return item; @@ -114,31 +181,18 @@ AMessage::Item *AMessage::allocateItem(const char *name) { const AMessage::Item *AMessage::findItem( const char *name, Type type) const { - name = AAtomizer::Atomize(name); - - for (size_t i = 0; i < mNumItems; ++i) { + size_t i = findItemIndex(name, strlen(name)); + if (i < mNumItems) { const Item *item = &mItems[i]; + return item->mType == type ? item : NULL; - if (item->mName == name) { - return item->mType == type ? item : NULL; - } } - return NULL; } bool AMessage::contains(const char *name) const { - name = AAtomizer::Atomize(name); - - for (size_t i = 0; i < mNumItems; ++i) { - const Item *item = &mItems[i]; - - if (item->mName == name) { - return true; - } - } - - return false; + size_t i = findItemIndex(name, strlen(name)); + return i < mNumItems; } #define BASIC_TYPE(NAME,FIELDNAME,TYPENAME) \ @@ -297,11 +351,20 @@ sp AMessage::dup() const { sp msg = new AMessage(mWhat, mTarget); msg->mNumItems = mNumItems; +#ifdef DUMP_STATS + { + Mutex::Autolock _l(gLock); + ++gDupCalls; + gAverageDupItems += mNumItems; + reportStats(); + } +#endif + for (size_t i = 0; i < mNumItems; ++i) { const Item *from = &mItems[i]; Item *to = &msg->mItems[i]; - to->mName = from->mName; + to->setName(from->mName, from->mNameLength); to->mType = from->mType; switch (from->mType) { @@ -472,11 +535,11 @@ sp AMessage::FromParcel(const Parcel &parcel) { sp msg = new AMessage(what); msg->mNumItems = static_cast(parcel.readInt32()); - for (size_t i = 0; i < msg->mNumItems; ++i) { Item *item = &msg->mItems[i]; - item->mName = AAtomizer::Atomize(parcel.readCString()); + const char *name = parcel.readCString(); + item->setName(name, strlen(name)); item->mType = static_cast(parcel.readInt32()); switch (item->mType) { -- cgit v1.1 From bf220f3e6e799f28d1599c3c5106e9e15631a91d Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Tue, 2 Sep 2014 10:55:41 -0700 Subject: stagefright: add adaptive playback support to SoftAVC decoder. Also change SoftVPX decoder to use common handlePortSettingsChanged and copyYV12FrameToOutputBuffer method. Bug: 17326758 Change-Id: I6fb2ee8fb9291f69c70493b8558af341adc1f4b2 --- media/libstagefright/codecs/on2/dec/SoftVPX.cpp | 63 +++-------------- .../libstagefright/codecs/on2/h264dec/SoftAVC.cpp | 81 ++++++++++------------ media/libstagefright/codecs/on2/h264dec/SoftAVC.h | 5 +- .../include/SoftVideoDecoderOMXComponent.h | 9 ++- .../omx/SoftVideoDecoderOMXComponent.cpp | 79 +++++++++++++++++++-- 5 files changed, 130 insertions(+), 107 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp index 2f63bdd..828577a 100644 --- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp +++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp @@ -137,29 +137,10 @@ void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) { uint32_t width = mImg->d_w; uint32_t height = mImg->d_h; - - if (width != mWidth || height != mHeight) { - mWidth = width; - mHeight = height; - - if (!mIsAdaptive || width > mAdaptiveMaxWidth || height > mAdaptiveMaxHeight) { - if (mIsAdaptive) { - if (width > mAdaptiveMaxWidth) { - mAdaptiveMaxWidth = width; - } - if (height > mAdaptiveMaxHeight) { - mAdaptiveMaxHeight = height; - } - } - updatePortDefinitions(); - notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; - return; - } else { - updatePortDefinitions(); - notify(OMX_EventPortSettingsChanged, kOutputPortIndex, - OMX_IndexConfigCommonOutputCrop, NULL); - } + bool portWillReset = false; + handlePortSettingsChange(&portWillReset, width, height); + if (portWillReset) { + return; } outHeader->nOffset = 0; @@ -167,36 +148,14 @@ void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) { outHeader->nFlags = EOSseen ? OMX_BUFFERFLAG_EOS : 0; outHeader->nTimeStamp = inHeader->nTimeStamp; - uint32_t buffer_stride = mIsAdaptive ? mAdaptiveMaxWidth : mWidth; - uint32_t buffer_height = mIsAdaptive ? mAdaptiveMaxHeight : mHeight; - - const uint8_t *srcLine = (const uint8_t *)mImg->planes[PLANE_Y]; uint8_t *dst = outHeader->pBuffer; - for (size_t i = 0; i < buffer_height; ++i) { - if (i < mImg->d_h) { - memcpy(dst, srcLine, mImg->d_w); - srcLine += mImg->stride[PLANE_Y]; - } - dst += buffer_stride; - } - - srcLine = (const uint8_t *)mImg->planes[PLANE_U]; - for (size_t i = 0; i < buffer_height / 2; ++i) { - if (i < mImg->d_h / 2) { - memcpy(dst, srcLine, mImg->d_w / 2); - srcLine += mImg->stride[PLANE_U]; - } - dst += buffer_stride / 2; - } - - srcLine = (const uint8_t *)mImg->planes[PLANE_V]; - for (size_t i = 0; i < buffer_height / 2; ++i) { - if (i < mImg->d_h / 2) { - memcpy(dst, srcLine, mImg->d_w / 2); - srcLine += mImg->stride[PLANE_V]; - } - dst += buffer_stride / 2; - } + const uint8_t *srcY = (const uint8_t *)mImg->planes[PLANE_Y]; + const uint8_t *srcU = (const uint8_t *)mImg->planes[PLANE_U]; + const uint8_t *srcV = (const uint8_t *)mImg->planes[PLANE_V]; + size_t srcYStride = mImg->stride[PLANE_Y]; + size_t srcUStride = mImg->stride[PLANE_U]; + size_t srcVStride = mImg->stride[PLANE_V]; + copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride); mImg = NULL; outInfo->mOwnedByUs = false; diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp index a7bde97..cf3c3e3 100644 --- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp +++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp @@ -58,7 +58,6 @@ SoftAVC::SoftAVC( 320 /* width */, 240 /* height */, callbacks, appData, component), mHandle(NULL), mInputBufferCount(0), - mPictureSize(mWidth * mHeight * 3 / 2), mFirstPicture(NULL), mFirstPictureId(-1), mPicId(0), @@ -118,7 +117,7 @@ void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) { } H264SwDecRet ret = H264SWDEC_PIC_RDY; - bool portSettingsChanged = false; + bool portWillReset = false; while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty()) && outQueue.size() == kNumOutputBuffers) { @@ -161,17 +160,13 @@ void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) { H264SwDecInfo decoderInfo; CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK); - if (handlePortSettingChangeEvent(&decoderInfo)) { - portSettingsChanged = true; - } - - if (decoderInfo.croppingFlag && - handleCropRectEvent(&decoderInfo.cropParams)) { - portSettingsChanged = true; - } + bool cropChanged = handleCropChange(decoderInfo); + handlePortSettingsChange( + &portWillReset, decoderInfo.picWidth, decoderInfo.picHeight, + cropChanged); } } else { - if (portSettingsChanged) { + if (portWillReset) { if (H264SwDecNextPicture(mHandle, &decodedPicture, 0) == H264SWDEC_PIC_RDY) { @@ -199,8 +194,7 @@ void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) { inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); - if (portSettingsChanged) { - portSettingsChanged = false; + if (portWillReset) { return; } @@ -215,44 +209,33 @@ void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) { } } -bool SoftAVC::handlePortSettingChangeEvent(const H264SwDecInfo *info) { - if (mWidth != info->picWidth || mHeight != info->picHeight) { - mWidth = info->picWidth; - mHeight = info->picHeight; - mPictureSize = mWidth * mHeight * 3 / 2; - updatePortDefinitions(); - notify(OMX_EventPortSettingsChanged, 1, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; - return true; +bool SoftAVC::handleCropChange(const H264SwDecInfo& decInfo) { + if (!decInfo.croppingFlag) { + return false; } - return false; -} - -bool SoftAVC::handleCropRectEvent(const CropParams *crop) { - if (mCropLeft != crop->cropLeftOffset || - mCropTop != crop->cropTopOffset || - mCropWidth != crop->cropOutWidth || - mCropHeight != crop->cropOutHeight) { - mCropLeft = crop->cropLeftOffset; - mCropTop = crop->cropTopOffset; - mCropWidth = crop->cropOutWidth; - mCropHeight = crop->cropOutHeight; - - notify(OMX_EventPortSettingsChanged, 1, - OMX_IndexConfigCommonOutputCrop, NULL); - - return true; + const CropParams& crop = decInfo.cropParams; + if (mCropLeft == crop.cropLeftOffset && + mCropTop == crop.cropTopOffset && + mCropWidth == crop.cropOutWidth && + mCropHeight == crop.cropOutHeight) { + return false; } - return false; + + mCropLeft = crop.cropLeftOffset; + mCropTop = crop.cropTopOffset; + mCropWidth = crop.cropOutWidth; + mCropHeight = crop.cropOutHeight; + return true; } void SoftAVC::saveFirstOutputBuffer(int32_t picId, uint8_t *data) { CHECK(mFirstPicture == NULL); mFirstPictureId = picId; - mFirstPicture = new uint8_t[mPictureSize]; - memcpy(mFirstPicture, data, mPictureSize); + uint32_t pictureSize = mWidth * mHeight * 3 / 2; + mFirstPicture = new uint8_t[pictureSize]; + memcpy(mFirstPicture, data, pictureSize); } void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) { @@ -263,9 +246,17 @@ void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) { OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId); outHeader->nTimeStamp = header->nTimeStamp; outHeader->nFlags = header->nFlags; - outHeader->nFilledLen = mPictureSize; - memcpy(outHeader->pBuffer + outHeader->nOffset, - data, mPictureSize); + outHeader->nFilledLen = mWidth * mHeight * 3 / 2; + + uint8_t *dst = outHeader->pBuffer + outHeader->nOffset; + const uint8_t *srcY = data; + const uint8_t *srcU = srcY + mWidth * mHeight; + const uint8_t *srcV = srcU + mWidth * mHeight / 4; + size_t srcYStride = mWidth; + size_t srcUStride = mWidth / 2; + size_t srcVStride = srcUStride; + copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride); + mPicToHeaderMap.removeItem(picId); delete header; outInfo->mOwnedByUs = false; diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.h b/media/libstagefright/codecs/on2/h264dec/SoftAVC.h index ee69926..253a406 100644 --- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.h +++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.h @@ -55,8 +55,6 @@ private: size_t mInputBufferCount; - uint32_t mPictureSize; - uint8_t *mFirstPicture; int32_t mFirstPictureId; @@ -75,8 +73,7 @@ private: void drainAllOutputBuffers(bool eos); void drainOneOutputBuffer(int32_t picId, uint8_t *data); void saveFirstOutputBuffer(int32_t pidId, uint8_t *data); - bool handleCropRectEvent(const CropParams* crop); - bool handlePortSettingChangeEvent(const H264SwDecInfo *info); + bool handleCropChange(const H264SwDecInfo& decInfo); DISALLOW_EVIL_CONSTRUCTORS(SoftAVC); }; diff --git a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h index ee553d9..4a6ab63 100644 --- a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h +++ b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h @@ -63,7 +63,14 @@ protected: OMX_U32 numOutputBuffers, const char *mimeType); - virtual void updatePortDefinitions(); + virtual void updatePortDefinitions(bool updateCrop = true); + + void handlePortSettingsChange( + bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged = false); + + void copyYV12FrameToOutputBuffer( + uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV, + size_t srcYStride, size_t srcUStride, size_t srcVStride); enum { kInputPortIndex = 0, diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp index 69b572e..e533fdd 100644 --- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp +++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp @@ -123,13 +123,15 @@ void SoftVideoDecoderOMXComponent::initPorts( updatePortDefinitions(); } -void SoftVideoDecoderOMXComponent::updatePortDefinitions() { +void SoftVideoDecoderOMXComponent::updatePortDefinitions(bool updateCrop) { OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef; def->format.video.nFrameWidth = mWidth; def->format.video.nFrameHeight = mHeight; def->format.video.nStride = def->format.video.nFrameWidth; def->format.video.nSliceHeight = def->format.video.nFrameHeight; + def->nBufferSize = def->format.video.nFrameWidth * def->format.video.nFrameHeight * 3 / 2; + def = &editPortInfo(kOutputPortIndex)->mDef; def->format.video.nFrameWidth = mIsAdaptive ? mAdaptiveMaxWidth : mWidth; def->format.video.nFrameHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight; @@ -140,10 +142,77 @@ void SoftVideoDecoderOMXComponent::updatePortDefinitions() { (def->format.video.nFrameWidth * def->format.video.nFrameHeight * 3) / 2; - mCropLeft = 0; - mCropTop = 0; - mCropWidth = mWidth; - mCropHeight = mHeight; + if (updateCrop) { + mCropLeft = 0; + mCropTop = 0; + mCropWidth = mWidth; + mCropHeight = mHeight; + } +} + +void SoftVideoDecoderOMXComponent::handlePortSettingsChange( + bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged) { + *portWillReset = false; + bool sizeChanged = (width != mWidth || height != mHeight); + + if (sizeChanged || cropChanged) { + mWidth = width; + mHeight = height; + + bool updateCrop = !cropChanged; + if ((sizeChanged && !mIsAdaptive) + || width > mAdaptiveMaxWidth + || height > mAdaptiveMaxHeight) { + if (mIsAdaptive) { + if (width > mAdaptiveMaxWidth) { + mAdaptiveMaxWidth = width; + } + if (height > mAdaptiveMaxHeight) { + mAdaptiveMaxHeight = height; + } + } + updatePortDefinitions(updateCrop); + notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + *portWillReset = true; + } else { + updatePortDefinitions(updateCrop); + notify(OMX_EventPortSettingsChanged, kOutputPortIndex, + OMX_IndexConfigCommonOutputCrop, NULL); + } + } +} + +void SoftVideoDecoderOMXComponent::copyYV12FrameToOutputBuffer( + uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV, + size_t srcYStride, size_t srcUStride, size_t srcVStride) { + size_t dstYStride = mIsAdaptive ? mAdaptiveMaxWidth : mWidth; + size_t dstUVStride = dstYStride / 2; + size_t dstHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight; + + for (size_t i = 0; i < dstHeight; ++i) { + if (i < mHeight) { + memcpy(dst, srcY, mWidth); + srcY += srcYStride; + } + dst += dstYStride; + } + + for (size_t i = 0; i < dstHeight / 2; ++i) { + if (i < mHeight / 2) { + memcpy(dst, srcU, mWidth / 2); + srcU += srcUStride; + } + dst += dstUVStride; + } + + for (size_t i = 0; i < dstHeight / 2; ++i) { + if (i < mHeight / 2) { + memcpy(dst, srcV, mWidth / 2); + srcV += srcVStride; + } + dst += dstUVStride; + } } OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalGetParameter( -- cgit v1.1 From f64b36deccd473b545dbed22c2feb11fc49157e5 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 10 Sep 2014 10:43:41 -0700 Subject: fix failure in MediaCodecTest#testException reset codec after failed configure() Bug: 17418876 Change-Id: I21ff8a0751dae6a164678015142e11d481403bed --- media/libstagefright/MediaCodec.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index fc2dd30..0bfc6e4 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -270,7 +270,20 @@ status_t MediaCodec::configure( } sp response; - return PostAndAwaitResponse(msg, &response); + status_t err = PostAndAwaitResponse(msg, &response); + + if (err != OK && err != INVALID_OPERATION) { + // MediaCodec now set state to UNINITIALIZED upon any fatal error. + // To maintain backward-compatibility, do a reset() to put codec + // back into INITIALIZED state. + // But don't reset if the err is INVALID_OPERATION, which means + // the configure failure is due to wrong state. + + ALOGE("configure failed with err 0x%08x, resetting...", err); + reset(); + } + + return err; } status_t MediaCodec::createInputSurface( -- cgit v1.1 From 71079fc29d93fb49d6022397b6d4168b7fba6e9b Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 10 Sep 2014 10:06:11 -0700 Subject: NuPlayerDriver: do not set to paused state when receiving playback complete and reset is in progress. Bug: 17453240 Change-Id: If243e2232779681fc84dc767feaed00f23d8fdb1 --- media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 35cd514..7dd54c1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -626,12 +626,15 @@ void NuPlayerDriver::notifyListener_l( switch (msg) { case MEDIA_PLAYBACK_COMPLETE: { - if (mLooping && mState != STATE_RESET_IN_PROGRESS) { - mPlayer->seekToAsync(0); - break; + if (mState != STATE_RESET_IN_PROGRESS) { + if (mLooping) { + mPlayer->seekToAsync(0); + break; + } + + mPlayer->pause(); + mState = STATE_PAUSED; } - mPlayer->pause(); - mState = STATE_PAUSED; // fall through } -- cgit v1.1 From 00598ec0b15426197494aaf9e5ec0bc88507c762 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 29 Aug 2014 18:13:13 -0700 Subject: LiveSession: raise upwards adaptation constraint Adjust bandwidth more conservatively when considering an upwards adaptation. Also fixed an issue with kWhatCheckBandwidth messages being accumulated across switch generations; this causes onCheckBandwidth to be fired at a high frequency and LiveSession to be too sensitive to network glitches. Bug: 13743153 Change-Id: I1dec99cb5d123c6675abe0847fd12aab5178eefd --- media/libstagefright/httplive/LiveSession.cpp | 35 +++++++++++++++------------ media/libstagefright/httplive/LiveSession.h | 2 +- 2 files changed, 21 insertions(+), 16 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 7b18348..02ebfc7 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -498,7 +498,7 @@ void LiveSession::onMessageReceived(const sp &msg) { break; } - onCheckBandwidth(); + onCheckBandwidth(msg); break; } @@ -919,14 +919,22 @@ size_t LiveSession::getBandwidthIndex() { } } - // Consider only 80% of the available bandwidth usable. - bandwidthBps = (bandwidthBps * 8) / 10; - // Pick the highest bandwidth stream below or equal to estimated bandwidth. index = mBandwidthItems.size() - 1; - while (index > 0 && mBandwidthItems.itemAt(index).mBandwidth - > (size_t)bandwidthBps) { + while (index > 0) { + // consider only 80% of the available bandwidth, but if we are switching up, + // be even more conservative (70%) to avoid overestimating and immediately + // switching back. + size_t adjustedBandwidthBps = bandwidthBps; + if (index > mCurBandwidthIndex) { + adjustedBandwidthBps = adjustedBandwidthBps * 7 / 10; + } else { + adjustedBandwidthBps = adjustedBandwidthBps * 8 / 10; + } + if (mBandwidthItems.itemAt(index).mBandwidth <= adjustedBandwidthBps) { + break; + } --index; } } @@ -1394,6 +1402,7 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { // All fetchers have now been started, the configuration change // has completed. + cancelCheckBandwidthEvent(); scheduleCheckBandwidthEvent(); ALOGV("XXX configuration change completed."); @@ -1492,20 +1501,16 @@ bool LiveSession::canSwitchBandwidthTo(size_t bandwidthIndex) { } } -void LiveSession::onCheckBandwidth() { +void LiveSession::onCheckBandwidth(const sp &msg) { size_t bandwidthIndex = getBandwidthIndex(); if (canSwitchBandwidthTo(bandwidthIndex)) { changeConfiguration(-1ll /* timeUs */, bandwidthIndex); } else { - scheduleCheckBandwidthEvent(); + // Come back and check again 10 seconds later in case there is nothing to do now. + // If we DO change configuration, once that completes it'll schedule a new + // check bandwidth event with an incremented mCheckBandwidthGeneration. + msg->post(10000000ll); } - - // Handling the kWhatCheckBandwidth even here does _not_ automatically - // schedule another one on return, only an explicit call to - // scheduleCheckBandwidthEvent will do that. - // This ensures that only one configuration change is ongoing at any - // one time, once that completes it'll schedule another check bandwidth - // event. } void LiveSession::postPrepared(status_t err) { diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 5423f0f..aa06a3f 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -257,7 +257,7 @@ private: void cancelBandwidthSwitch(); bool canSwitchBandwidthTo(size_t bandwidthIndex); - void onCheckBandwidth(); + void onCheckBandwidth(const sp &msg); void finishDisconnect(); -- cgit v1.1 From 8484830a6b488b41da0e32acacf2e6b68060d9d0 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 10 Sep 2014 12:21:59 -0700 Subject: Revert "Fix AAC timestamps for multiple aac frames per input buffer" This reverts commit e086387c805311ac87904c3c4d6d4eb08d4b4ee2. (broke multichannel movie playback) Bug: 17454025 Change-Id: I95b82359f87f8beca66f35c34b7e125850a44747 --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 317 ++++++++++-------------- media/libstagefright/codecs/aacdec/SoftAAC2.h | 5 +- 2 files changed, 128 insertions(+), 194 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 6dd9b92..8b4dd6f 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -//#define LOG_NDEBUG 0 #define LOG_TAG "SoftAAC2" +//#define LOG_NDEBUG 0 #include #include "SoftAAC2.h" @@ -68,6 +68,7 @@ SoftAAC2::SoftAAC2( mOutputBufferCount(0), mSignalledError(false), mLastInHeader(NULL), + mCurrentInputTime(0), mOutputPortSettingsChange(NONE) { initPorts(); CHECK_EQ(initDecoder(), (status_t)OK); @@ -609,24 +610,9 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL); return; } - - // insert buffer size and time stamp - mBufferSizes.add(inBufferLength[0]); - if (mLastInHeader != inHeader) { - mBufferTimestamps.add(inHeader->nTimeStamp); - mLastInHeader = inHeader; - } else { - int64_t currentTime = mBufferTimestamps.top(); - currentTime += mStreamInfo->aacSamplesPerFrame * - 1000000ll / mStreamInfo->sampleRate; - mBufferTimestamps.add(currentTime); - } } else { inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; inBufferLength[0] = inHeader->nFilledLen; - mLastInHeader = inHeader; - mBufferTimestamps.add(inHeader->nTimeStamp); - mBufferSizes.add(inHeader->nFilledLen); } // Fill and decode @@ -635,130 +621,136 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { INT prevSampleRate = mStreamInfo->sampleRate; INT prevNumChannels = mStreamInfo->numChannels; + if (inHeader != mLastInHeader) { + mLastInHeader = inHeader; + mCurrentInputTime = inHeader->nTimeStamp; + } else { + if (mStreamInfo->sampleRate) { + mCurrentInputTime += mStreamInfo->aacSamplesPerFrame * + 1000000ll / mStreamInfo->sampleRate; + } else { + ALOGW("no sample rate yet"); + } + } + mAnchorTimes.add(mCurrentInputTime); aacDecoder_Fill(mAACDecoder, inBuffer, inBufferLength, bytesValid); - // run DRC check - mDrcWrap.submitStreamData(mStreamInfo); - mDrcWrap.update(); + // run DRC check + mDrcWrap.submitStreamData(mStreamInfo); + mDrcWrap.update(); - UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; - inHeader->nFilledLen -= inBufferUsedLength; - inHeader->nOffset += inBufferUsedLength; + AAC_DECODER_ERROR decoderErr = + aacDecoder_DecodeFrame(mAACDecoder, + tmpOutBuffer, + 2048 * MAX_CHANNEL_COUNT, + 0 /* flags */); - AAC_DECODER_ERROR decoderErr; - do { - int numconsumed = mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes; - decoderErr = aacDecoder_DecodeFrame(mAACDecoder, - tmpOutBuffer, - 2048 * MAX_CHANNEL_COUNT, - 0 /* flags */); + if (decoderErr != AAC_DEC_OK) { + ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); + } - numconsumed = (mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes) - numconsumed; - if (numconsumed != 0) { - mDecodedSizes.add(numconsumed); - } + if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { + ALOGE("AAC_DEC_NOT_ENOUGH_BITS should never happen"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } - if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { - break; - } + if (bytesValid[0] != 0) { + ALOGE("bytesValid[0] != 0 should never happen"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } - if (decoderErr != AAC_DEC_OK) { - ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); - } + size_t numOutBytes = + mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; - if (bytesValid[0] != 0) { - ALOGE("bytesValid[0] != 0 should never happen"); + if (decoderErr == AAC_DEC_OK) { + if (!outputDelayRingBufferPutSamples(tmpOutBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels)) { mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); return; } + UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; + inHeader->nFilledLen -= inBufferUsedLength; + inHeader->nOffset += inBufferUsedLength; + } else { + ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr); - size_t numOutBytes = - mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; - - if (decoderErr == AAC_DEC_OK) { - if (!outputDelayRingBufferPutSamples(tmpOutBuffer, - mStreamInfo->frameSize * mStreamInfo->numChannels)) { - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - return; - } - } else { - ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr); - - memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow - - if (!outputDelayRingBufferPutSamples(tmpOutBuffer, - mStreamInfo->frameSize * mStreamInfo->numChannels)) { - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - return; - } + memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow - // Discard input buffer. - inHeader->nFilledLen = 0; + if (!outputDelayRingBufferPutSamples(tmpOutBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels)) { + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; + } - aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); + // Discard input buffer. + inHeader->nFilledLen = 0; + + aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); + + // fall through + } + + /* + * AAC+/eAAC+ streams can be signalled in two ways: either explicitly + * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual + * rate system and the sampling rate in the final output is actually + * doubled compared with the core AAC decoder sampling rate. + * + * Explicit signalling is done by explicitly defining SBR audio object + * type in the bitstream. Implicit signalling is done by embedding + * SBR content in AAC extension payload specific to SBR, and hence + * requires an AAC decoder to perform pre-checks on actual audio frames. + * + * Thus, we could not say for sure whether a stream is + * AAC+/eAAC+ until the first data frame is decoded. + */ + if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1 + if (mStreamInfo->sampleRate != prevSampleRate || + mStreamInfo->numChannels != prevNumChannels) { + ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", + prevSampleRate, mStreamInfo->sampleRate, + prevNumChannels, mStreamInfo->numChannels); - // fall through - } + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; - /* - * AAC+/eAAC+ streams can be signalled in two ways: either explicitly - * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual - * rate system and the sampling rate in the final output is actually - * doubled compared with the core AAC decoder sampling rate. - * - * Explicit signalling is done by explicitly defining SBR audio object - * type in the bitstream. Implicit signalling is done by embedding - * SBR content in AAC extension payload specific to SBR, and hence - * requires an AAC decoder to perform pre-checks on actual audio frames. - * - * Thus, we could not say for sure whether a stream is - * AAC+/eAAC+ until the first data frame is decoded. - */ - if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1 - if (mStreamInfo->sampleRate != prevSampleRate || - mStreamInfo->numChannels != prevNumChannels) { - ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", - prevSampleRate, mStreamInfo->sampleRate, - prevNumChannels, mStreamInfo->numChannels); - - notify(OMX_EventPortSettingsChanged, 1, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; - - if (inHeader->nFilledLen == 0) { - inInfo->mOwnedByUs = false; - mInputBufferCount++; - inQueue.erase(inQueue.begin()); - mLastInHeader = NULL; - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; - } - return; + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + mInputBufferCount++; + inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; } - } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { - ALOGW("Invalid AAC stream"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); return; } - if (inHeader && inHeader->nFilledLen == 0) { - inInfo->mOwnedByUs = false; - mInputBufferCount++; - inQueue.erase(inQueue.begin()); - mLastInHeader = NULL; - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; - } else { - ALOGV("inHeader->nFilledLen = %d", inHeader ? inHeader->nFilledLen : 0); - } - } while (decoderErr == AAC_DEC_OK); + } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { + ALOGW("Invalid AAC stream"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; + } + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + mInputBufferCount++; + inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } else { + ALOGV("inHeader->nFilledLen = %d", inHeader->nFilledLen); + } } int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels; @@ -817,9 +809,8 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { INT_PCM *outBuffer = reinterpret_cast(outHeader->pBuffer + outHeader->nOffset); - int samplesize = mStreamInfo->numChannels * sizeof(int16_t); if (outHeader->nOffset - + mStreamInfo->frameSize * samplesize + + mStreamInfo->frameSize * mStreamInfo->numChannels * sizeof(int16_t) > outHeader->nAllocLen) { ALOGE("buffer overflow"); mSignalledError = true; @@ -827,67 +818,17 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { return; } - - int available = outputDelayRingBufferSamplesAvailable(); - int numSamples = outHeader->nAllocLen / samplesize; - if (numSamples > available) { - numSamples = available; - } - int64_t currentTime = 0; - if (available) { - - int numFrames = numSamples / (mStreamInfo->frameSize * mStreamInfo->numChannels); - numSamples = numFrames * (mStreamInfo->frameSize * mStreamInfo->numChannels); - - ALOGV("%d samples available (%d), or %d frames", - numSamples, available, numFrames); - int64_t *nextTimeStamp = &mBufferTimestamps.editItemAt(0); - currentTime = *nextTimeStamp; - int32_t *currentBufLeft = &mBufferSizes.editItemAt(0); - for (int i = 0; i < numFrames; i++) { - int32_t decodedSize = mDecodedSizes.itemAt(0); - mDecodedSizes.removeAt(0); - ALOGV("decoded %d of %d", decodedSize, *currentBufLeft); - if (*currentBufLeft > decodedSize) { - // adjust/interpolate next time stamp - *currentBufLeft -= decodedSize; - *nextTimeStamp += mStreamInfo->aacSamplesPerFrame * - 1000000ll / mStreamInfo->sampleRate; - ALOGV("adjusted nextTimeStamp/size to %lld/%d", - *nextTimeStamp, *currentBufLeft); - } else { - // move to next timestamp in list - if (mBufferTimestamps.size() > 0) { - mBufferTimestamps.removeAt(0); - nextTimeStamp = &mBufferTimestamps.editItemAt(0); - mBufferSizes.removeAt(0); - currentBufLeft = &mBufferSizes.editItemAt(0); - ALOGV("moved to next time/size: %lld/%d", - *nextTimeStamp, *currentBufLeft); - } - // try to limit output buffer size to match input buffers - // (e.g when an input buffer contained 4 "sub" frames, output - // at most 4 decoded units in the corresponding output buffer) - // This is optional. Remove the next three lines to fill the output - // buffer with as many units as available. - numFrames = i + 1; - numSamples = numFrames * mStreamInfo->frameSize * mStreamInfo->numChannels; - break; - } - } - - ALOGV("getting %d from ringbuffer", numSamples); - int32_t ns = outputDelayRingBufferGetSamples(outBuffer, numSamples); - if (ns != numSamples) { - ALOGE("not a complete frame of samples available"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); - return; - } + int32_t ns = outputDelayRingBufferGetSamples(outBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels); // TODO: check for overflow + if (ns != mStreamInfo->frameSize * mStreamInfo->numChannels) { + ALOGE("not a complete frame of samples available"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; } - outHeader->nFilledLen = numSamples * sizeof(int16_t); - + outHeader->nFilledLen = mStreamInfo->frameSize * mStreamInfo->numChannels + * sizeof(int16_t); if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) { outHeader->nFlags = OMX_BUFFERFLAG_EOS; mEndOfOutput = true; @@ -895,13 +836,13 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { outHeader->nFlags = 0; } - outHeader->nTimeStamp = currentTime; + outHeader->nTimeStamp = mAnchorTimes.isEmpty() ? 0 : mAnchorTimes.itemAt(0); + mAnchorTimes.removeAt(0); mOutputBufferCount++; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; - ALOGV("out timestamp %lld / %d", outHeader->nTimeStamp, outHeader->nFilledLen); notifyFillBufferDone(outHeader); outHeader = NULL; } @@ -936,10 +877,8 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { outHeader->nFilledLen = 0; outHeader->nFlags = OMX_BUFFERFLAG_EOS; - outHeader->nTimeStamp = mBufferTimestamps.itemAt(0); - mBufferTimestamps.clear(); - mBufferSizes.clear(); - mDecodedSizes.clear(); + outHeader->nTimeStamp = mAnchorTimes.itemAt(0); + mAnchorTimes.removeAt(0); mOutputBufferCount++; outInfo->mOwnedByUs = false; @@ -960,9 +899,7 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { // depend on fragments from the last one decoded. // drain all existing data drainDecoder(); - mBufferTimestamps.clear(); - mBufferSizes.clear(); - mDecodedSizes.clear(); + mAnchorTimes.clear(); mLastInHeader = NULL; } else { while (outputDelayRingBufferSamplesAvailable() > 0) { @@ -1018,9 +955,7 @@ void SoftAAC2::onReset() { mOutputDelayRingBufferReadPos = 0; mEndOfInput = false; mEndOfOutput = false; - mBufferTimestamps.clear(); - mBufferSizes.clear(); - mDecodedSizes.clear(); + mAnchorTimes.clear(); mLastInHeader = NULL; // To make the codec behave the same before and after a reset, we need to invalidate the diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h index 9fcb598..865bd15 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.h +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h @@ -59,9 +59,8 @@ private: size_t mOutputBufferCount; bool mSignalledError; OMX_BUFFERHEADERTYPE *mLastInHeader; - Vector mBufferSizes; - Vector mDecodedSizes; - Vector mBufferTimestamps; + int64_t mCurrentInputTime; + Vector mAnchorTimes; CDrcPresModeWrapper mDrcWrap; -- cgit v1.1 From b9b87fe9d9f3d91c05300a22920d7227a3f8eb83 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 10 Sep 2014 13:53:21 -0700 Subject: mediaplayer: release MediaBuffer in stale input buffers Bug: 17454455 Change-Id: If63a6e42f96851d6c10fdec11360f0dabae9bf50 --- media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 8ce7baf..163a0b5 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -595,7 +595,18 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { { if (!isStaleReply(msg)) { onInputBufferFilled(msg); + } else { + /* release any MediaBuffer passed in the stale buffer */ + sp buffer; + MediaBuffer *mediaBuffer = NULL; + if (msg->findBuffer("buffer", &buffer) && + buffer->meta()->findPointer( + "mediaBuffer", (void **)&mediaBuffer) && + mediaBuffer != NULL) { + mediaBuffer->release(); + } } + break; } -- cgit v1.1 From a3d078b02d22ee2329e3778f63974be59296f64f Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 5 Sep 2014 09:28:24 -0700 Subject: Fix AAC timestamps for multiple aac frames per input buffer Support multiple aac frames per input buffer also for non-ADTS streams, now also works with 5.1 audio. Bug: 16715379 --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 323 +++++++++++++++--------- media/libstagefright/codecs/aacdec/SoftAAC2.h | 5 +- 2 files changed, 200 insertions(+), 128 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 8b4dd6f..4569c1c 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#define LOG_TAG "SoftAAC2" //#define LOG_NDEBUG 0 +#define LOG_TAG "SoftAAC2" #include #include "SoftAAC2.h" @@ -68,7 +68,6 @@ SoftAAC2::SoftAAC2( mOutputBufferCount(0), mSignalledError(false), mLastInHeader(NULL), - mCurrentInputTime(0), mOutputPortSettingsChange(NONE) { initPorts(); CHECK_EQ(initDecoder(), (status_t)OK); @@ -610,9 +609,24 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL); return; } + + // insert buffer size and time stamp + mBufferSizes.add(inBufferLength[0]); + if (mLastInHeader != inHeader) { + mBufferTimestamps.add(inHeader->nTimeStamp); + mLastInHeader = inHeader; + } else { + int64_t currentTime = mBufferTimestamps.top(); + currentTime += mStreamInfo->aacSamplesPerFrame * + 1000000ll / mStreamInfo->sampleRate; + mBufferTimestamps.add(currentTime); + } } else { inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; inBufferLength[0] = inHeader->nFilledLen; + mLastInHeader = inHeader; + mBufferTimestamps.add(inHeader->nTimeStamp); + mBufferSizes.add(inHeader->nFilledLen); } // Fill and decode @@ -621,136 +635,136 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { INT prevSampleRate = mStreamInfo->sampleRate; INT prevNumChannels = mStreamInfo->numChannels; - if (inHeader != mLastInHeader) { - mLastInHeader = inHeader; - mCurrentInputTime = inHeader->nTimeStamp; - } else { - if (mStreamInfo->sampleRate) { - mCurrentInputTime += mStreamInfo->aacSamplesPerFrame * - 1000000ll / mStreamInfo->sampleRate; - } else { - ALOGW("no sample rate yet"); - } - } - mAnchorTimes.add(mCurrentInputTime); aacDecoder_Fill(mAACDecoder, inBuffer, inBufferLength, bytesValid); - // run DRC check - mDrcWrap.submitStreamData(mStreamInfo); - mDrcWrap.update(); + // run DRC check + mDrcWrap.submitStreamData(mStreamInfo); + mDrcWrap.update(); - AAC_DECODER_ERROR decoderErr = - aacDecoder_DecodeFrame(mAACDecoder, - tmpOutBuffer, - 2048 * MAX_CHANNEL_COUNT, - 0 /* flags */); + UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; + inHeader->nFilledLen -= inBufferUsedLength; + inHeader->nOffset += inBufferUsedLength; - if (decoderErr != AAC_DEC_OK) { - ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); - } - - if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { - ALOGE("AAC_DEC_NOT_ENOUGH_BITS should never happen"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); - return; - } + AAC_DECODER_ERROR decoderErr; + do { + if (outputDelayRingBufferSamplesLeft() < + (mStreamInfo->frameSize * mStreamInfo->numChannels)) { + ALOGV("skipping decode: not enough space left in ringbuffer"); + break; + } - if (bytesValid[0] != 0) { - ALOGE("bytesValid[0] != 0 should never happen"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); - return; - } + int numconsumed = mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes; + decoderErr = aacDecoder_DecodeFrame(mAACDecoder, + tmpOutBuffer, + 2048 * MAX_CHANNEL_COUNT, + 0 /* flags */); - size_t numOutBytes = - mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; + numconsumed = (mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes) - numconsumed; + if (numconsumed != 0) { + mDecodedSizes.add(numconsumed); + } - if (decoderErr == AAC_DEC_OK) { - if (!outputDelayRingBufferPutSamples(tmpOutBuffer, - mStreamInfo->frameSize * mStreamInfo->numChannels)) { - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - return; + if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { + break; } - UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; - inHeader->nFilledLen -= inBufferUsedLength; - inHeader->nOffset += inBufferUsedLength; - } else { - ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr); - memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow + if (decoderErr != AAC_DEC_OK) { + ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); + } - if (!outputDelayRingBufferPutSamples(tmpOutBuffer, - mStreamInfo->frameSize * mStreamInfo->numChannels)) { + if (bytesValid[0] != 0) { + ALOGE("bytesValid[0] != 0 should never happen"); mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); return; } - // Discard input buffer. - inHeader->nFilledLen = 0; - - aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); - - // fall through - } - - /* - * AAC+/eAAC+ streams can be signalled in two ways: either explicitly - * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual - * rate system and the sampling rate in the final output is actually - * doubled compared with the core AAC decoder sampling rate. - * - * Explicit signalling is done by explicitly defining SBR audio object - * type in the bitstream. Implicit signalling is done by embedding - * SBR content in AAC extension payload specific to SBR, and hence - * requires an AAC decoder to perform pre-checks on actual audio frames. - * - * Thus, we could not say for sure whether a stream is - * AAC+/eAAC+ until the first data frame is decoded. - */ - if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1 - if (mStreamInfo->sampleRate != prevSampleRate || - mStreamInfo->numChannels != prevNumChannels) { - ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", - prevSampleRate, mStreamInfo->sampleRate, - prevNumChannels, mStreamInfo->numChannels); + size_t numOutBytes = + mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; - notify(OMX_EventPortSettingsChanged, 1, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; + if (decoderErr == AAC_DEC_OK) { + if (!outputDelayRingBufferPutSamples(tmpOutBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels)) { + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; + } + } else { + ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr); + + memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow - if (inHeader->nFilledLen == 0) { - inInfo->mOwnedByUs = false; - mInputBufferCount++; - inQueue.erase(inQueue.begin()); - mLastInHeader = NULL; - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; + if (!outputDelayRingBufferPutSamples(tmpOutBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels)) { + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; } + + // Discard input buffer. + inHeader->nFilledLen = 0; + + aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); + + // fall through + } + + /* + * AAC+/eAAC+ streams can be signalled in two ways: either explicitly + * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual + * rate system and the sampling rate in the final output is actually + * doubled compared with the core AAC decoder sampling rate. + * + * Explicit signalling is done by explicitly defining SBR audio object + * type in the bitstream. Implicit signalling is done by embedding + * SBR content in AAC extension payload specific to SBR, and hence + * requires an AAC decoder to perform pre-checks on actual audio frames. + * + * Thus, we could not say for sure whether a stream is + * AAC+/eAAC+ until the first data frame is decoded. + */ + if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1 + if (mStreamInfo->sampleRate != prevSampleRate || + mStreamInfo->numChannels != prevNumChannels) { + ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", + prevSampleRate, mStreamInfo->sampleRate, + prevNumChannels, mStreamInfo->numChannels); + + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + mInputBufferCount++; + inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } + return; + } + } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { + ALOGW("Invalid AAC stream"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); return; } - } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { - ALOGW("Invalid AAC stream"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - return; - } - if (inHeader->nFilledLen == 0) { - inInfo->mOwnedByUs = false; - mInputBufferCount++; - inQueue.erase(inQueue.begin()); - mLastInHeader = NULL; - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; - } else { - ALOGV("inHeader->nFilledLen = %d", inHeader->nFilledLen); - } + if (inHeader && inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + mInputBufferCount++; + inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } else { + ALOGV("inHeader->nFilledLen = %d", inHeader ? inHeader->nFilledLen : 0); + } + } while (decoderErr == AAC_DEC_OK); } int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels; @@ -809,8 +823,9 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { INT_PCM *outBuffer = reinterpret_cast(outHeader->pBuffer + outHeader->nOffset); + int samplesize = mStreamInfo->numChannels * sizeof(int16_t); if (outHeader->nOffset - + mStreamInfo->frameSize * mStreamInfo->numChannels * sizeof(int16_t) + + mStreamInfo->frameSize * samplesize > outHeader->nAllocLen) { ALOGE("buffer overflow"); mSignalledError = true; @@ -818,17 +833,67 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { return; } - int32_t ns = outputDelayRingBufferGetSamples(outBuffer, - mStreamInfo->frameSize * mStreamInfo->numChannels); // TODO: check for overflow - if (ns != mStreamInfo->frameSize * mStreamInfo->numChannels) { - ALOGE("not a complete frame of samples available"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); - return; + + int available = outputDelayRingBufferSamplesAvailable(); + int numSamples = outHeader->nAllocLen / sizeof(int16_t); + if (numSamples > available) { + numSamples = available; + } + int64_t currentTime = 0; + if (available) { + + int numFrames = numSamples / (mStreamInfo->frameSize * mStreamInfo->numChannels); + numSamples = numFrames * (mStreamInfo->frameSize * mStreamInfo->numChannels); + + ALOGV("%d samples available (%d), or %d frames", + numSamples, available, numFrames); + int64_t *nextTimeStamp = &mBufferTimestamps.editItemAt(0); + currentTime = *nextTimeStamp; + int32_t *currentBufLeft = &mBufferSizes.editItemAt(0); + for (int i = 0; i < numFrames; i++) { + int32_t decodedSize = mDecodedSizes.itemAt(0); + mDecodedSizes.removeAt(0); + ALOGV("decoded %d of %d", decodedSize, *currentBufLeft); + if (*currentBufLeft > decodedSize) { + // adjust/interpolate next time stamp + *currentBufLeft -= decodedSize; + *nextTimeStamp += mStreamInfo->aacSamplesPerFrame * + 1000000ll / mStreamInfo->sampleRate; + ALOGV("adjusted nextTimeStamp/size to %lld/%d", + *nextTimeStamp, *currentBufLeft); + } else { + // move to next timestamp in list + if (mBufferTimestamps.size() > 0) { + mBufferTimestamps.removeAt(0); + nextTimeStamp = &mBufferTimestamps.editItemAt(0); + mBufferSizes.removeAt(0); + currentBufLeft = &mBufferSizes.editItemAt(0); + ALOGV("moved to next time/size: %lld/%d", + *nextTimeStamp, *currentBufLeft); + } + // try to limit output buffer size to match input buffers + // (e.g when an input buffer contained 4 "sub" frames, output + // at most 4 decoded units in the corresponding output buffer) + // This is optional. Remove the next three lines to fill the output + // buffer with as many units as available. + numFrames = i + 1; + numSamples = numFrames * mStreamInfo->frameSize * mStreamInfo->numChannels; + break; + } + } + + ALOGV("getting %d from ringbuffer", numSamples); + int32_t ns = outputDelayRingBufferGetSamples(outBuffer, numSamples); + if (ns != numSamples) { + ALOGE("not a complete frame of samples available"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } } - outHeader->nFilledLen = mStreamInfo->frameSize * mStreamInfo->numChannels - * sizeof(int16_t); + outHeader->nFilledLen = numSamples * sizeof(int16_t); + if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) { outHeader->nFlags = OMX_BUFFERFLAG_EOS; mEndOfOutput = true; @@ -836,13 +901,13 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { outHeader->nFlags = 0; } - outHeader->nTimeStamp = mAnchorTimes.isEmpty() ? 0 : mAnchorTimes.itemAt(0); - mAnchorTimes.removeAt(0); + outHeader->nTimeStamp = currentTime; mOutputBufferCount++; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; + ALOGV("out timestamp %lld / %d", outHeader->nTimeStamp, outHeader->nFilledLen); notifyFillBufferDone(outHeader); outHeader = NULL; } @@ -877,8 +942,10 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { outHeader->nFilledLen = 0; outHeader->nFlags = OMX_BUFFERFLAG_EOS; - outHeader->nTimeStamp = mAnchorTimes.itemAt(0); - mAnchorTimes.removeAt(0); + outHeader->nTimeStamp = mBufferTimestamps.itemAt(0); + mBufferTimestamps.clear(); + mBufferSizes.clear(); + mDecodedSizes.clear(); mOutputBufferCount++; outInfo->mOwnedByUs = false; @@ -899,7 +966,9 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { // depend on fragments from the last one decoded. // drain all existing data drainDecoder(); - mAnchorTimes.clear(); + mBufferTimestamps.clear(); + mBufferSizes.clear(); + mDecodedSizes.clear(); mLastInHeader = NULL; } else { while (outputDelayRingBufferSamplesAvailable() > 0) { @@ -955,7 +1024,9 @@ void SoftAAC2::onReset() { mOutputDelayRingBufferReadPos = 0; mEndOfInput = false; mEndOfOutput = false; - mAnchorTimes.clear(); + mBufferTimestamps.clear(); + mBufferSizes.clear(); + mDecodedSizes.clear(); mLastInHeader = NULL; // To make the codec behave the same before and after a reset, we need to invalidate the diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h index 865bd15..9fcb598 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.h +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h @@ -59,8 +59,9 @@ private: size_t mOutputBufferCount; bool mSignalledError; OMX_BUFFERHEADERTYPE *mLastInHeader; - int64_t mCurrentInputTime; - Vector mAnchorTimes; + Vector mBufferSizes; + Vector mDecodedSizes; + Vector mBufferTimestamps; CDrcPresModeWrapper mDrcWrap; -- cgit v1.1 From 200092b7f21d2b98f30b800e79d152636f9ba225 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 15 Aug 2014 15:13:30 -0700 Subject: Clean up AudioTrack position and timestamp handling Replace epoch concept by observing and accumulating server delta positions. The advantage of using server deltas instead of absolute values is that they (1) are not sensitive to 32-bit wraparound, (2) are not sensitive to server behavior for stop(), and (3) prepare for future 64-bit client positions without requiring 64-bit positions on server. Add comments to AudioTrack::getTimestamp() and friends that the timestamp output parameter is undefined on error. Don't allow getTimestamp to return a negative frame position after stop(). Accumulate the client released frames, which may be useful for a future API. Bug: 11815245 Change-Id: I652940fa2db2f34a78c012a3ead0d9204fa29c6e --- media/libmedia/AudioTrack.cpp | 91 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 18 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index d87e6f5..ff7da83 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -398,7 +398,7 @@ status_t AudioTrack::set( } // create the IAudioTrack - status = createTrack_l(0 /*epoch*/); + status = createTrack_l(); if (status != NO_ERROR) { if (mAudioTrackThread != 0) { @@ -417,6 +417,9 @@ status_t AudioTrack::set( mMarkerReached = false; mNewPosition = 0; mUpdatePeriod = 0; + mServer = 0; + mPosition = 0; + mReleased = 0; AudioSystem::acquireAudioSessionId(mSessionId, mClientPid); mSequence = 1; mObservedSequence = mSequence; @@ -443,14 +446,16 @@ status_t AudioTrack::start() } else { mState = STATE_ACTIVE; } + (void) updateAndGetPosition_l(); if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) { // reset current position as seen by client to 0 - mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition()); + mPosition = 0; + mReleased = 0; // force refresh of remaining frames by processAudioBuffer() as last // write before stop could be partial. mRefreshRemaining = true; } - mNewPosition = mProxy->getPosition() + mUpdatePeriod; + mNewPosition = mPosition + mUpdatePeriod; int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags); sp t = mAudioTrackThread; @@ -709,7 +714,7 @@ void AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount) { // FIXME If setting a loop also sets position to start of loop, then // this is correct. Otherwise it should be removed. - mNewPosition = mProxy->getPosition() + mUpdatePeriod; + mNewPosition = updateAndGetPosition_l() + mUpdatePeriod; mLoopPeriod = loopCount != 0 ? loopEnd - loopStart : 0; mStaticProxy->setLoop(loopStart, loopEnd, loopCount); } @@ -751,7 +756,7 @@ status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod) } AutoMutex lock(mLock); - mNewPosition = mProxy->getPosition() + updatePeriod; + mNewPosition = updateAndGetPosition_l() + updatePeriod; mUpdatePeriod = updatePeriod; return NO_ERROR; @@ -791,7 +796,7 @@ status_t AudioTrack::setPosition(uint32_t position) if (mState == STATE_ACTIVE) { return INVALID_OPERATION; } - mNewPosition = mProxy->getPosition() + mUpdatePeriod; + mNewPosition = updateAndGetPosition_l() + mUpdatePeriod; mLoopPeriod = 0; // FIXME Check whether loops and setting position are incompatible in old code. // If we use setLoop for both purposes we lose the capability to set the position while looping. @@ -800,7 +805,7 @@ status_t AudioTrack::setPosition(uint32_t position) return NO_ERROR; } -status_t AudioTrack::getPosition(uint32_t *position) const +status_t AudioTrack::getPosition(uint32_t *position) { if (position == NULL) { return BAD_VALUE; @@ -823,8 +828,8 @@ status_t AudioTrack::getPosition(uint32_t *position) const *position = dspFrames; } else { // IAudioTrack::stop() isn't synchronous; we don't know when presentation completes - *position = (mState == STATE_STOPPED || mState == STATE_FLUSHED) ? 0 : - mProxy->getPosition(); + *position = (mState == STATE_STOPPED || mState == STATE_FLUSHED) ? + 0 : updateAndGetPosition_l(); } return NO_ERROR; } @@ -881,7 +886,7 @@ status_t AudioTrack::attachAuxEffect(int effectId) // ------------------------------------------------------------------------- // must be called with mLock held -status_t AudioTrack::createTrack_l(size_t epoch) +status_t AudioTrack::createTrack_l() { status_t status; const sp& audioFlinger = AudioSystem::get_audio_flinger(); @@ -1184,7 +1189,6 @@ status_t AudioTrack::createTrack_l(size_t epoch) mProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY); mProxy->setSendLevel(mSendLevel); mProxy->setSampleRate(mSampleRate); - mProxy->setEpoch(epoch); mProxy->setMinimum(mNotificationFramesAct); mDeathNotifier = new DeathNotifier(this); @@ -1319,6 +1323,7 @@ void AudioTrack::releaseBuffer(Buffer* audioBuffer) buffer.mRaw = audioBuffer->raw; AutoMutex lock(mLock); + mReleased += stepCount; mInUnderrun = false; mProxy->releaseBuffer(&buffer); @@ -1531,7 +1536,7 @@ nsecs_t AudioTrack::processAudioBuffer() } // Get current position of server - size_t position = mProxy->getPosition(); + size_t position = updateAndGetPosition_l(); // Manage marker callback bool markerReached = false; @@ -1796,14 +1801,18 @@ status_t AudioTrack::restoreTrack_l(const char *from) return DEAD_OBJECT; } - // if the new IAudioTrack is created, createTrack_l() will modify the + // save the old static buffer position + size_t bufferPosition = mStaticProxy != NULL ? mStaticProxy->getBufferPosition() : 0; + + // If a new IAudioTrack is successfully created, createTrack_l() will modify the // following member variables: mAudioTrack, mCblkMemory and mCblk. - // It will also delete the strong references on previous IAudioTrack and IMemory + // It will also delete the strong references on previous IAudioTrack and IMemory. + // If a new IAudioTrack cannot be created, the previous (dead) instance will be left intact. + result = createTrack_l(); // take the frames that will be lost by track recreation into account in saved position - size_t position = mProxy->getPosition() + mProxy->getFramesFilled(); - size_t bufferPosition = mStaticProxy != NULL ? mStaticProxy->getBufferPosition() : 0; - result = createTrack_l(position /*epoch*/); + (void) updateAndGetPosition_l(); + mPosition = mReleased; if (result == NO_ERROR) { // continue playback from last known position, but @@ -1838,6 +1847,27 @@ status_t AudioTrack::restoreTrack_l(const char *from) return result; } +uint32_t AudioTrack::updateAndGetPosition_l() +{ + // This is the sole place to read server consumed frames + uint32_t newServer = mProxy->getPosition(); + int32_t delta = newServer - mServer; + mServer = newServer; + // TODO There is controversy about whether there can be "negative jitter" in server position. + // This should be investigated further, and if possible, it should be addressed. + // A more definite failure mode is infrequent polling by client. + // One could call (void)getPosition_l() in releaseBuffer(), + // so mReleased and mPosition are always lock-step as best possible. + // That should ensure delta never goes negative for infrequent polling + // unless the server has more than 2^31 frames in its buffer, + // in which case the use of uint32_t for these counters has bigger issues. + if (delta < 0) { + ALOGE("detected illegal retrograde motion by the server: mServer advanced by %d", delta); + delta = 0; + } + return mPosition += (uint32_t) delta; +} + status_t AudioTrack::setParameters(const String8& keyValuePairs) { AutoMutex lock(mLock); @@ -1854,9 +1884,34 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) if (mState != STATE_ACTIVE && mState != STATE_PAUSED) { return INVALID_OPERATION; } + // The presented frame count must always lag behind the consumed frame count. + // To avoid a race, read the presented frames first. This ensures that presented <= consumed. status_t status = mAudioTrack->getTimestamp(timestamp); if (status == NO_ERROR) { - timestamp.mPosition += mProxy->getEpoch(); + // Update the mapping between local consumed (mPosition) and server consumed (mServer) + (void) updateAndGetPosition_l(); + // Server consumed (mServer) and presented both use the same server time base, + // and server consumed is always >= presented. + // The delta between these represents the number of frames in the buffer pipeline. + // If this delta between these is greater than the client position, it means that + // actually presented is still stuck at the starting line (figuratively speaking), + // waiting for the first frame to go by. So we can't report a valid timestamp yet. + if ((uint32_t) (mServer - timestamp.mPosition) > mPosition) { + return INVALID_OPERATION; + } + // Convert timestamp position from server time base to client time base. + // TODO The following code should work OK now because timestamp.mPosition is 32-bit. + // But if we change it to 64-bit then this could fail. + // If (mPosition - mServer) can be negative then should use: + // (int32_t)(mPosition - mServer) + timestamp.mPosition += mPosition - mServer; + // Immediately after a call to getPosition_l(), mPosition and + // mServer both represent the same frame position. mPosition is + // in client's point of view, and mServer is in server's point of + // view. So the difference between them is the "fudge factor" + // between client and server views due to stop() and/or new + // IAudioTrack. And timestamp.mPosition is initially in server's + // point of view, so we need to apply the same fudge factor to it. } return status; } -- cgit v1.1 From a694dd0ce2caaf921f7bc894df87a5d52594b4eb Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Fri, 5 Sep 2014 14:25:39 -0700 Subject: stagefright: add adaptive playback support to SoftMPEG decoder. This covers both MPEG4 and H263 adaptive playback. Bug: 17326758 Change-Id: I80a67b7f3ceab05e792f0a459439a8274bd78e20 --- .../codecs/m4v_h263/dec/SoftMPEG4.cpp | 50 ++++++++++++---------- .../libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h | 2 +- .../libstagefright/codecs/m4v_h263/dec/src/vop.cpp | 2 +- .../colorconversion/SoftwareRenderer.cpp | 4 +- .../include/SoftVideoDecoderOMXComponent.h | 3 +- .../omx/SoftVideoDecoderOMXComponent.cpp | 15 ++++++- 6 files changed, 47 insertions(+), 29 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp index 0d1ab71..5b2ab84 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp @@ -134,6 +134,12 @@ void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) { } uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset; + uint32_t *start_code = (uint32_t *)bitstream; + bool volHeader = *start_code == 0xB0010000; + if (volHeader) { + PVCleanUpVideoDecoder(mHandle); + mInitialized = false; + } if (!mInitialized) { uint8_t *vol_data[1]; @@ -141,7 +147,7 @@ void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) { vol_data[0] = NULL; - if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { + if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) || volHeader) { vol_data[0] = bitstream; vol_size = inHeader->nFilledLen; } @@ -169,21 +175,26 @@ void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) { PVSetPostProcType((VideoDecControls *) mHandle, 0); + bool hasFrameData = false; if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; + } else if (volHeader) { + hasFrameData = true; } mInitialized = true; - if (mode == MPEG4_MODE && portSettingsChanged()) { + if (mode == MPEG4_MODE && handlePortSettingsChange()) { return; } - continue; + if (!hasFrameData) { + continue; + } } if (!mFramesConfigured) { @@ -223,7 +234,9 @@ void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) { return; } - if (portSettingsChanged()) { + // H263 doesn't have VOL header, the frame size information is in short header, i.e. the + // decoder may detect size change after PVDecodeVideoFrame. + if (handlePortSettingsChange()) { return; } @@ -269,7 +282,7 @@ void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) { } } -bool SoftMPEG4::portSettingsChanged() { +bool SoftMPEG4::handlePortSettingsChange() { uint32_t disp_width, disp_height; PVGetVideoDimensions(mHandle, (int32 *)&disp_width, (int32 *)&disp_height); @@ -282,25 +295,20 @@ bool SoftMPEG4::portSettingsChanged() { ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d", disp_width, disp_height, buf_width, buf_height); - if (mCropWidth != disp_width - || mCropHeight != disp_height) { + bool cropChanged = false; + if (mCropWidth != disp_width || mCropHeight != disp_height) { mCropLeft = 0; mCropTop = 0; mCropWidth = disp_width; mCropHeight = disp_height; - - notify(OMX_EventPortSettingsChanged, - 1, - OMX_IndexConfigCommonOutputCrop, - NULL); + cropChanged = true; } - if (buf_width != mWidth || buf_height != mHeight) { - mWidth = buf_width; - mHeight = buf_height; - - updatePortDefinitions(); - + bool portWillReset = false; + const bool fakeStride = true; + SoftVideoDecoderOMXComponent::handlePortSettingsChange( + &portWillReset, buf_width, buf_height, cropChanged, fakeStride); + if (portWillReset) { if (mMode == MODE_H263) { PVCleanUpVideoDecoder(mHandle); @@ -318,13 +326,9 @@ bool SoftMPEG4::portSettingsChanged() { } mFramesConfigured = false; - - notify(OMX_EventPortSettingsChanged, 1, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; - return true; } - return false; + return portWillReset; } void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) { diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h index de14aaf..8a06a00 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h +++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h @@ -67,7 +67,7 @@ private: status_t initDecoder(); virtual void updatePortDefinitions(); - bool portSettingsChanged(); + bool handlePortSettingsChange(); DISALLOW_EVIL_CONSTRUCTORS(SoftMPEG4); }; diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp index b3c350f..b03ec8c 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp @@ -1426,7 +1426,7 @@ PV_STATUS DecodeShortHeader(VideoDecData *video, Vop *currVop) video->nBitsForMBID = CalcNumBits((uint)video->nTotalMB - 1); /* otherwise calculate above */ } size = (int32)video->width * video->height; - if (video->currVop->predictionType == P_VOP && size > video->videoDecControls->size) + if (currVop->predictionType == P_VOP && size > video->videoDecControls->size) { status = PV_FAIL; goto return_point; diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp index cc98da0..1899b40 100644 --- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp +++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp @@ -65,8 +65,8 @@ void SoftwareRenderer::resetFormatIfChanged(const sp &format) { CHECK(format->findInt32("color-format", &colorFormatNew)); int32_t widthNew, heightNew; - CHECK(format->findInt32("width", &widthNew)); - CHECK(format->findInt32("height", &heightNew)); + CHECK(format->findInt32("stride", &widthNew)); + CHECK(format->findInt32("slice-height", &heightNew)); int32_t cropLeftNew, cropTopNew, cropRightNew, cropBottomNew; if (!format->findRect( diff --git a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h index 4a6ab63..8cb8ed7 100644 --- a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h +++ b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h @@ -66,7 +66,8 @@ protected: virtual void updatePortDefinitions(bool updateCrop = true); void handlePortSettingsChange( - bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged = false); + bool *portWillReset, uint32_t width, uint32_t height, + bool cropChanged = false, bool fakeStride = false); void copyYV12FrameToOutputBuffer( uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV, diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp index e533fdd..741ac96 100644 --- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp +++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp @@ -151,7 +151,7 @@ void SoftVideoDecoderOMXComponent::updatePortDefinitions(bool updateCrop) { } void SoftVideoDecoderOMXComponent::handlePortSettingsChange( - bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged) { + bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged, bool fakeStride) { *portWillReset = false; bool sizeChanged = (width != mWidth || height != mHeight); @@ -177,6 +177,19 @@ void SoftVideoDecoderOMXComponent::handlePortSettingsChange( *portWillReset = true; } else { updatePortDefinitions(updateCrop); + + if (fakeStride) { + // MAJOR HACK that is not pretty, it's just to fool the renderer to read the correct + // data. + // Some software decoders (e.g. SoftMPEG4) fill decoded frame directly to output + // buffer without considering the output buffer stride and slice height. So this is + // used to signal how the buffer is arranged. The alternative is to re-arrange the + // output buffer in SoftMPEG4, but that results in memcopies. + OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef; + def->format.video.nStride = mWidth; + def->format.video.nSliceHeight = mHeight; + } + notify(OMX_EventPortSettingsChanged, kOutputPortIndex, OMX_IndexConfigCommonOutputCrop, NULL); } -- cgit v1.1 From 54ef1bae010f12dfe6a40ff4452695b1b11ff449 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Mon, 8 Sep 2014 18:55:34 -0700 Subject: StagefrightRecorder: default to codec and fps from camcorder low profile Bug: 16870964 Change-Id: I18425af630d3f041a3bcf77fbae3f07856fe8af2 --- .../libmediaplayerservice/StagefrightRecorder.cpp | 38 ++++++++++++++++++---- media/libmediaplayerservice/StagefrightRecorder.h | 1 + 2 files changed, 33 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index e2bcb1e..b904aa8 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -183,11 +183,7 @@ status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) { return BAD_VALUE; } - if (ve == VIDEO_ENCODER_DEFAULT) { - mVideoEncoder = VIDEO_ENCODER_H263; - } else { - mVideoEncoder = ve; - } + mVideoEncoder = ve; return OK; } @@ -1033,6 +1029,7 @@ status_t StagefrightRecorder::setupRTPRecording() { if (mAudioSource != AUDIO_SOURCE_CNT) { source = createAudioSource(); } else { + setDefaultVideoEncoderIfNecessary(); sp mediaSource; status_t err = setupMediaSource(&mediaSource); @@ -1074,6 +1071,7 @@ status_t StagefrightRecorder::setupMPEG2TSRecording() { if (mVideoSource < VIDEO_SOURCE_LIST_END) { if (mVideoEncoder != VIDEO_ENCODER_H264) { + ALOGE("MPEG2TS recording only supports H.264 encoding!"); return ERROR_UNSUPPORTED; } @@ -1108,6 +1106,12 @@ status_t StagefrightRecorder::setupMPEG2TSRecording() { void StagefrightRecorder::clipVideoFrameRate() { ALOGV("clipVideoFrameRate: encoder %d", mVideoEncoder); + if (mFrameRate == -1) { + mFrameRate = mEncoderProfiles->getCamcorderProfileParamByName( + "vid.fps", mCameraId, CAMCORDER_QUALITY_LOW); + ALOGW("Using default video fps %d", mFrameRate); + } + int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName( "enc.vid.fps.min", mVideoEncoder); int maxFrameRate = mEncoderProfiles->getVideoEncoderParamByName( @@ -1243,6 +1247,27 @@ void StagefrightRecorder::setDefaultProfileIfNecessary() { } } +void StagefrightRecorder::setDefaultVideoEncoderIfNecessary() { + if (mVideoEncoder == VIDEO_ENCODER_DEFAULT) { + if (mOutputFormat == OUTPUT_FORMAT_WEBM) { + // default to VP8 for WEBM recording + mVideoEncoder = VIDEO_ENCODER_VP8; + } else { + // pick the default encoder for CAMCORDER_QUALITY_LOW + int videoCodec = mEncoderProfiles->getCamcorderProfileParamByName( + "vid.codec", mCameraId, CAMCORDER_QUALITY_LOW); + + if (videoCodec > VIDEO_ENCODER_DEFAULT && + videoCodec < VIDEO_ENCODER_LIST_END) { + mVideoEncoder = (video_encoder)videoCodec; + } else { + // default to H.264 if camcorder profile not available + mVideoEncoder = VIDEO_ENCODER_H264; + } + } + } +} + status_t StagefrightRecorder::checkAudioEncoderCapabilities() { clipAudioBitRate(); clipAudioSampleRate(); @@ -1562,6 +1587,7 @@ status_t StagefrightRecorder::setupMPEG4orWEBMRecording() { } if (mVideoSource < VIDEO_SOURCE_LIST_END) { + setDefaultVideoEncoderIfNecessary(); sp mediaSource; err = setupMediaSource(&mediaSource); @@ -1721,7 +1747,7 @@ status_t StagefrightRecorder::reset() { // Default parameters mOutputFormat = OUTPUT_FORMAT_THREE_GPP; mAudioEncoder = AUDIO_ENCODER_AMR_NB; - mVideoEncoder = VIDEO_ENCODER_H263; + mVideoEncoder = VIDEO_ENCODER_DEFAULT; mVideoWidth = 176; mVideoHeight = 144; mFrameRate = -1; diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 9062f30..54c38d3 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -178,6 +178,7 @@ private: void clipAudioSampleRate(); void clipNumberOfAudioChannels(); void setDefaultProfileIfNecessary(); + void setDefaultVideoEncoderIfNecessary(); StagefrightRecorder(const StagefrightRecorder &); -- cgit v1.1 From 84f5278a36f2816cc38f64307b4a1ad8a6818507 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 11 Sep 2014 10:01:55 -0700 Subject: avoid kWhatReadBuffer message spam in GenericSource When playig WVM video, an extra readBuffer is posted for each dequeueAccessUnit, resulting in an unbounded number of messages. Bug: 17472979 Change-Id: Ice92ccf2454bf7a70856a4a8b535cefffc9e61ac --- .../nuplayer/GenericSource.cpp | 21 +++++++++++++++++---- .../libmediaplayerservice/nuplayer/GenericSource.h | 2 ++ 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 8e1987a..ec1a9a0 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -54,7 +54,8 @@ NuPlayer::GenericSource::GenericSource( mDrmManagerClient(NULL), mMetaDataSize(-1ll), mBitrate(-1ll), - mPollBufferingGeneration(0) { + mPollBufferingGeneration(0), + mPendingReadBufferTypes(0) { resetDataSource(); DataSource::RegisterDefaultSniffers(); } @@ -1148,15 +1149,27 @@ sp NuPlayer::GenericSource::mediaBufferToABuffer( } void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) { - sp msg = new AMessage(kWhatReadBuffer, id()); - msg->setInt32("trackType", trackType); - msg->post(); + Mutex::Autolock _l(mReadBufferLock); + + if ((mPendingReadBufferTypes & (1 << trackType)) == 0) { + mPendingReadBufferTypes |= (1 << trackType); + sp msg = new AMessage(kWhatReadBuffer, id()); + msg->setInt32("trackType", trackType); + msg->post(); + } } void NuPlayer::GenericSource::onReadBuffer(sp msg) { int32_t tmpType; CHECK(msg->findInt32("trackType", &tmpType)); media_track_type trackType = (media_track_type)tmpType; + { + // only protect the variable change, as readBuffer may + // take considerable time. This may result in one extra + // read being processed, but that is benign. + Mutex::Autolock _l(mReadBufferLock); + mPendingReadBufferTypes &= ~(1 << trackType); + } readBuffer(trackType); } diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 50ff98a..c70c48e 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -131,6 +131,8 @@ private: off64_t mMetaDataSize; int64_t mBitrate; int32_t mPollBufferingGeneration; + uint32_t mPendingReadBufferTypes; + mutable Mutex mReadBufferLock; sp mLooper; -- cgit v1.1 From af52c1a1ccab588ae4ed94521f202ed9474eccec Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 11 Sep 2014 15:38:54 -0700 Subject: GenericSource: move track packet init from start to prepare Bug: 17244704 Change-Id: I15eba0e4d2a178cc0ba46bbc17be0e6d95e76935 --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 8e1987a..3a28ecb 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -169,6 +169,8 @@ status_t NuPlayer::GenericSource::initFromDataSource() { if (mAudioTrack.mSource == NULL) { mAudioTrack.mIndex = i; mAudioTrack.mSource = track; + mAudioTrack.mPackets = + new AnotherPacketSource(mAudioTrack.mSource->getFormat()); if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { mAudioIsVorbis = true; @@ -180,6 +182,8 @@ status_t NuPlayer::GenericSource::initFromDataSource() { if (mVideoTrack.mSource == NULL) { mVideoTrack.mIndex = i; mVideoTrack.mSource = track; + mVideoTrack.mPackets = + new AnotherPacketSource(mVideoTrack.mSource->getFormat()); // check if the source requires secure buffers int32_t secure; @@ -427,16 +431,12 @@ void NuPlayer::GenericSource::start() { if (mAudioTrack.mSource != NULL) { CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); - mAudioTrack.mPackets = - new AnotherPacketSource(mAudioTrack.mSource->getFormat()); postReadBuffer(MEDIA_TRACK_TYPE_AUDIO); } if (mVideoTrack.mSource != NULL) { CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); - mVideoTrack.mPackets = - new AnotherPacketSource(mVideoTrack.mSource->getFormat()); postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); } -- cgit v1.1 From 0ad776d2e4c6b4968d9dcd9bf34b962366b312a9 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 29 Aug 2014 18:02:56 -0700 Subject: LiveSession: added onSwitchDown additionally in this change - AnotherPacketSource: added getEstimatedDurationUs that avoids looping through buffered access units in most cases; this method is called by LiveSession before triggering onSwitchDown. Also fix the original getBufferedDurationUs to accumulate durations across discontinuities. Bug: 13742612 Change-Id: I135932ea0c74671b7019a3c7054844926c18bc14 --- media/libstagefright/httplive/LiveSession.cpp | 57 +++++++++++++++++++ media/libstagefright/httplive/LiveSession.h | 5 ++ .../libstagefright/mpeg2ts/AnotherPacketSource.cpp | 65 ++++++++++++++++++++-- media/libstagefright/mpeg2ts/AnotherPacketSource.h | 5 ++ 4 files changed, 128 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 7b18348..f98af70 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -531,6 +531,19 @@ void LiveSession::onMessageReceived(const sp &msg) { onSwapped(msg); break; } + + case kWhatCheckSwitchDown: + { + onCheckSwitchDown(); + break; + } + + case kWhatSwitchDown: + { + onSwitchDown(); + break; + } + default: TRESPASS(); break; @@ -643,6 +656,9 @@ void LiveSession::finishDisconnect() { // (finishDisconnect, onFinishDisconnect2) cancelBandwidthSwitch(); + // cancel switch down monitor + mSwitchDownMonitor.clear(); + for (size_t i = 0; i < mFetcherInfos.size(); ++i) { mFetcherInfos.valueAt(i).mFetcher->stopAsync(); } @@ -1435,6 +1451,44 @@ void LiveSession::onSwapped(const sp &msg) { tryToFinishBandwidthSwitch(); } +void LiveSession::onCheckSwitchDown() { + if (mSwitchDownMonitor == NULL) { + return; + } + + for (size_t i = 0; i < kMaxStreams; ++i) { + int32_t targetDuration; + sp packetSource = mPacketSources.valueFor(indexToType(i)); + sp meta = packetSource->getLatestDequeuedMeta(); + + if (meta != NULL && meta->findInt32("targetDuration", &targetDuration) ) { + int64_t bufferedDurationUs = packetSource->getEstimatedDurationUs(); + int64_t targetDurationUs = targetDuration * 1000000ll; + + if (bufferedDurationUs < targetDurationUs / 3) { + (new AMessage(kWhatSwitchDown, id()))->post(); + break; + } + } + } + + mSwitchDownMonitor->post(1000000ll); +} + +void LiveSession::onSwitchDown() { + if (mReconfigurationInProgress || mSwitchInProgress || mCurBandwidthIndex == 0) { + return; + } + + ssize_t bandwidthIndex = getBandwidthIndex(); + if (bandwidthIndex < mCurBandwidthIndex) { + changeConfiguration(-1, bandwidthIndex, false); + return; + } + + changeConfiguration(-1, mCurBandwidthIndex - 1, false); +} + // Mark switch done when: // 1. all old buffers are swapped out void LiveSession::tryToFinishBandwidthSwitch() { @@ -1522,6 +1576,9 @@ void LiveSession::postPrepared(status_t err) { notify->post(); mInPreparationPhase = false; + + mSwitchDownMonitor = new AMessage(kWhatCheckSwitchDown, id()); + mSwitchDownMonitor->post(); } } // namespace android diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 5423f0f..a68faf0 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -108,6 +108,8 @@ private: kWhatChangeConfiguration3 = 'chC3', kWhatFinishDisconnect2 = 'fin2', kWhatSwapped = 'swap', + kWhatCheckSwitchDown = 'ckSD', + kWhatSwitchDown = 'sDwn', }; struct BandwidthItem { @@ -202,6 +204,7 @@ private: bool mFirstTimeUsValid; int64_t mFirstTimeUs; int64_t mLastSeekTimeUs; + sp mSwitchDownMonitor; KeyedVector mDiscontinuityAbsStartTimesUs; KeyedVector mDiscontinuityOffsetTimesUs; @@ -246,6 +249,8 @@ private: void onChangeConfiguration2(const sp &msg); void onChangeConfiguration3(const sp &msg); void onSwapped(const sp &msg); + void onCheckSwitchDown(); + void onSwitchDown(); void tryToFinishBandwidthSwitch(); void scheduleCheckBandwidthEvent(); diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index 010063f..c74c3e7 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -42,7 +42,8 @@ AnotherPacketSource::AnotherPacketSource(const sp &meta) mLastQueuedTimeUs(0), mEOSResult(OK), mLatestEnqueuedMeta(NULL), - mLatestDequeuedMeta(NULL) { + mLatestDequeuedMeta(NULL), + mQueuedDiscontinuityCount(0) { setFormat(meta); } @@ -122,6 +123,7 @@ status_t AnotherPacketSource::dequeueAccessUnit(sp *buffer) { mFormat.clear(); } + --mQueuedDiscontinuityCount; return INFO_DISCONTINUITY; } @@ -210,6 +212,11 @@ void AnotherPacketSource::queueAccessUnit(const sp &buffer) { mBuffers.push_back(buffer); mCondition.signal(); + int32_t discontinuity; + if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { + ++mQueuedDiscontinuityCount; + } + if (mLatestEnqueuedMeta == NULL) { mLatestEnqueuedMeta = buffer->meta(); } else { @@ -226,6 +233,7 @@ void AnotherPacketSource::clear() { mBuffers.clear(); mEOSResult = OK; + mQueuedDiscontinuityCount = 0; mFormat = NULL; mLatestEnqueuedMeta = NULL; @@ -262,6 +270,7 @@ void AnotherPacketSource::queueDiscontinuity( mEOSResult = OK; mLastQueuedTimeUs = 0; mLatestEnqueuedMeta = NULL; + ++mQueuedDiscontinuityCount; sp buffer = new ABuffer(0); buffer->meta()->setInt32("discontinuity", static_cast(type)); @@ -291,7 +300,10 @@ bool AnotherPacketSource::hasBufferAvailable(status_t *finalResult) { int64_t AnotherPacketSource::getBufferedDurationUs(status_t *finalResult) { Mutex::Autolock autoLock(mLock); + return getBufferedDurationUs_l(finalResult); +} +int64_t AnotherPacketSource::getBufferedDurationUs_l(status_t *finalResult) { *finalResult = mEOSResult; if (mBuffers.empty()) { @@ -300,6 +312,7 @@ int64_t AnotherPacketSource::getBufferedDurationUs(status_t *finalResult) { int64_t time1 = -1; int64_t time2 = -1; + int64_t durationUs = 0; List >::iterator it = mBuffers.begin(); while (it != mBuffers.end()) { @@ -307,20 +320,64 @@ int64_t AnotherPacketSource::getBufferedDurationUs(status_t *finalResult) { int64_t timeUs; if (buffer->meta()->findInt64("timeUs", &timeUs)) { - if (time1 < 0) { + if (time1 < 0 || timeUs < time1) { time1 = timeUs; } - time2 = timeUs; + if (time2 < 0 || timeUs > time2) { + time2 = timeUs; + } } else { // This is a discontinuity, reset everything. + durationUs += time2 - time1; time1 = time2 = -1; } ++it; } - return time2 - time1; + return durationUs + (time2 - time1); +} + +// A cheaper but less precise version of getBufferedDurationUs that we would like to use in +// LiveSession::dequeueAccessUnit to trigger downwards adaptation. +int64_t AnotherPacketSource::getEstimatedDurationUs() { + Mutex::Autolock autoLock(mLock); + if (mBuffers.empty()) { + return 0; + } + + if (mQueuedDiscontinuityCount > 0) { + status_t finalResult; + return getBufferedDurationUs_l(&finalResult); + } + + List >::iterator it = mBuffers.begin(); + sp buffer = *it; + + int64_t startTimeUs; + buffer->meta()->findInt64("timeUs", &startTimeUs); + if (startTimeUs < 0) { + return 0; + } + + it = mBuffers.end(); + --it; + buffer = *it; + + int64_t endTimeUs; + buffer->meta()->findInt64("timeUs", &endTimeUs); + if (endTimeUs < 0) { + return 0; + } + + int64_t diffUs; + if (endTimeUs > startTimeUs) { + diffUs = endTimeUs - startTimeUs; + } else { + diffUs = startTimeUs - endTimeUs; + } + return diffUs; } status_t AnotherPacketSource::nextBufferTime(int64_t *timeUs) { diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h index 0c717d7..809a858 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h @@ -49,6 +49,8 @@ struct AnotherPacketSource : public MediaSource { // presentation timestamps since the last discontinuity (if any). int64_t getBufferedDurationUs(status_t *finalResult); + int64_t getEstimatedDurationUs(); + status_t nextBufferTime(int64_t *timeUs); void queueAccessUnit(const sp &buffer); @@ -83,7 +85,10 @@ private: sp mLatestEnqueuedMeta; sp mLatestDequeuedMeta; + size_t mQueuedDiscontinuityCount; + bool wasFormatChange(int32_t discontinuityType) const; + int64_t getBufferedDurationUs_l(status_t *finalResult); DISALLOW_EVIL_CONSTRUCTORS(AnotherPacketSource); }; -- cgit v1.1 From f69c996864844e8f669308af8412cede043062a2 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 29 Aug 2014 18:16:29 -0700 Subject: LiveSession: re-buffer on under run to avoid stutter Bug: 13742725 Change-Id: I7dad8876e18084c3c060d08190fa8a72fc2f5bad --- media/libstagefright/httplive/LiveSession.cpp | 36 ++++++++++++++++++++++++++- media/libstagefright/httplive/LiveSession.h | 2 ++ 2 files changed, 37 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 83481bc..5f566ca 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -81,6 +81,7 @@ LiveSession::LiveSession( mDiscontinuities.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); mPacketSources.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); mPacketSources2.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); + mBuffering[i] = false; } } @@ -133,8 +134,26 @@ status_t LiveSession::dequeueAccessUnit( sp packetSource = mPacketSources.valueFor(stream); + ssize_t idx = typeToIndex(stream); if (!packetSource->hasBufferAvailable(&finalResult)) { - return finalResult == OK ? -EAGAIN : finalResult; + if (finalResult == OK) { + mBuffering[idx] = true; + return -EAGAIN; + } else { + return finalResult; + } + } + + if (mBuffering[idx]) { + if (mSwitchInProgress + || packetSource->isFinished(0) + || packetSource->getEstimatedDurationUs() > 10000000ll) { + mBuffering[idx] = false; + } + } + + if (mBuffering[idx]) { + return -EAGAIN; } // wait for counterpart @@ -567,6 +586,21 @@ LiveSession::StreamType LiveSession::indexToType(int idx) { return (StreamType)(1 << idx); } +// static +ssize_t LiveSession::typeToIndex(int32_t type) { + switch (type) { + case STREAMTYPE_AUDIO: + return 0; + case STREAMTYPE_VIDEO: + return 1; + case STREAMTYPE_SUBTITLES: + return 2; + default: + return -1; + }; + return -1; +} + void LiveSession::onConnect(const sp &msg) { AString url; CHECK(msg->findString("url", &url)); diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 8a800da..26df543 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -153,6 +153,7 @@ private: sp mHTTPService; bool mInPreparationPhase; + bool mBuffering[kMaxStreams]; sp mHTTPDataSource; KeyedVector mExtraHeaders; @@ -242,6 +243,7 @@ private: static int SortByBandwidth(const BandwidthItem *, const BandwidthItem *); static StreamType indexToType(int idx); + static ssize_t typeToIndex(int32_t type); void changeConfiguration( int64_t timeUs, size_t bandwidthIndex, bool pickTrack = false); -- cgit v1.1 From f4a48dfa8570d6a4708a868b8b15d1236f7ca54b Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 29 Aug 2014 18:09:26 -0700 Subject: LiveSession: reliable switch Bug: 17142706 Change-Id: I9cd6c068178d62c294496e8ab0b0a3763354964f --- media/libstagefright/httplive/LiveSession.cpp | 65 +++++++++++++++++++++++---- media/libstagefright/httplive/LiveSession.h | 2 +- 2 files changed, 57 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 5f566ca..3720085 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -1286,12 +1286,6 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask)); CHECK(msg->findInt32("resumeMask", (int32_t *)&resumeMask)); - for (size_t i = 0; i < kMaxStreams; ++i) { - if (streamMask & indexToType(i)) { - CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mUri)); - } - } - int64_t timeUs; int32_t pickTrack; bool switching = false; @@ -1307,7 +1301,20 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { mRealTimeBaseUs = ALooper::GetNowUs() - timeUs; } + for (size_t i = 0; i < kMaxStreams; ++i) { + if (streamMask & indexToType(i)) { + if (switching) { + CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mNewUri)); + } else { + CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mUri)); + } + } + } + mNewStreamMask = streamMask | resumeMask; + if (switching) { + mSwapMask = mStreamMask & ~resumeMask; + } // Of all existing fetchers: // * Resume fetchers that are still needed and assign them original packet sources. @@ -1357,7 +1364,7 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { } AString uri; - uri = mStreams[i].mUri; + uri = switching ? mStreams[i].mNewUri : mStreams[i].mUri; sp fetcher = addFetcher(uri.c_str()); CHECK(fetcher != NULL); @@ -1370,7 +1377,8 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { // TRICKY: looping from i as earlier streams are already removed from streamMask for (size_t j = i; j < kMaxStreams; ++j) { - if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) { + const AString &streamUri = switching ? mStreams[j].mNewUri : mStreams[j].mUri; + if ((streamMask & indexToType(j)) && uri == streamUri) { sources[j] = mPacketSources.valueFor(indexToType(j)); if (timeUs >= 0) { @@ -1459,7 +1467,6 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { mReconfigurationInProgress = false; if (switching) { mSwitchInProgress = true; - mSwapMask = streamMask; } else { mStreamMask = mNewStreamMask; } @@ -1478,6 +1485,15 @@ void LiveSession::onSwapped(const sp &msg) { int32_t stream; CHECK(msg->findInt32("stream", &stream)); + + ssize_t idx = typeToIndex(stream); + CHECK(idx >= 0); + if ((mNewStreamMask & stream) && mStreams[idx].mNewUri.empty()) { + ALOGW("swapping stream type %d %s to empty stream", stream, mStreams[idx].mUri.c_str()); + } + mStreams[idx].mUri = mStreams[idx].mNewUri; + mStreams[idx].mNewUri.clear(); + mSwapMask &= ~stream; if (mSwapMask != 0) { return; @@ -1489,6 +1505,15 @@ void LiveSession::onSwapped(const sp &msg) { StreamType extraStream = (StreamType) (extraStreams & ~(extraStreams - 1)); swapPacketSource(extraStream); extraStreams &= ~extraStream; + + idx = typeToIndex(extraStream); + CHECK(idx >= 0); + if (mStreams[idx].mNewUri.empty()) { + ALOGW("swapping extra stream type %d %s to empty stream", + extraStream, mStreams[idx].mUri.c_str()); + } + mStreams[idx].mUri = mStreams[idx].mNewUri; + mStreams[idx].mNewUri.clear(); } tryToFinishBandwidthSwitch(); @@ -1569,6 +1594,28 @@ void LiveSession::cancelBandwidthSwitch() { mSwitchGeneration++; mSwitchInProgress = false; mSwapMask = 0; + + for (size_t i = 0; i < mFetcherInfos.size(); ++i) { + FetcherInfo& info = mFetcherInfos.editValueAt(i); + if (info.mToBeRemoved) { + info.mToBeRemoved = false; + } + } + + for (size_t i = 0; i < kMaxStreams; ++i) { + if (!mStreams[i].mNewUri.empty()) { + ssize_t j = mFetcherInfos.indexOfKey(mStreams[i].mNewUri); + if (j < 0) { + mStreams[i].mNewUri.clear(); + continue; + } + + const FetcherInfo &info = mFetcherInfos.valueAt(j); + info.mFetcher->stopAsync(); + mFetcherInfos.removeItemsAt(j); + mStreams[i].mNewUri.clear(); + } + } } bool LiveSession::canSwitchBandwidthTo(size_t bandwidthIndex) { diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 26df543..6be86cf 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -126,7 +126,7 @@ private: struct StreamItem { const char *mType; - AString mUri; + AString mUri, mNewUri; size_t mCurDiscontinuitySeq; int64_t mLastDequeuedTimeUs; int64_t mLastSampleDurationUs; -- cgit v1.1 From c5cc2e21602182c7ab4df1d7eba40f18037c1818 Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Tue, 9 Sep 2014 20:08:39 -0700 Subject: mediaplayer: optimize buffer queue management Various changes for power consumption including: Restrict the number of messages in flight. Buffer more frames in the GenericSource so reads occur in a burst. Bug: 15094301 Change-Id: I783481fd91f3fdd445b95e88ab82178f649f1a38 Signed-off-by: Phil Burk --- .../nuplayer/GenericSource.cpp | 6 +- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 70 ++++++++++------------ media/libmediaplayerservice/nuplayer/NuPlayer.h | 5 ++ .../nuplayer/NuPlayerDecoderPassThrough.cpp | 62 ++++++++++++------- .../nuplayer/NuPlayerDecoderPassThrough.h | 15 +++-- 5 files changed, 93 insertions(+), 65 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index ec1a9a0..2421b32 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -1176,12 +1176,14 @@ void NuPlayer::GenericSource::onReadBuffer(sp msg) { void NuPlayer::GenericSource::readBuffer( media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) { Track *track; + size_t maxBuffers = 1; switch (trackType) { case MEDIA_TRACK_TYPE_VIDEO: track = &mVideoTrack; break; case MEDIA_TRACK_TYPE_AUDIO: track = &mAudioTrack; + maxBuffers = 64; break; case MEDIA_TRACK_TYPE_SUBTITLE: track = &mSubtitleTrack; @@ -1214,7 +1216,7 @@ void NuPlayer::GenericSource::readBuffer( options.setNonBlocking(); } - for (;;) { + for (size_t numBuffers = 0; numBuffers < maxBuffers; ) { MediaBuffer *mbuf; status_t err = track->mSource->read(&mbuf, &options); @@ -1245,7 +1247,7 @@ void NuPlayer::GenericSource::readBuffer( sp buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs); track->mPackets->queueAccessUnit(buffer); - break; + ++numBuffers; } else if (err == WOULD_BLOCK) { break; } else if (err == INFO_FORMAT_CHANGED) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index df3e992..9020a8d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -50,6 +50,10 @@ namespace android { +// TODO optimize buffer size for power consumption +// The offload read buffer size is 32 KB but 24 KB uses less power. +const size_t NuPlayer::kAggregateBufferSizeBytes = 24 * 1024; + struct NuPlayer::Action : public RefBase { Action() {} @@ -730,7 +734,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { if (err == -EWOULDBLOCK) { if (mSource->feedMoreTSData() == OK) { - msg->post(10000ll); + msg->post(10 * 1000ll); } } } else if (what == Decoder::kWhatEOS) { @@ -995,6 +999,7 @@ void NuPlayer::finishFlushIfPossible() { ALOGV("both audio and video are flushed now."); mPendingAudioAccessUnit.clear(); + mAggregateBuffer.clear(); if (mTimeDiscontinuityPending) { mRenderer->signalTimeDiscontinuity(); @@ -1256,14 +1261,8 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { // Aggregate smaller buffers into a larger buffer. // The goal is to reduce power consumption. // Unfortunately this does not work with the software AAC decoder. - // TODO optimize buffer size for power consumption - // The offload read buffer size is 32 KB but 24 KB uses less power. - const int kAudioBigBufferSizeBytes = 24 * 1024; - bool doBufferAggregation = (audio && mOffloadAudio); - sp biggerBuffer; + bool doBufferAggregation = (audio && mOffloadAudio);; bool needMoreData = false; - int numSmallBuffers = 0; - bool gotTime = false; bool dropAccessUnit; do { @@ -1279,14 +1278,10 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { } if (err == -EWOULDBLOCK) { - if (biggerBuffer == NULL) { - return err; - } else { - break; // Reply with data that we already have. - } + return err; } else if (err != OK) { if (err == INFO_DISCONTINUITY) { - if (biggerBuffer != NULL) { + if (mAggregateBuffer != NULL) { // We already have some data so save this for later. mPendingAudioErr = err; mPendingAudioAccessUnit = accessUnit; @@ -1401,46 +1396,45 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { size_t smallSize = accessUnit->size(); needMoreData = false; - if (doBufferAggregation && (biggerBuffer == NULL) + if (doBufferAggregation && (mAggregateBuffer == NULL) // Don't bother if only room for a few small buffers. - && (smallSize < (kAudioBigBufferSizeBytes / 3))) { + && (smallSize < (kAggregateBufferSizeBytes / 3))) { // Create a larger buffer for combining smaller buffers from the extractor. - biggerBuffer = new ABuffer(kAudioBigBufferSizeBytes); - biggerBuffer->setRange(0, 0); // start empty + mAggregateBuffer = new ABuffer(kAggregateBufferSizeBytes); + mAggregateBuffer->setRange(0, 0); // start empty } - if (biggerBuffer != NULL) { + if (mAggregateBuffer != NULL) { int64_t timeUs; + int64_t dummy; bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs); + bool bigTimestampValid = mAggregateBuffer->meta()->findInt64("timeUs", &dummy); // Will the smaller buffer fit? - size_t bigSize = biggerBuffer->size(); - size_t roomLeft = biggerBuffer->capacity() - bigSize; + size_t bigSize = mAggregateBuffer->size(); + size_t roomLeft = mAggregateBuffer->capacity() - bigSize; // Should we save this small buffer for the next big buffer? // If the first small buffer did not have a timestamp then save // any buffer that does have a timestamp until the next big buffer. if ((smallSize > roomLeft) - || (!gotTime && (numSmallBuffers > 0) && smallTimestampValid)) { + || (!bigTimestampValid && (bigSize > 0) && smallTimestampValid)) { mPendingAudioErr = err; mPendingAudioAccessUnit = accessUnit; accessUnit.clear(); } else { + // Grab time from first small buffer if available. + if ((bigSize == 0) && smallTimestampValid) { + mAggregateBuffer->meta()->setInt64("timeUs", timeUs); + } // Append small buffer to the bigger buffer. - memcpy(biggerBuffer->base() + bigSize, accessUnit->data(), smallSize); + memcpy(mAggregateBuffer->base() + bigSize, accessUnit->data(), smallSize); bigSize += smallSize; - biggerBuffer->setRange(0, bigSize); + mAggregateBuffer->setRange(0, bigSize); - // Keep looping until we run out of room in the biggerBuffer. + // Keep looping until we run out of room in the mAggregateBuffer. needMoreData = true; - // Grab time from first small buffer if available. - if ((numSmallBuffers == 0) && smallTimestampValid) { - biggerBuffer->meta()->setInt64("timeUs", timeUs); - gotTime = true; - } - - ALOGV("feedDecoderInputData() #%d, smallSize = %zu, bigSize = %zu, capacity = %zu", - numSmallBuffers, smallSize, bigSize, biggerBuffer->capacity()); - numSmallBuffers++; + ALOGV("feedDecoderInputData() smallSize = %zu, bigSize = %zu, capacity = %zu", + smallSize, bigSize, mAggregateBuffer->capacity()); } } } while (dropAccessUnit || needMoreData); @@ -1459,9 +1453,11 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { mCCDecoder->decode(accessUnit); } - if (biggerBuffer != NULL) { - ALOGV("feedDecoderInputData() reply with aggregated buffer, %d", numSmallBuffers); - reply->setBuffer("buffer", biggerBuffer); + if (mAggregateBuffer != NULL) { + ALOGV("feedDecoderInputData() reply with aggregated buffer, %zu", + mAggregateBuffer->size()); + reply->setBuffer("buffer", mAggregateBuffer); + mAggregateBuffer.clear(); } else { reply->setBuffer("buffer", accessUnit); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 89ae11c..2e951bd 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -67,6 +67,8 @@ struct NuPlayer : public AHandler { status_t getSelectedTrack(int32_t type, Parcel* reply) const; status_t selectTrack(size_t trackIndex, bool select); + static const size_t kAggregateBufferSizeBytes; + protected: virtual ~NuPlayer(); @@ -158,8 +160,11 @@ private: // notion of time has changed. bool mTimeDiscontinuityPending; + // Used by feedDecoderInputData to aggregate small buffers into + // one large buffer. sp mPendingAudioAccessUnit; status_t mPendingAudioErr; + sp mAggregateBuffer; FlushStatus mFlushingAudio; FlushStatus mFlushingVideo; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp index ab7906a..f7aacdd 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp @@ -30,8 +30,10 @@ namespace android { -static const int kMaxPendingBuffers = 10; -static const int kMaxCachedBytes = 200000; +static const size_t kMaxCachedBytes = 200000; +// The buffers will contain a bit less than kAggregateBufferSizeBytes. +// So we can start off with just enough buffers to keep the cache full. +static const size_t kMaxPendingBuffers = 1 + (kMaxCachedBytes / NuPlayer::kAggregateBufferSizeBytes); NuPlayer::DecoderPassThrough::DecoderPassThrough( const sp ¬ify) @@ -39,7 +41,8 @@ NuPlayer::DecoderPassThrough::DecoderPassThrough( mNotify(notify), mBufferGeneration(0), mReachedEOS(true), - mPendingBuffers(0), + mPendingBuffersToFill(0), + mPendingBuffersToDrain(0), mCachedBytes(0), mComponentName("pass through decoder") { mDecoderLooper = new ALooper; @@ -79,12 +82,13 @@ bool NuPlayer::DecoderPassThrough::supportsSeamlessFormatChange( void NuPlayer::DecoderPassThrough::onConfigure(const sp &format) { ALOGV("[%s] onConfigure", mComponentName.c_str()); - mPendingBuffers = 0; mCachedBytes = 0; + mPendingBuffersToFill = 0; + mPendingBuffersToDrain = 0; mReachedEOS = false; ++mBufferGeneration; - requestABuffer(); + requestMaxBuffers(); sp notify = mNotify->dup(); notify->setInt32("what", kWhatOutputFormatChanged); @@ -98,12 +102,15 @@ bool NuPlayer::DecoderPassThrough::isStaleReply(const sp &msg) { return generation != mBufferGeneration; } -void NuPlayer::DecoderPassThrough::requestABuffer() { - if (mCachedBytes >= kMaxCachedBytes || mReachedEOS) { - ALOGV("[%s] mReachedEOS=%d, max pending buffers(%d:%d)", - mComponentName.c_str(), (mReachedEOS ? 1 : 0), - mPendingBuffers, kMaxPendingBuffers); - return; +bool NuPlayer::DecoderPassThrough::requestABuffer() { + if (mCachedBytes >= kMaxCachedBytes) { + ALOGV("[%s] mCachedBytes = %zu", + mComponentName.c_str(), mCachedBytes); + return false; + } + if (mReachedEOS) { + ALOGV("[%s] reached EOS", mComponentName.c_str()); + return false; } sp reply = new AMessage(kWhatInputBufferFilled, id()); @@ -113,19 +120,16 @@ void NuPlayer::DecoderPassThrough::requestABuffer() { notify->setInt32("what", kWhatFillThisBuffer); notify->setMessage("reply", reply); notify->post(); - mPendingBuffers++; + mPendingBuffersToFill++; + ALOGV("requestABuffer: #ToFill = %zu, #ToDrain = %zu", mPendingBuffersToFill, + mPendingBuffersToDrain); - // pending buffers will already result in requestABuffer - if (mPendingBuffers < kMaxPendingBuffers) { - sp message = new AMessage(kWhatRequestABuffer, id()); - message->setInt32("generation", mBufferGeneration); - message->post(); - } - return; + return true; } void android::NuPlayer::DecoderPassThrough::onInputBufferFilled( const sp &msg) { + --mPendingBuffersToFill; if (mReachedEOS) { return; } @@ -153,11 +157,16 @@ void android::NuPlayer::DecoderPassThrough::onInputBufferFilled( notify->setBuffer("buffer", buffer); notify->setMessage("reply", reply); notify->post(); + ++mPendingBuffersToDrain; + ALOGV("onInputBufferFilled: #ToFill = %zu, #ToDrain = %zu, cachedBytes = %zu", + mPendingBuffersToFill, mPendingBuffersToDrain, mCachedBytes); } void NuPlayer::DecoderPassThrough::onBufferConsumed(int32_t size) { - mPendingBuffers--; + --mPendingBuffersToDrain; mCachedBytes -= size; + ALOGV("onBufferConsumed: #ToFill = %zu, #ToDrain = %zu, cachedBytes = %zu", + mPendingBuffersToFill, mPendingBuffersToDrain, mCachedBytes); requestABuffer(); } @@ -167,11 +176,20 @@ void NuPlayer::DecoderPassThrough::onFlush() { sp notify = mNotify->dup(); notify->setInt32("what", kWhatFlushCompleted); notify->post(); - mPendingBuffers = 0; + mPendingBuffersToFill = 0; + mPendingBuffersToDrain = 0; mCachedBytes = 0; mReachedEOS = false; } +void NuPlayer::DecoderPassThrough::requestMaxBuffers() { + for (size_t i = 0; i < kMaxPendingBuffers; i++) { + if (!requestABuffer()) { + break; + } + } +} + void NuPlayer::DecoderPassThrough::onShutdown() { ++mBufferGeneration; @@ -229,7 +247,7 @@ void NuPlayer::DecoderPassThrough::onMessageReceived(const sp &msg) { case kWhatResume: { - requestABuffer(); + requestMaxBuffers(); break; } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h index 8590856..fb20257 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h @@ -55,19 +55,26 @@ private: sp mNotify; sp mDecoderLooper; - void requestABuffer(); + /** Returns true if a buffer was requested. + * Returns false if at EOS or cache already full. + */ + bool requestABuffer(); bool isStaleReply(const sp &msg); void onConfigure(const sp &format); void onFlush(); void onInputBufferFilled(const sp &msg); void onBufferConsumed(int32_t size); + void requestMaxBuffers(); void onShutdown(); int32_t mBufferGeneration; - bool mReachedEOS; - int32_t mPendingBuffers; - int32_t mCachedBytes; + bool mReachedEOS; + // TODO mPendingBuffersToFill and mPendingBuffersToDrain are only for + // debugging. They can be removed when the power investigation is done. + size_t mPendingBuffersToFill; + size_t mPendingBuffersToDrain; + size_t mCachedBytes; AString mComponentName; DISALLOW_EVIL_CONSTRUCTORS(DecoderPassThrough); -- cgit v1.1 From 14986f6cca08b9ab0407cc2d31f92bfb02b5cb8c Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 15 Sep 2014 11:04:44 -0700 Subject: mediaplayer: handle surface dis/connection errors Bug: 17408008 Change-Id: I752d5372086772b79b1300a2d3fabbc4985954a8 --- media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 163a0b5..87f85e7 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -122,14 +122,17 @@ void NuPlayer::Decoder::onConfigure(const sp &format) { mCodec->getName(&mComponentName); + status_t err; if (mNativeWindow != NULL) { // disconnect from surface as MediaCodec will reconnect - CHECK_EQ((int)NO_ERROR, - native_window_api_disconnect( - surface.get(), - NATIVE_WINDOW_API_MEDIA)); + err = native_window_api_disconnect( + surface.get(), NATIVE_WINDOW_API_MEDIA); + // We treat this as a warning, as this is a preparatory step. + // Codec will try to connect to the surface, which is where + // any error signaling will occur. + ALOGW_IF(err != OK, "failed to disconnect from surface: %d", err); } - status_t err = mCodec->configure( + err = mCodec->configure( format, surface, NULL /* crypto */, 0 /* flags */); if (err != OK) { ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err); -- cgit v1.1 From f78f62bd6b0a99747db53828d281a50b9270a646 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 29 Aug 2014 19:01:29 -0700 Subject: PlaylistFetcher: find the correct sequence number to start fetching - skip over bad segemnts - if we skipped too far into the future when adapting in live streams, adjust back Bug: 17141635 Bug: 17416657 Change-Id: I0877ceaf6e69cab751bf9e92579071f9e61643eb --- media/libstagefright/httplive/PlaylistFetcher.cpp | 153 ++++++++++++++-------- media/libstagefright/httplive/PlaylistFetcher.h | 5 + 2 files changed, 107 insertions(+), 51 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 82a4c39..8ffe79e 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -951,7 +951,7 @@ void PlaylistFetcher::onDownloadNext() { } if (err == -EAGAIN) { - // starting sequence number too low + // starting sequence number too low/high mTSParser.clear(); postMonitorQueue(); return; @@ -1023,12 +1023,39 @@ void PlaylistFetcher::onDownloadNext() { return; } - mStartup = false; ++mSeqNumber; postMonitorQueue(); } +int32_t PlaylistFetcher::getSeqNumberWithAnchorTime(int64_t anchorTimeUs) const { + int32_t firstSeqNumberInPlaylist, lastSeqNumberInPlaylist; + if (mPlaylist->meta() == NULL + || !mPlaylist->meta()->findInt32("media-sequence", &firstSeqNumberInPlaylist)) { + firstSeqNumberInPlaylist = 0; + } + lastSeqNumberInPlaylist = firstSeqNumberInPlaylist + mPlaylist->size() - 1; + + int32_t index = mSeqNumber - firstSeqNumberInPlaylist - 1; + while (index >= 0 && anchorTimeUs > mStartTimeUs) { + sp itemMeta; + CHECK(mPlaylist->itemAt(index, NULL /* uri */, &itemMeta)); + + int64_t itemDurationUs; + CHECK(itemMeta->findInt64("durationUs", &itemDurationUs)); + + anchorTimeUs -= itemDurationUs; + --index; + } + + int32_t newSeqNumber = firstSeqNumberInPlaylist + index + 1; + if (newSeqNumber <= lastSeqNumberInPlaylist) { + return newSeqNumber; + } else { + return lastSeqNumberInPlaylist; + } +} + int32_t PlaylistFetcher::getSeqNumberForDiscontinuity(size_t discontinuitySeq) const { int32_t firstSeqNumberInPlaylist; if (mPlaylist->meta() == NULL @@ -1198,60 +1225,84 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp &bu if (timeUs < 0) { timeUs = 0; } - } else if (mAdaptive && timeUs > mStartTimeUs) { - int32_t seq; - if (mStartTimeUsNotify != NULL - && !mStartTimeUsNotify->findInt32("discontinuitySeq", &seq)) { - mStartTimeUsNotify->setInt32("discontinuitySeq", mDiscontinuitySeq); + } + + if (timeUs < mStartTimeUs) { + // buffer up to the closest preceding IDR frame + ALOGV("timeUs %" PRId64 " us < mStartTimeUs %" PRId64 " us", + timeUs, mStartTimeUs); + const char *mime; + sp format = source->getFormat(); + bool isAvc = false; + if (format != NULL && format->findCString(kKeyMIMEType, &mime) + && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { + isAvc = true; + } + if (isAvc && IsIDR(accessUnit)) { + mVideoBuffer->clear(); } - int64_t startTimeUs; - if (mStartTimeUsNotify != NULL - && !mStartTimeUsNotify->findInt64(key, &startTimeUs)) { - mStartTimeUsNotify->setInt64(key, timeUs); - - uint32_t streamMask = 0; - mStartTimeUsNotify->findInt32("streamMask", (int32_t *) &streamMask); - streamMask |= mPacketSources.keyAt(i); - mStartTimeUsNotify->setInt32("streamMask", streamMask); - - if (streamMask == mStreamTypeMask) { - mStartTimeUsNotify->post(); - mStartTimeUsNotify.clear(); - } + if (isAvc) { + mVideoBuffer->queueAccessUnit(accessUnit); } + + continue; } + } - if (timeUs < mStartTimeUs) { - if (mAdaptive) { - int32_t targetDuration; - mPlaylist->meta()->findInt32("target-duration", &targetDuration); - int32_t incr = (mStartTimeUs - timeUs) / 1000000 / targetDuration; - if (incr == 0) { - // increment mSeqNumber by at least one - incr = 1; - } - mSeqNumber += incr; - err = -EAGAIN; - break; + CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); + if (mStartTimeUsNotify != NULL && timeUs > mStartTimeUs) { + + int32_t targetDurationSecs; + CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs)); + int64_t targetDurationUs = targetDurationSecs * 1000000ll; + // mStartup + // mStartup is true until we have queued a packet for all the streams + // we are fetching. We queue packets whose timestamps are greater than + // mStartTimeUs. + // mSegmentStartTimeUs >= 0 + // mSegmentStartTimeUs is non-negative when adapting or switching tracks + // timeUs - mStartTimeUs > targetDurationUs: + // This and the 2 above conditions should only happen when adapting in a live + // stream; the old fetcher has already fetched to mStartTimeUs; the new fetcher + // would start fetching after timeUs, which should be greater than mStartTimeUs; + // the old fetcher would then continue fetching data until timeUs. We don't want + // timeUs to be too far ahead of mStartTimeUs because we want the old fetcher to + // stop as early as possible. The definition of being "too far ahead" is + // arbitrary; here we use targetDurationUs as threshold. + if (mStartup && mSegmentStartTimeUs >= 0 + && timeUs - mStartTimeUs > targetDurationUs) { + // we just guessed a starting timestamp that is too high when adapting in a + // live stream; re-adjust based on the actual timestamp extracted from the + // media segment; if we didn't move backward after the re-adjustment + // (newSeqNumber), start at least 1 segment prior. + int32_t newSeqNumber = getSeqNumberWithAnchorTime(timeUs); + if (newSeqNumber >= mSeqNumber) { + --mSeqNumber; } else { - // buffer up to the closest preceding IDR frame - ALOGV("timeUs %" PRId64 " us < mStartTimeUs %" PRId64 " us", - timeUs, mStartTimeUs); - const char *mime; - sp format = source->getFormat(); - bool isAvc = false; - if (format != NULL && format->findCString(kKeyMIMEType, &mime) - && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { - isAvc = true; - } - if (isAvc && IsIDR(accessUnit)) { - mVideoBuffer->clear(); - } - if (isAvc) { - mVideoBuffer->queueAccessUnit(accessUnit); - } - - continue; + mSeqNumber = newSeqNumber; + } + mStartTimeUsNotify = mNotify->dup(); + mStartTimeUsNotify->setInt32("what", kWhatStartedAt); + return -EAGAIN; + } + + int32_t seq; + if (!mStartTimeUsNotify->findInt32("discontinuitySeq", &seq)) { + mStartTimeUsNotify->setInt32("discontinuitySeq", mDiscontinuitySeq); + } + int64_t startTimeUs; + if (!mStartTimeUsNotify->findInt64(key, &startTimeUs)) { + mStartTimeUsNotify->setInt64(key, timeUs); + + uint32_t streamMask = 0; + mStartTimeUsNotify->findInt32("streamMask", (int32_t *) &streamMask); + streamMask |= mPacketSources.keyAt(i); + mStartTimeUsNotify->setInt32("streamMask", streamMask); + + if (streamMask == mStreamTypeMask) { + mStartup = false; + mStartTimeUsNotify->post(); + mStartTimeUsNotify.clear(); } } } diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index daefb26..4ba37fa 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -104,7 +104,12 @@ private: uint32_t mStreamTypeMask; int64_t mStartTimeUs; + + // Start time relative to the beginning of the first segment in the initial + // playlist. It's value is initialized to a non-negative value only when we are + // adapting or switching tracks. int64_t mSegmentStartTimeUs; + ssize_t mDiscontinuitySeq; bool mStartTimeUsRelative; sp mStopParams; // message containing the latest timestamps we should fetch. -- cgit v1.1 From 58c4cf4540e3f23847196bd4b45d82613e238821 Mon Sep 17 00:00:00 2001 From: hkuang Date: Fri, 12 Sep 2014 13:38:04 -0700 Subject: Optimize the YUV buffer copy a little bit to skip unnecessary operation. Bug: 17326758 Change-Id: I2505751cb40a53242ceeb3be8f362c3754c2ee3f --- .../omx/SoftVideoDecoderOMXComponent.cpp | 33 ++++++++++------------ 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'media') diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp index e533fdd..37535ce 100644 --- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp +++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp @@ -189,29 +189,26 @@ void SoftVideoDecoderOMXComponent::copyYV12FrameToOutputBuffer( size_t dstYStride = mIsAdaptive ? mAdaptiveMaxWidth : mWidth; size_t dstUVStride = dstYStride / 2; size_t dstHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight; + uint8_t *dstStart = dst; - for (size_t i = 0; i < dstHeight; ++i) { - if (i < mHeight) { - memcpy(dst, srcY, mWidth); - srcY += srcYStride; - } - dst += dstYStride; + for (size_t i = 0; i < mHeight; ++i) { + memcpy(dst, srcY, mWidth); + srcY += srcYStride; + dst += dstYStride; } - for (size_t i = 0; i < dstHeight / 2; ++i) { - if (i < mHeight / 2) { - memcpy(dst, srcU, mWidth / 2); - srcU += srcUStride; - } - dst += dstUVStride; + dst = dstStart + dstYStride * dstHeight; + for (size_t i = 0; i < mHeight / 2; ++i) { + memcpy(dst, srcU, mWidth / 2); + srcU += srcUStride; + dst += dstUVStride; } - for (size_t i = 0; i < dstHeight / 2; ++i) { - if (i < mHeight / 2) { - memcpy(dst, srcV, mWidth / 2); - srcV += srcVStride; - } - dst += dstUVStride; + dst = dstStart + (5 * dstYStride * dstHeight) / 4; + for (size_t i = 0; i < mHeight / 2; ++i) { + memcpy(dst, srcV, mWidth / 2); + srcV += srcVStride; + dst += dstUVStride; } } -- cgit v1.1 From 666c96d37203fd91ec319b8b499442696f70fd53 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Tue, 2 Sep 2014 16:51:37 -0700 Subject: ESQueue: do not merge aac packets Bug: 17310061 Change-Id: Ie0fb0702b0af1c4094415190fdfdf132d5fcd511 --- media/libstagefright/mpeg2ts/ESQueue.cpp | 46 +++++++++++++++++++++++++++++++- media/libstagefright/mpeg2ts/ESQueue.h | 1 + 2 files changed, 46 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp index 3c8f03e..ef1cd3d 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.cpp +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp @@ -604,6 +604,8 @@ sp ElementaryStreamQueue::dequeueAccessUnitAAC() { // having to interpolate. // The final AAC frame may well extend into the next RangeInfo but // that's ok. + // TODO: the logic commented above is skipped because codec cannot take + // arbitrary sized input buffers; size_t offset = 0; while (offset < info.mLength) { if (offset + 7 > mBuffer->size()) { @@ -668,9 +670,12 @@ sp ElementaryStreamQueue::dequeueAccessUnitAAC() { size_t headerSize = protection_absent ? 7 : 9; offset += aac_frame_length; + // TODO: move back to concatenation when codec can support arbitrary input buffers. + // For now only queue a single buffer + break; } - int64_t timeUs = fetchTimestamp(offset); + int64_t timeUs = fetchTimestampAAC(offset); sp accessUnit = new ABuffer(offset); memcpy(accessUnit->data(), mBuffer->data(), offset); @@ -717,6 +722,45 @@ int64_t ElementaryStreamQueue::fetchTimestamp(size_t size) { return timeUs; } +// TODO: avoid interpolating timestamps once codec supports arbitrary sized input buffers +int64_t ElementaryStreamQueue::fetchTimestampAAC(size_t size) { + int64_t timeUs = -1; + bool first = true; + + size_t samplesize = size; + while (size > 0) { + CHECK(!mRangeInfos.empty()); + + RangeInfo *info = &*mRangeInfos.begin(); + + if (first) { + timeUs = info->mTimestampUs; + first = false; + } + + if (info->mLength > size) { + int32_t sampleRate; + CHECK(mFormat->findInt32(kKeySampleRate, &sampleRate)); + info->mLength -= size; + size_t numSamples = 1024 * size / samplesize; + info->mTimestampUs += numSamples * 1000000ll / sampleRate; + size = 0; + } else { + size -= info->mLength; + + mRangeInfos.erase(mRangeInfos.begin()); + info = NULL; + } + + } + + if (timeUs == 0ll) { + ALOGV("Returning 0 timestamp"); + } + + return timeUs; +} + struct NALPosition { size_t nalOffset; size_t nalSize; diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h index a2cca77..7c81ff0 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.h +++ b/media/libstagefright/mpeg2ts/ESQueue.h @@ -77,6 +77,7 @@ private: // consume a logical (compressed) access unit of size "size", // returns its timestamp in us (or -1 if no time information). int64_t fetchTimestamp(size_t size); + int64_t fetchTimestampAAC(size_t size); DISALLOW_EVIL_CONSTRUCTORS(ElementaryStreamQueue); }; -- cgit v1.1 From f4eadb67ba9130b583b8f2f192276b53fa3d50bc Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Mon, 15 Sep 2014 17:34:19 -0700 Subject: ASessionDescription: allow open-ended NTP range. Bug: 17435211 Change-Id: I450d512abdc4368f5180d9859f3b4e207e3b5591 --- media/libstagefright/rtsp/ASessionDescription.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'media') diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp index a9b3330..98498e9 100644 --- a/media/libstagefright/rtsp/ASessionDescription.cpp +++ b/media/libstagefright/rtsp/ASessionDescription.cpp @@ -319,6 +319,11 @@ bool ASessionDescription::parseNTPRange( s = end + 1; // skip the dash. + if (*s == '\0') { + *npt2 = FLT_MAX; // open ended. + return true; + } + if (!strncmp("now", s, 3)) { return false; // no absolute end time available } -- cgit v1.1 From 73d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 29 Aug 2014 18:22:44 -0700 Subject: HLS: fix freezes when toggling between a/v streams Bug: 17412740 Change-Id: Iacaf2fa1d20584056375803e1782ad6761c56fc5 --- media/libstagefright/httplive/LiveSession.cpp | 11 ++++- media/libstagefright/httplive/PlaylistFetcher.cpp | 53 +++++++++++++++++++++-- media/libstagefright/httplive/PlaylistFetcher.h | 4 ++ 3 files changed, 63 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 3720085..7786c27 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -158,9 +158,16 @@ status_t LiveSession::dequeueAccessUnit( // wait for counterpart sp otherSource; - if (stream == STREAMTYPE_AUDIO && (mStreamMask & STREAMTYPE_VIDEO)) { + uint32_t mask = mNewStreamMask & mStreamMask; + uint32_t fetchersMask = 0; + for (size_t i = 0; i < mFetcherInfos.size(); ++i) { + uint32_t fetcherMask = mFetcherInfos.valueAt(i).mFetcher->getStreamTypeMask(); + fetchersMask |= fetcherMask; + } + mask &= fetchersMask; + if (stream == STREAMTYPE_AUDIO && (mask & STREAMTYPE_VIDEO)) { otherSource = mPacketSources.valueFor(STREAMTYPE_VIDEO); - } else if (stream == STREAMTYPE_VIDEO && (mStreamMask & STREAMTYPE_AUDIO)) { + } else if (stream == STREAMTYPE_VIDEO && (mask & STREAMTYPE_AUDIO)) { otherSource = mPacketSources.valueFor(STREAMTYPE_AUDIO); } if (otherSource != NULL && !otherSource->hasBufferAvailable(&finalResult)) { diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 1166762..f78f8b4 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -1009,7 +1009,16 @@ void PlaylistFetcher::onDownloadNext() { // bulk extract non-ts files if (tsBuffer == NULL) { - err = extractAndQueueAccessUnits(buffer, itemMeta); + err = extractAndQueueAccessUnits(buffer, itemMeta); + if (err == -EAGAIN) { + // starting sequence number too low/high + postMonitorQueue(); + return; + } else if (err == ERROR_OUT_OF_RANGE) { + // reached stopping point + stopAsync(/* clear = */false); + return; + } } if (err != OK) { @@ -1552,14 +1561,52 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( if (startTimeUs < mStartTimeUs) { continue; } + + if (mStartTimeUsNotify != NULL) { + int32_t targetDurationSecs; + CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs)); + int64_t targetDurationUs = targetDurationSecs * 1000000ll; + + // Duplicated logic from how we handle .ts playlists. + if (mStartup && mSegmentStartTimeUs >= 0 + && timeUs - mStartTimeUs > targetDurationUs) { + int32_t newSeqNumber = getSeqNumberWithAnchorTime(timeUs); + if (newSeqNumber >= mSeqNumber) { + --mSeqNumber; + } else { + mSeqNumber = newSeqNumber; + } + return -EAGAIN; + } + + mStartTimeUsNotify->setInt64("timeUsAudio", timeUs); + mStartTimeUsNotify->setInt32("discontinuitySeq", mDiscontinuitySeq); + mStartTimeUsNotify->setInt32("streamMask", LiveSession::STREAMTYPE_AUDIO); + mStartTimeUsNotify->post(); + mStartTimeUsNotify.clear(); + } + } + + if (mStopParams != NULL) { + // Queue discontinuity in original stream. + int32_t discontinuitySeq; + int64_t stopTimeUs; + if (!mStopParams->findInt32("discontinuitySeq", &discontinuitySeq) + || discontinuitySeq > mDiscontinuitySeq + || !mStopParams->findInt64("timeUsAudio", &stopTimeUs) + || (discontinuitySeq == mDiscontinuitySeq && unitTimeUs >= stopTimeUs)) { + packetSource->queueAccessUnit(mSession->createFormatChangeBuffer()); + mStreamTypeMask = 0; + mPacketSources.clear(); + return ERROR_OUT_OF_RANGE; + } } sp unit = new ABuffer(aac_frame_length); memcpy(unit->data(), adtsHeader, aac_frame_length); unit->meta()->setInt64("timeUs", unitTimeUs); - unit->meta()->setInt64("segmentStartTimeUs", getSegmentStartTimeUs(mSeqNumber)); - unit->meta()->setInt32("discontinuitySeq", mDiscontinuitySeq); + setAccessUnitProperties(unit, packetSource); packetSource->queueAccessUnit(unit); } diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index 4ba37fa..4b09df1 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -69,6 +69,10 @@ struct PlaylistFetcher : public AHandler { void resumeUntilAsync(const sp ¶ms); + uint32_t getStreamTypeMask() const { + return mStreamTypeMask; + } + protected: virtual ~PlaylistFetcher(); virtual void onMessageReceived(const sp &msg); -- cgit v1.1 From 48296b792a8d68358de74141fa80bd5bd84d0307 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Sun, 14 Sep 2014 14:28:45 -0700 Subject: Disconnect HTTP-based data source upon reset Bug: 17425250 Change-Id: Ieb4c93fd9848489f9dbf35a36474376924fd8eb9 --- .../nuplayer/GenericSource.cpp | 9 ++++++ .../libmediaplayerservice/nuplayer/GenericSource.h | 2 ++ media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 10 +++++++ .../nuplayer/NuPlayerSource.h | 3 ++ media/libstagefright/NuCachedSource2.cpp | 34 +++++++++++++++++----- media/libstagefright/include/NuCachedSource2.h | 3 ++ 6 files changed, 53 insertions(+), 8 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index d8ed836..0b85b23 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -464,6 +464,15 @@ void NuPlayer::GenericSource::resume() { mStarted = true; } +void NuPlayer::GenericSource::disconnect() { + if (mDataSource != NULL) { + // disconnect data source + if (mDataSource->flags() & DataSource::kIsCachingDataSource) { + static_cast(mDataSource.get())->disconnect(); + } + } +} + void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) { if (mDecryptHandle != NULL) { mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position); diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index c70c48e..454edeb 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -55,6 +55,8 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual void pause(); virtual void resume(); + virtual void disconnect(); + virtual status_t feedMoreTSData(); virtual status_t dequeueAccessUnit(bool audio, sp *accessUnit); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index df3e992..078e78b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -306,6 +306,16 @@ void NuPlayer::resume() { } void NuPlayer::resetAsync() { + if (mSource != NULL) { + // During a reset, the data source might be unresponsive already, we need to + // disconnect explicitly so that reads exit promptly. + // We can't queue the disconnect request to the looper, as it might be + // queued behind a stuck read and never gets processed. + // Doing a disconnect outside the looper to allows the pending reads to exit + // (either successfully or with error). + mSource->disconnect(); + } + (new AMessage(kWhatReset, id()))->post(); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index 7ccf3b1..7d994fa 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -67,6 +67,9 @@ struct NuPlayer::Source : public AHandler { virtual void pause() {} virtual void resume() {} + // Explicitly disconnect the underling data source + virtual void disconnect() {} + // Returns OK iff more data was available, // an error or ERROR_END_OF_STREAM if not. virtual status_t feedMoreTSData() = 0; diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index c1feff8..be2a873 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -191,6 +191,7 @@ NuCachedSource2::NuCachedSource2( mFinalStatus(OK), mLastAccessPos(0), mFetching(true), + mDisconnecting(false), mLastFetchTimeUs(-1), mNumRetriesLeft(kMaxNumRetries), mHighwaterThresholdBytes(kDefaultHighWaterThreshold), @@ -244,6 +245,23 @@ status_t NuCachedSource2::getEstimatedBandwidthKbps(int32_t *kbps) { return ERROR_UNSUPPORTED; } +void NuCachedSource2::disconnect() { + if (mSource->flags() & kIsHTTPBasedSource) { + ALOGV("disconnecting HTTPBasedSource"); + + { + Mutex::Autolock autoLock(mLock); + // set mDisconnecting to true, if a fetch returns after + // this, the source will be marked as EOS. + mDisconnecting = true; + } + + // explicitly disconnect from the source, to allow any + // pending reads to return more promptly + static_cast(mSource.get())->disconnect(); + } +} + status_t NuCachedSource2::setCacheStatCollectFreq(int32_t freqMs) { if (mSource->flags() & kIsHTTPBasedSource) { HTTPBase *source = static_cast(mSource.get()); @@ -327,7 +345,14 @@ void NuCachedSource2::fetchInternal() { Mutex::Autolock autoLock(mLock); - if (n < 0) { + if (n == 0 || mDisconnecting) { + ALOGI("ERROR_END_OF_STREAM"); + + mNumRetriesLeft = 0; + mFinalStatus = ERROR_END_OF_STREAM; + + mCache->releasePage(page); + } else if (n < 0) { mFinalStatus = n; if (n == ERROR_UNSUPPORTED || n == -EPIPE) { // These are errors that are not likely to go away even if we @@ -337,13 +362,6 @@ void NuCachedSource2::fetchInternal() { ALOGE("source returned error %zd, %d retries left", n, mNumRetriesLeft); mCache->releasePage(page); - } else if (n == 0) { - ALOGI("ERROR_END_OF_STREAM"); - - mNumRetriesLeft = 0; - mFinalStatus = ERROR_END_OF_STREAM; - - mCache->releasePage(page); } else { if (mFinalStatus != OK) { ALOGI("retrying a previously failed read succeeded."); diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h index 5db4b4b..4252706 100644 --- a/media/libstagefright/include/NuCachedSource2.h +++ b/media/libstagefright/include/NuCachedSource2.h @@ -37,6 +37,8 @@ struct NuCachedSource2 : public DataSource { virtual ssize_t readAt(off64_t offset, void *data, size_t size); + virtual void disconnect(); + virtual status_t getSize(off64_t *size); virtual uint32_t flags(); @@ -103,6 +105,7 @@ private: off64_t mLastAccessPos; sp mAsyncResult; bool mFetching; + bool mDisconnecting; int64_t mLastFetchTimeUs; int32_t mNumRetriesLeft; -- cgit v1.1 From da23ab9b0dfa780175651daf057a02b0aa106dc8 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Tue, 16 Sep 2014 11:34:08 -0700 Subject: GenericSource: fix selectTrack parameter Bug: 17512187 Change-Id: I19a0915fb0fb1b1ae036bf5df85b9c9e7657a7ea --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 511871d..a57e0f2 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -942,7 +942,7 @@ status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); sp msg = new AMessage(kWhatSelectTrack, id()); msg->setInt32("trackIndex", trackIndex); - msg->setInt32("select", trackIndex); + msg->setInt32("select", select); sp response; status_t err = msg->postAndAwaitResponse(&response); -- cgit v1.1 From 6e9f6b498d758848fd934f8217c386dd74ef3833 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Tue, 16 Sep 2014 17:07:22 -0700 Subject: NuPlayerDriver: restart after eos pause Bug: 17512187 Change-Id: I204ce83790bf98bc7ffebcb76d5df1e56a6a3f66 --- media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 7dd54c1..4e6b4d8 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -263,8 +263,15 @@ status_t NuPlayerDriver::start() { case STATE_PAUSED: case STATE_STOPPED_AND_PREPARED: { - mPlayer->resume(); - mPositionUs -= ALooper::GetNowUs() - mPauseStartedTimeUs; + if (mAtEOS) { + mPlayer->seekToAsync(0); + mAtEOS = false; + mPlayer->resume(); + mPositionUs = -1; + } else { + mPlayer->resume(); + mPositionUs -= ALooper::GetNowUs() - mPauseStartedTimeUs; + } break; } -- cgit v1.1 From 317a49a4c4bf02944d1e01941c6b9f86179044bb Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 16 Sep 2014 21:32:33 -0700 Subject: mediaplayer: reset flags when pre-reading multiple buffers Bug: 17521470 Change-Id: I15ee9b1d3dd4ad29f4961a642f7fadafd9fe5b24 --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index bd67cbd..3eb87a4 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -1256,6 +1256,8 @@ void NuPlayer::GenericSource::readBuffer( sp buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs); track->mPackets->queueAccessUnit(buffer); + formatChange = false; + seeking = false; ++numBuffers; } else if (err == WOULD_BLOCK) { break; -- cgit v1.1 From f0b72b509ab1147a2a0925aced970dd68fd7fa4f Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 16 Sep 2014 15:43:44 -0700 Subject: Add support for ANDROID_LOOP to NuPlayer Bug: 17518139 Change-Id: I9355ddd4c998d967013dd8bd32d670a9a83dea31 --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 10 +++++++--- media/libmediaplayerservice/nuplayer/GenericSource.h | 3 +++ media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 4 ++++ media/libmediaplayerservice/nuplayer/NuPlayer.h | 2 ++ media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 12 +++++++++++- media/libmediaplayerservice/nuplayer/NuPlayerDriver.h | 2 ++ media/libmediaplayerservice/nuplayer/NuPlayerSource.h | 1 + 7 files changed, 30 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 511871d..d194e73 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -106,6 +106,10 @@ status_t NuPlayer::GenericSource::setDataSource( return OK; } +sp NuPlayer::GenericSource::getFileFormatMeta() const { + return mFileMeta; +} + status_t NuPlayer::GenericSource::initFromDataSource() { sp extractor; @@ -144,10 +148,10 @@ status_t NuPlayer::GenericSource::initFromDataSource() { checkDrmStatus(mDataSource); } - sp fileMeta = extractor->getMetaData(); - if (fileMeta != NULL) { + mFileMeta = extractor->getMetaData(); + if (mFileMeta != NULL) { int64_t duration; - if (fileMeta->findInt64(kKeyDuration, &duration)) { + if (mFileMeta->findInt64(kKeyDuration, &duration)) { mDurationUs = duration; } } diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index c70c48e..dcdfb0a 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -57,6 +57,8 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual status_t feedMoreTSData(); + virtual sp getFileFormatMeta() const; + virtual status_t dequeueAccessUnit(bool audio, sp *accessUnit); virtual status_t getDuration(int64_t *durationUs); @@ -123,6 +125,7 @@ private: sp mDataSource; sp mCachedSource; sp mWVMExtractor; + sp mFileMeta; DrmManagerClient *mDrmManagerClient; sp mDecryptHandle; bool mStarted; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 9020a8d..4bb7c96 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1720,6 +1720,10 @@ status_t NuPlayer::selectTrack(size_t trackIndex, bool select) { return err; } +sp NuPlayer::getFileMeta() { + return mSource->getFileFormatMeta(); +} + void NuPlayer::schedulePollDuration() { sp msg = new AMessage(kWhatPollDuration, id()); msg->setInt32("generation", mPollDurationGeneration); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 2e951bd..7197e5f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -67,6 +67,8 @@ struct NuPlayer : public AHandler { status_t getSelectedTrack(int32_t type, Parcel* reply) const; status_t selectTrack(size_t trackIndex, bool select); + sp getFileMeta(); + static const size_t kAggregateBufferSizeBytes; protected: diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 7dd54c1..69aa7b3 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -45,6 +45,7 @@ NuPlayerDriver::NuPlayerDriver() mPlayerFlags(0), mAtEOS(false), mLooping(false), + mAutoLoop(false), mStartupSeekTimeUs(-1) { mLooper->setName("NuPlayerDriver Looper"); @@ -498,6 +499,7 @@ status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) { void NuPlayerDriver::setAudioSink(const sp &audioSink) { mPlayer->setAudioSink(audioSink); + mAudioSink = audioSink; } status_t NuPlayerDriver::setParameter( @@ -627,7 +629,8 @@ void NuPlayerDriver::notifyListener_l( case MEDIA_PLAYBACK_COMPLETE: { if (mState != STATE_RESET_IN_PROGRESS) { - if (mLooping) { + if (mLooping || (mAutoLoop + && (mAudioSink == NULL || mAudioSink->realtime()))) { mPlayer->seekToAsync(0); break; } @@ -693,6 +696,13 @@ void NuPlayerDriver::notifyPrepareCompleted(status_t err) { } } + sp meta = mPlayer->getFileMeta(); + int32_t loop; + if (meta != NULL + && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { + mAutoLoop = true; + } + mCondition.broadcast(); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index e81d605..f2bd431 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -114,10 +114,12 @@ private: sp mLooper; sp mPlayer; + sp mAudioSink; uint32_t mPlayerFlags; bool mAtEOS; bool mLooping; + bool mAutoLoop; int64_t mStartupSeekTimeUs; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index 7ccf3b1..a2d9b2f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -73,6 +73,7 @@ struct NuPlayer::Source : public AHandler { virtual sp getFormat(bool audio); virtual sp getFormatMeta(bool /* audio */) { return NULL; } + virtual sp getFileFormatMeta() const { return NULL; } virtual status_t dequeueAccessUnit( bool audio, sp *accessUnit) = 0; -- cgit v1.1 From 15f8ecfa23b650b3efa8fe841d2be6bd0c9523fb Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Mon, 15 Sep 2014 13:36:30 -0700 Subject: PlaylistFetcher:don't signal a/v eos on subttitle eos Bug: 17310061 Change-Id: Ifbca3c12f21171a6e429dca51a250a41051fdd34 --- media/libstagefright/httplive/LiveSession.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 7786c27..b465566 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -443,6 +443,23 @@ void LiveSession::onMessageReceived(const sp &msg) { ALOGE("XXX Received error %d from PlaylistFetcher.", err); + // handle EOS on subtitle tracks independently + AString uri; + if (err == ERROR_END_OF_STREAM && msg->findString("uri", &uri)) { + ssize_t i = mFetcherInfos.indexOfKey(uri); + if (i >= 0) { + const sp &fetcher = mFetcherInfos.valueAt(i).mFetcher; + if (fetcher != NULL) { + uint32_t type = fetcher->getStreamTypeMask(); + if (type == STREAMTYPE_SUBTITLES) { + mPacketSources.valueFor( + STREAMTYPE_SUBTITLES)->signalEOS(err);; + break; + } + } + } + } + if (mInPreparationPhase) { postPrepared(err); } -- cgit v1.1 From 9b7db1c57ff2a3f854568dd61fcec82ff63addeb Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 17 Sep 2014 12:38:33 -0700 Subject: Fix null pointer dereference Bug: 17544813 Change-Id: I6c94cd3056a99bb42fc71ee583938a2e3806fdc7 --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 4569c1c..456be89 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -705,7 +705,9 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { } // Discard input buffer. - inHeader->nFilledLen = 0; + if (inHeader) { + inHeader->nFilledLen = 0; + } aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); @@ -736,7 +738,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { notify(OMX_EventPortSettingsChanged, 1, 0, NULL); mOutputPortSettingsChange = AWAITING_DISABLED; - if (inHeader->nFilledLen == 0) { + if (inHeader && inHeader->nFilledLen == 0) { inInfo->mOwnedByUs = false; mInputBufferCount++; inQueue.erase(inQueue.begin()); -- cgit v1.1 From 06ad1528e6dd4c866c085d3cad9235d2752eb3ed Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 28 Aug 2014 07:27:44 -0700 Subject: NuPlayer: use getTimestamp instead of getPosition Bug: 14659809 Bug: 16985287 Change-Id: I59ec72fbd40a9b8d28fe548ddad082c03000c045 --- media/libmediaplayerservice/MediaPlayerService.cpp | 16 ++++++ media/libmediaplayerservice/MediaPlayerService.h | 2 + .../nuplayer/NuPlayerRenderer.cpp | 60 ++++++++++++++-------- .../nuplayer/NuPlayerRenderer.h | 3 +- 4 files changed, 58 insertions(+), 23 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index c8cb7ed..8eb1269 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -43,6 +43,7 @@ #include // for status_t #include #include +#include #include #include @@ -1496,6 +1497,12 @@ status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position) const return mTrack->getPosition(position); } +status_t MediaPlayerService::AudioOutput::getTimestamp(AudioTimestamp &ts) const +{ + if (mTrack == 0) return NO_INIT; + return mTrack->getTimestamp(ts); +} + status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const { if (mTrack == 0) return NO_INIT; @@ -1971,6 +1978,15 @@ status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position) const return NO_ERROR; } +status_t MediaPlayerService::AudioCache::getTimestamp(AudioTimestamp &ts) const +{ + ts.mPosition = mSize / mFrameSize; + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + ts.mTime.tv_sec = now / 1000000000LL; + ts.mTime.tv_nsec = now - (1000000000LL * ts.mTime.tv_sec); + return NO_ERROR; +} + status_t MediaPlayerService::AudioCache::getFramesWritten(uint32_t *written) const { if (written == 0) return BAD_VALUE; diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 4fe7075..3b96e88 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -85,6 +85,7 @@ class MediaPlayerService : public BnMediaPlayerService virtual uint32_t latency() const; virtual float msecsPerFrame() const; virtual status_t getPosition(uint32_t *position) const; + virtual status_t getTimestamp(AudioTimestamp &ts) const; virtual status_t getFramesWritten(uint32_t *frameswritten) const; virtual int getSessionId() const; virtual uint32_t getSampleRate() const; @@ -198,6 +199,7 @@ class MediaPlayerService : public BnMediaPlayerService virtual uint32_t latency() const; virtual float msecsPerFrame() const; virtual status_t getPosition(uint32_t *position) const; + virtual status_t getTimestamp(AudioTimestamp &ts) const; virtual status_t getFramesWritten(uint32_t *frameswritten) const; virtual int getSessionId() const; virtual uint32_t getSampleRate() const; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 067784b..8ab777a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -343,15 +343,13 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { mFirstAudioTimeUs = mediaTimeUs; } - uint32_t numFramesPlayed; - CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); - - // TODO: figure out how to calculate initial latency. - // Otherwise, the initial time is not correct till the first sample - // is played. - mAnchorTimeMediaUs = mFirstAudioTimeUs - + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll; - mAnchorTimeRealUs = ALooper::GetNowUs(); + // TODO: figure out how to calculate initial latency if + // getTimestamp is not available. Otherwise, the initial time + // is not correct till the first sample is played. + int64_t nowUs = ALooper::GetNowUs(); + mAnchorTimeMediaUs = + mFirstAudioTimeUs + getPlayedOutAudioDurationUs(nowUs); + mAnchorTimeRealUs = nowUs; } size_t copy = entry->mBuffer->size() - entry->mOffset; @@ -413,7 +411,7 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { // EOS int64_t postEOSDelayUs = 0; if (mAudioSink->needsTrailingPadding()) { - postEOSDelayUs = getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency(); + postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs()); } notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs); @@ -428,8 +426,8 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); mAnchorTimeMediaUs = mediaTimeUs; - mAnchorTimeRealUs = ALooper::GetNowUs() - + getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency() / 2; + int64_t nowUs = ALooper::GetNowUs(); + mAnchorTimeRealUs = nowUs + getPendingAudioPlayoutDurationUs(nowUs); } size_t copy = entry->mBuffer->size() - entry->mOffset; @@ -483,12 +481,10 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { return !mAudioQueue.empty(); } -int64_t NuPlayer::Renderer::getAudioPendingPlayoutUs() { - uint32_t numFramesPlayed; - CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); - - uint32_t numFramesPendingPlayout = mNumFramesWritten - numFramesPlayed; - return numFramesPendingPlayout * mAudioSink->msecsPerFrame() * 1000; +int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) { + int64_t writtenAudioDurationUs = + mNumFramesWritten * 1000LL * mAudioSink->msecsPerFrame(); + return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs); } void NuPlayer::Renderer::postDrainVideoQueue() { @@ -937,17 +933,37 @@ void NuPlayer::Renderer::onResume() { } } -void NuPlayer::Renderer::onAudioOffloadTearDown() { +int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) { + // FIXME: getTimestamp sometimes returns negative frame count. + // Since we do not handle the rollover at this point (which can + // happen every 14 hours), simply treat the timestamp as signed. uint32_t numFramesPlayed; - CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); + int64_t numFramesPlayedAt; + AudioTimestamp ts; + status_t res = mAudioSink->getTimestamp(ts); + if (res == OK) { + numFramesPlayed = ts.mPosition; + numFramesPlayedAt = + ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000; + } else { + res = mAudioSink->getPosition(&numFramesPlayed); + CHECK_EQ(res, (status_t)OK); + numFramesPlayedAt = nowUs; + numFramesPlayedAt += 1000LL * mAudioSink->latency() / 2; /* XXX */ + } + return (int32_t)numFramesPlayed * 1000LL * mAudioSink->msecsPerFrame() + + nowUs - numFramesPlayedAt; +} +void NuPlayer::Renderer::onAudioOffloadTearDown() { int64_t firstAudioTimeUs; { Mutex::Autolock autoLock(mLock); firstAudioTimeUs = mFirstAudioTimeUs; } - int64_t currentPositionUs = firstAudioTimeUs - + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll; + + int64_t currentPositionUs = + firstAudioTimeUs + getPlayedOutAudioDurationUs(ALooper::GetNowUs()); mAudioSink->stop(); mAudioSink->flush(); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 5c7d2d7..2b32c48 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -130,7 +130,8 @@ private: size_t fillAudioBuffer(void *buffer, size_t size); bool onDrainAudioQueue(); - int64_t getAudioPendingPlayoutUs(); + int64_t getPendingAudioPlayoutDurationUs(int64_t nowUs); + int64_t getPlayedOutAudioDurationUs(int64_t nowUs); void postDrainAudioQueue_l(int64_t delayUs = 0); void onDrainVideoQueue(); -- cgit v1.1 From 33b51b07ca90cc3b48e86598f7e82f93e440fe02 Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Wed, 17 Sep 2014 16:03:47 -0700 Subject: mediaplayer: fix buffer aggregation when video has offloaded audio Change conditional test so we don't accidentally do buffer aggregation on video buffers. Bug: 17553847 Change-Id: I746452b2e62db664315732a38f982ce7faf26212 Signed-off-by: Phil Burk --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 9020a8d..b6d27e2 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1260,8 +1260,8 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { // Aggregate smaller buffers into a larger buffer. // The goal is to reduce power consumption. - // Unfortunately this does not work with the software AAC decoder. - bool doBufferAggregation = (audio && mOffloadAudio);; + // Note this will not work if the decoder requires one frame per buffer. + bool doBufferAggregation = (audio && mOffloadAudio); bool needMoreData = false; bool dropAccessUnit; @@ -1281,7 +1281,7 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { return err; } else if (err != OK) { if (err == INFO_DISCONTINUITY) { - if (mAggregateBuffer != NULL) { + if (doBufferAggregation && (mAggregateBuffer != NULL)) { // We already have some data so save this for later. mPendingAudioErr = err; mPendingAudioAccessUnit = accessUnit; @@ -1404,7 +1404,7 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { mAggregateBuffer->setRange(0, 0); // start empty } - if (mAggregateBuffer != NULL) { + if (doBufferAggregation && (mAggregateBuffer != NULL)) { int64_t timeUs; int64_t dummy; bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs); @@ -1453,7 +1453,7 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { mCCDecoder->decode(accessUnit); } - if (mAggregateBuffer != NULL) { + if (doBufferAggregation && (mAggregateBuffer != NULL)) { ALOGV("feedDecoderInputData() reply with aggregated buffer, %zu", mAggregateBuffer->size()); reply->setBuffer("buffer", mAggregateBuffer); -- cgit v1.1 From 09e0c3646362d29c78bc26c8b23b7a753c412e6c Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Fri, 12 Sep 2014 15:12:16 -0700 Subject: NuPlayer: update timestamp handling Use getTimestamp WOULD_BLOCK error return code to clean up initial playback/start timestamp handling. Account for pause time and seeks. Only send notification from driver when the media time changes. Bug: 14659809 Bug: 17428188 Change-Id: I051bb5e2dd4fd5990474f8fb635615ad8d18eb2c --- .../nuplayer/NuPlayerDriver.cpp | 32 +++++- .../nuplayer/NuPlayerRenderer.cpp | 116 +++++++++++++++------ .../nuplayer/NuPlayerRenderer.h | 2 +- 3 files changed, 117 insertions(+), 33 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 4e6b4d8..bcf8e99 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -270,7 +270,14 @@ status_t NuPlayerDriver::start() { mPositionUs = -1; } else { mPlayer->resume(); - mPositionUs -= ALooper::GetNowUs() - mPauseStartedTimeUs; + if (mNotifyTimeRealUs != -1) { + // Pause time must be set if here by setPauseStartedTimeIfNeeded(). + //CHECK(mPauseStartedTimeUs != -1); + + // if no seek occurs, adjust our notify time so that getCurrentPosition() + // is continuous if read immediately after calling start(). + mNotifyTimeRealUs += ALooper::GetNowUs() - mPauseStartedTimeUs; + } } break; } @@ -378,15 +385,36 @@ status_t NuPlayerDriver::getCurrentPosition(int *msec) { Mutex::Autolock autoLock(mLock); if (mPositionUs < 0) { + // mPositionUs is the media time. + // It is negative under these cases + // (1) == -1 after reset, or very first playback, no stream notification yet. + // (2) == -1 start after end of stream, no stream notification yet. + // (3) == large negative # after ~292,471 years of continuous playback. + + //CHECK_EQ(mPositionUs, -1); *msec = 0; } else if (mNotifyTimeRealUs == -1) { + // A seek has occurred just occurred, no stream notification yet. + // mPositionUs (>= 0) is the new media position. *msec = mPositionUs / 1000; } else { + // mPosition must be valid (i.e. >= 0) by the first check above. + // We're either playing or have pause time set: mPauseStartedTimeUs is >= 0 + //LOG_ALWAYS_FATAL_IF( + // !isPlaying() && mPauseStartedTimeUs < 0, + // "Player in non-playing mState(%d) and mPauseStartedTimeUs(%lld) < 0", + // mState, (long long)mPauseStartedTimeUs); + ALOG_ASSERT(mNotifyTimeRealUs >= 0); int64_t nowUs = (isPlaying() ? ALooper::GetNowUs() : mPauseStartedTimeUs); *msec = (mPositionUs + nowUs - mNotifyTimeRealUs + 500ll) / 1000; + // It is possible for *msec to be negative if the media position is > 596 hours. + // but we turn on this checking in NDEBUG == 0 mode. + ALOG_ASSERT(*msec >= 0); + ALOGV("getCurrentPosition nowUs(%lld)", (long long)nowUs); } - + ALOGV("getCurrentPosition returning(%d) mPositionUs(%lld) mNotifyRealTimeUs(%lld)", + *msec, (long long)mPositionUs, (long long)mNotifyTimeRealUs); return OK; } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 8ab777a..7674616 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -45,7 +45,7 @@ NuPlayer::Renderer::Renderer( mDrainVideoQueuePending(false), mAudioQueueGeneration(0), mVideoQueueGeneration(0), - mFirstAudioTimeUs(-1), + mFirstAnchorTimeMediaUs(-1), mAnchorTimeMediaUs(-1), mAnchorTimeRealUs(-1), mFlushingAudio(false), @@ -54,12 +54,12 @@ NuPlayer::Renderer::Renderer( mHasVideo(false), mSyncQueues(false), mPaused(false), + mVideoSampleReceived(false), mVideoRenderingStarted(false), mVideoRenderingStartGeneration(0), mAudioRenderingStartGeneration(0), mLastPositionUpdateUs(-1ll), - mVideoLateByUs(0ll), - mVideoSampleReceived(false) { + mVideoLateByUs(0ll) { } NuPlayer::Renderer::~Renderer() { @@ -115,6 +115,7 @@ void NuPlayer::Renderer::signalTimeDiscontinuity() { Mutex::Autolock autoLock(mLock); // CHECK(mAudioQueue.empty()); // CHECK(mVideoQueue.empty()); + mFirstAnchorTimeMediaUs = -1; mAnchorTimeMediaUs = -1; mAnchorTimeRealUs = -1; mSyncQueues = false; @@ -339,17 +340,16 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { int64_t mediaTimeUs; CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); - if (mFirstAudioTimeUs == -1) { - mFirstAudioTimeUs = mediaTimeUs; + if (mFirstAnchorTimeMediaUs == -1) { + mFirstAnchorTimeMediaUs = mediaTimeUs; } - // TODO: figure out how to calculate initial latency if - // getTimestamp is not available. Otherwise, the initial time - // is not correct till the first sample is played. int64_t nowUs = ALooper::GetNowUs(); mAnchorTimeMediaUs = - mFirstAudioTimeUs + getPlayedOutAudioDurationUs(nowUs); + mFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs); mAnchorTimeRealUs = nowUs; + + notifyPosition(); } size_t copy = entry->mBuffer->size() - entry->mOffset; @@ -372,10 +372,6 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { notifyIfMediaRenderingStarted(); } - if (sizeCopied != 0) { - notifyPosition(); - } - if (hasEOS) { (new AMessage(kWhatStopAudioSink, id()))->post(); } @@ -424,10 +420,15 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { int64_t mediaTimeUs; CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); + if (mFirstAnchorTimeMediaUs == -1) { + mFirstAnchorTimeMediaUs = mediaTimeUs; + } mAnchorTimeMediaUs = mediaTimeUs; int64_t nowUs = ALooper::GetNowUs(); mAnchorTimeRealUs = nowUs + getPendingAudioPlayoutDurationUs(nowUs); + + notifyPosition(); } size_t copy = entry->mBuffer->size() - entry->mOffset; @@ -476,8 +477,6 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { break; } } - notifyPosition(); - return !mAudioQueue.empty(); } @@ -517,12 +516,16 @@ void NuPlayer::Renderer::postDrainVideoQueue() { int64_t mediaTimeUs; CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); + if (mFirstAnchorTimeMediaUs == -1 && !mHasAudio) { + mFirstAnchorTimeMediaUs = mediaTimeUs; + } if (mAnchorTimeMediaUs < 0) { delayUs = 0; if (!mHasAudio) { mAnchorTimeMediaUs = mediaTimeUs; mAnchorTimeRealUs = ALooper::GetNowUs(); + notifyPosition(); } } else { int64_t realTimeUs = @@ -554,8 +557,6 @@ void NuPlayer::Renderer::onDrainVideoQueue() { entry = NULL; mVideoLateByUs = 0ll; - - notifyPosition(); return; } @@ -601,8 +602,6 @@ void NuPlayer::Renderer::onDrainVideoQueue() { } notifyIfMediaRenderingStarted(); } - - notifyPosition(); } void NuPlayer::Renderer::notifyVideoRenderingStart() { @@ -779,7 +778,7 @@ void NuPlayer::Renderer::onFlush(const sp &msg) { prepareForMediaRenderingStart(); if (offloadingAudio()) { - mFirstAudioTimeUs = -1; + mFirstAnchorTimeMediaUs = -1; } } @@ -867,9 +866,11 @@ void NuPlayer::Renderer::onDisableOffloadAudio() { } void NuPlayer::Renderer::notifyPosition() { - if (mAnchorTimeRealUs < 0 || mAnchorTimeMediaUs < 0) { - return; - } + // notifyPosition() must be called only after setting mAnchorTimeRealUs + // and mAnchorTimeMediaUs, and must not be paused as it extrapolates position. + //CHECK_GE(mAnchorTimeRealUs, 0); + //CHECK_GE(mAnchorTimeMediaUs, 0); + //CHECK(!mPaused || !mHasAudio); // video-only does display in paused mode. int64_t nowUs = ALooper::GetNowUs(); @@ -881,6 +882,18 @@ void NuPlayer::Renderer::notifyPosition() { int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs; + //ALOGD("notifyPosition: positionUs(%lld) nowUs(%lld) mAnchorTimeRealUs(%lld)" + // " mAnchorTimeMediaUs(%lld) mFirstAnchorTimeMediaUs(%lld)", + // (long long)positionUs, (long long)nowUs, (long long)mAnchorTimeRealUs, + // (long long)mAnchorTimeMediaUs, (long long)mFirstAnchorTimeMediaUs); + + // Due to adding the latency to mAnchorTimeRealUs in onDrainAudioQueue(), + // positionUs may be less than the first media time. This is avoided + // here to prevent potential retrograde motion of the position bar + // when starting up after a seek. + if (positionUs < mFirstAnchorTimeMediaUs) { + positionUs = mFirstAnchorTimeMediaUs; + } sp notify = mNotify->dup(); notify->setInt32("what", kWhatPosition); notify->setInt64("positionUs", positionUs); @@ -933,33 +946,76 @@ void NuPlayer::Renderer::onResume() { } } +// TODO: Remove unnecessary calls to getPlayedOutAudioDurationUs() +// as it acquires locks and may query the audio driver. +// +// Some calls are not needed since notifyPosition() doesn't always deliver a message. +// Some calls could conceivably retrieve extrapolated data instead of +// accessing getTimestamp() or getPosition() every time a data buffer with +// a media time is received. +// int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) { - // FIXME: getTimestamp sometimes returns negative frame count. - // Since we do not handle the rollover at this point (which can - // happen every 14 hours), simply treat the timestamp as signed. uint32_t numFramesPlayed; int64_t numFramesPlayedAt; AudioTimestamp ts; + static const int64_t kStaleTimestamp100ms = 100000; + status_t res = mAudioSink->getTimestamp(ts); - if (res == OK) { + if (res == OK) { // case 1: mixing audio tracks and offloaded tracks. numFramesPlayed = ts.mPosition; numFramesPlayedAt = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000; - } else { + const int64_t timestampAge = nowUs - numFramesPlayedAt; + if (timestampAge > kStaleTimestamp100ms) { + // This is an audio FIXME. + // getTimestamp returns a timestamp which may come from audio mixing threads. + // After pausing, the MixerThread may go idle, thus the mTime estimate may + // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms, + // the max latency should be about 25ms with an average around 12ms (to be verified). + // For safety we use 100ms. + ALOGW("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)", + (long long)nowUs, (long long)numFramesPlayedAt); + numFramesPlayedAt = nowUs - kStaleTimestamp100ms; + } + //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAt); + } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track + numFramesPlayed = 0; + numFramesPlayedAt = nowUs; + //ALOGD("getTimestamp: WOULD_BLOCK %d %lld", + // numFramesPlayed, (long long)numFramesPlayedAt); + } else { // case 3: transitory at new track or audio fast tracks. res = mAudioSink->getPosition(&numFramesPlayed); CHECK_EQ(res, (status_t)OK); numFramesPlayedAt = nowUs; numFramesPlayedAt += 1000LL * mAudioSink->latency() / 2; /* XXX */ + //ALOGD("getPosition: %d %lld", numFramesPlayed, numFramesPlayedAt); } - return (int32_t)numFramesPlayed * 1000LL * mAudioSink->msecsPerFrame() + + // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours. + //CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test + int64_t durationUs = (int32_t)numFramesPlayed * 1000LL * mAudioSink->msecsPerFrame() + nowUs - numFramesPlayedAt; + if (durationUs < 0) { + // Occurs when numFramesPlayed position is very small and the following: + // (1) In case 1, the time nowUs is computed before getTimestamp() is called and + // numFramesPlayedAt is greater than nowUs by time more than numFramesPlayed. + // (2) In case 3, using getPosition and adding mAudioSink->latency() to + // numFramesPlayedAt, by a time amount greater than numFramesPlayed. + // + // Both of these are transitory conditions. + ALOGW("getPlayedOutAudioDurationUs: negative timestamp %lld set to zero", (long long)durationUs); + durationUs = 0; + } + ALOGV("getPlayedOutAudioDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)", + (long long)durationUs, (long long)nowUs, numFramesPlayed, (long long)numFramesPlayedAt); + return durationUs; } void NuPlayer::Renderer::onAudioOffloadTearDown() { int64_t firstAudioTimeUs; { Mutex::Autolock autoLock(mLock); - firstAudioTimeUs = mFirstAudioTimeUs; + firstAudioTimeUs = mFirstAnchorTimeMediaUs; } int64_t currentPositionUs = diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 2b32c48..97fdae7 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -106,7 +106,7 @@ private: int32_t mAudioQueueGeneration; int32_t mVideoQueueGeneration; - int64_t mFirstAudioTimeUs; + int64_t mFirstAnchorTimeMediaUs; int64_t mAnchorTimeMediaUs; int64_t mAnchorTimeRealUs; -- cgit v1.1 From 7f1bc8af1c46695191bf7e2aba6467f3616629c0 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Fri, 12 Sep 2014 14:43:11 -0700 Subject: Fix AudioTrack offloaded timestamp handling. getTimestamp for offloaded tracks now returns WOULD_BLOCK for situations where the timestamp is unavailable due to the previous track still flushing or the timestamp is stale. It is fixed for normal playback conditions. Bug: 14659809 Bug: 17428188 Change-Id: Ic9ec07ccabc604236979769db5c4ea2dec252660 --- media/libmedia/AudioTrack.cpp | 98 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index ff7da83..762dca5 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -37,6 +37,19 @@ namespace android { // --------------------------------------------------------------------------- +static int64_t convertTimespecToUs(const struct timespec &tv) +{ + return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000; +} + +// current monotonic time in microseconds. +static int64_t getNowUs() +{ + struct timespec tv; + (void) clock_gettime(CLOCK_MONOTONIC, &tv); + return convertTimespecToUs(tv); +} + // static status_t AudioTrack::getMinFrameCount( size_t* frameCount, @@ -420,6 +433,7 @@ status_t AudioTrack::set( mServer = 0; mPosition = 0; mReleased = 0; + mStartUs = 0; AudioSystem::acquireAudioSessionId(mSessionId, mClientPid); mSequence = 1; mObservedSequence = mSequence; @@ -451,6 +465,12 @@ status_t AudioTrack::start() // reset current position as seen by client to 0 mPosition = 0; mReleased = 0; + // For offloaded tracks, we don't know if the hardware counters are really zero here, + // since the flush is asynchronous and stop may not fully drain. + // We save the time when the track is started to later verify whether + // the counters are realistic (i.e. start from zero after this time). + mStartUs = getNowUs(); + // force refresh of remaining frames by processAudioBuffer() as last // write before stop could be partial. mRefreshRemaining = true; @@ -587,9 +607,18 @@ void AudioTrack::pause() if (isOffloaded_l()) { if (mOutput != AUDIO_IO_HANDLE_NONE) { + // An offload output can be re-used between two audio tracks having + // the same configuration. A timestamp query for a paused track + // while the other is running would return an incorrect time. + // To fix this, cache the playback position on a pause() and return + // this time when requested until the track is resumed. + + // OffloadThread sends HAL pause in its threadLoop. Time saved + // here can be slightly off. + + // TODO: check return code for getRenderPosition. + uint32_t halFrames; - // OffloadThread sends HAL pause in its threadLoop.. time saved - // here can be slightly off AudioSystem::getRenderPosition(mOutput, &halFrames, &mPausedPosition); ALOGV("AudioTrack::pause for offload, cache current position %u", mPausedPosition); } @@ -825,6 +854,8 @@ status_t AudioTrack::getPosition(uint32_t *position) uint32_t halFrames; AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames); } + // FIXME: dspFrames may not be zero in (mState == STATE_STOPPED || mState == STATE_FLUSHED) + // due to hardware latency. We leave this behavior for now. *position = dspFrames; } else { // IAudioTrack::stop() isn't synchronous; we don't know when presentation completes @@ -1881,13 +1912,70 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) if (mFlags & AUDIO_OUTPUT_FLAG_FAST) { return INVALID_OPERATION; } - if (mState != STATE_ACTIVE && mState != STATE_PAUSED) { - return INVALID_OPERATION; + + switch (mState) { + case STATE_ACTIVE: + case STATE_PAUSED: + break; // handle below + case STATE_FLUSHED: + case STATE_STOPPED: + return WOULD_BLOCK; + case STATE_STOPPING: + case STATE_PAUSED_STOPPING: + if (!isOffloaded_l()) { + return INVALID_OPERATION; + } + break; // offloaded tracks handled below + default: + LOG_ALWAYS_FATAL("Invalid mState in getTimestamp(): %d", mState); + break; } + // The presented frame count must always lag behind the consumed frame count. // To avoid a race, read the presented frames first. This ensures that presented <= consumed. status_t status = mAudioTrack->getTimestamp(timestamp); - if (status == NO_ERROR) { + if (status != NO_ERROR) { + ALOGW_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status); + return status; + } + if (isOffloadedOrDirect_l()) { + if (isOffloaded_l() && (mState == STATE_PAUSED || mState == STATE_PAUSED_STOPPING)) { + // use cached paused position in case another offloaded track is running. + timestamp.mPosition = mPausedPosition; + clock_gettime(CLOCK_MONOTONIC, ×tamp.mTime); + return NO_ERROR; + } + + // Check whether a pending flush or stop has completed, as those commands may + // be asynchronous or return near finish. + if (mStartUs != 0 && mSampleRate != 0) { + static const int kTimeJitterUs = 100000; // 100 ms + static const int k1SecUs = 1000000; + + const int64_t timeNow = getNowUs(); + + if (timeNow < mStartUs + k1SecUs) { // within first second of starting + const int64_t timestampTimeUs = convertTimespecToUs(timestamp.mTime); + if (timestampTimeUs < mStartUs) { + return WOULD_BLOCK; // stale timestamp time, occurs before start. + } + const int64_t deltaTimeUs = timestampTimeUs - mStartUs; + const int64_t deltaPositionByUs = timestamp.mPosition * 1000000LL / mSampleRate; + + if (deltaPositionByUs > deltaTimeUs + kTimeJitterUs) { + // Verify that the counter can't count faster than the sample rate + // since the start time. If greater, then that means we have failed + // to completely flush or stop the previous playing track. + ALOGW("incomplete flush or stop:" + " deltaTimeUs(%lld) deltaPositionUs(%lld) tsmPosition(%u)", + (long long)deltaTimeUs, (long long)deltaPositionByUs, + timestamp.mPosition); + return WOULD_BLOCK; + } + } + mStartUs = 0; // no need to check again, start timestamp has either expired or unneeded. + } + } else { // Update the mapping between local consumed (mPosition) and server consumed (mServer) (void) updateAndGetPosition_l(); // Server consumed (mServer) and presented both use the same server time base, -- cgit v1.1 From a0fd9ca66a68baefd9d76800fd66823fd654ef45 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Thu, 18 Sep 2014 14:07:18 -0700 Subject: AudioEffect acquires session Currently, users of audio sessions, AudioTrack and AudioRecord, are acquiring and releasing audio sessions according to their life-cycle. AudioEffect instances were not counting as users of an audio session. This caused an effect used on a session to be purged by AudioFlinger::purgeStaleEffects_l() whenever the last user of that session went away. This CL makes AudioEffect acquire and release a session when created and destroyed. Bug 15432115 Change-Id: I922532150009988d43872f9b5928044a830ae0b3 --- media/libmedia/AudioEffect.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp index 35f6557..0d5d7e4 100644 --- a/media/libmedia/AudioEffect.cpp +++ b/media/libmedia/AudioEffect.cpp @@ -145,15 +145,19 @@ status_t AudioEffect::set(const effect_uuid_t *type, return mStatus; } - mIEffect = iEffect; mCblkMemory = cblk; mCblk = static_cast(cblk->pointer()); int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int); mCblk->buffer = (uint8_t *)mCblk + bufOffset; iEffect->asBinder()->linkToDeath(mIEffectClient); - ALOGV("set() %p OK effect: %s id: %d status %d enabled %d", this, mDescriptor.name, mId, - mStatus, mEnabled); + mClientPid = IPCThreadState::self()->getCallingPid(); + ALOGV("set() %p OK effect: %s id: %d status %d enabled %d pid %d", this, mDescriptor.name, mId, + mStatus, mEnabled, mClientPid); + + if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) { + AudioSystem::acquireAudioSessionId(mSessionId, mClientPid); + } return mStatus; } @@ -164,6 +168,9 @@ AudioEffect::~AudioEffect() ALOGV("Destructor %p", this); if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) { + if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) { + AudioSystem::releaseAudioSessionId(mSessionId, mClientPid); + } if (mIEffect != NULL) { mIEffect->disconnect(); mIEffect->asBinder()->unlinkToDeath(mIEffectClient); -- cgit v1.1 From 229b7a8d7c986645ef7ef75a36f27feb0c1a4117 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 18 Sep 2014 15:09:28 -0700 Subject: Always consider first buffer to be config for backwards compatibility. Also fix a problem where writing 0 bytes to an empty ringbuffer would treat it as overflowed. Bug: 17567501 Change-Id: I8019da76466576e1b2984e9eccf09bdec593038a --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 456be89..863b908 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -408,6 +408,9 @@ void SoftAAC2::configureDownmix() const { } bool SoftAAC2::outputDelayRingBufferPutSamples(INT_PCM *samples, int32_t numSamples) { + if (numSamples == 0) { + return true; + } if (mOutputDelayRingBufferWritePos + numSamples <= mOutputDelayRingBufferSize && (mOutputDelayRingBufferReadPos <= mOutputDelayRingBufferWritePos || mOutputDelayRingBufferReadPos > mOutputDelayRingBufferWritePos + numSamples)) { @@ -512,6 +515,11 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; mEndOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0; + + if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) { + ALOGE("first buffer should have OMX_BUFFERFLAG_CODECCONFIG set"); + inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG; + } if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) { BufferInfo *inInfo = *inQueue.begin(); OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; -- cgit v1.1 From 800599cdd50737de1cde483a34b39923750b0658 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 29 Aug 2014 18:25:05 -0700 Subject: LiveSession: do not drop seek request Bug: 17538727 Change-Id: I28658b2779ac16512ff54adbe536d01790e6449e --- media/libstagefright/httplive/LiveSession.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index b465566..13cf50c 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -347,10 +347,6 @@ status_t LiveSession::seekTo(int64_t timeUs) { sp response; status_t err = msg->postAndAwaitResponse(&response); - uint32_t replyID; - CHECK(response == mSeekReply && 0 != mSeekReplyID); - mSeekReply.clear(); - mSeekReplyID = 0; return err; } @@ -376,12 +372,16 @@ void LiveSession::onMessageReceived(const sp &msg) { case kWhatSeek: { - CHECK(msg->senderAwaitsResponse(&mSeekReplyID)); + uint32_t seekReplyID; + CHECK(msg->senderAwaitsResponse(&seekReplyID)); + mSeekReplyID = seekReplyID; + mSeekReply = new AMessage; status_t err = onSeek(msg); - mSeekReply = new AMessage; - mSeekReply->setInt32("err", err); + if (err != OK) { + msg->post(50000); + } break; } @@ -416,7 +416,10 @@ void LiveSession::onMessageReceived(const sp &msg) { if (mSeekReplyID != 0) { CHECK(mSeekReply != NULL); + mSeekReply->setInt32("err", OK); mSeekReply->postReply(mSeekReplyID); + mSeekReplyID = 0; + mSeekReply.clear(); } } } @@ -1070,10 +1073,11 @@ status_t LiveSession::onSeek(const sp &msg) { CHECK(msg->findInt64("timeUs", &timeUs)); if (!mReconfigurationInProgress) { - changeConfiguration(timeUs, getBandwidthIndex()); + changeConfiguration(timeUs, mCurBandwidthIndex); + return OK; + } else { + return -EWOULDBLOCK; } - - return OK; } status_t LiveSession::getDuration(int64_t *durationUs) const { @@ -1225,7 +1229,10 @@ void LiveSession::changeConfiguration( if (mSeekReplyID != 0) { CHECK(mSeekReply != NULL); + mSeekReply->setInt32("err", OK); mSeekReply->postReply(mSeekReplyID); + mSeekReplyID = 0; + mSeekReply.clear(); } } } -- cgit v1.1 From dfc34daba6d6cb923683d96689a0cb7c7006eee5 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 19 Sep 2014 09:05:05 -0700 Subject: Reduce log spam from getTimestamp errors Bug: 17576481 Change-Id: I07d99e7c42b7d4f0994b5a6d9c9fe8eb29fbbe40 --- media/libmedia/AudioTrack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 762dca5..ea7b279 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1935,7 +1935,7 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) // To avoid a race, read the presented frames first. This ensures that presented <= consumed. status_t status = mAudioTrack->getTimestamp(timestamp); if (status != NO_ERROR) { - ALOGW_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status); + ALOGV_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status); return status; } if (isOffloadedOrDirect_l()) { -- cgit v1.1 From ab7f4182d4d509733107622216db4dd128340185 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 19 Sep 2014 11:46:44 -0700 Subject: Fix ringbuffer handling Explicitly keep track of the number of samples in the ring buffer, rather than inferring it from the difference between the read and write pointer, since the latter cannot distinguish between a completely full and a completely empty buffer. Bug: 17582331 Change-Id: I24d16ce96710209b7457ffad7c4c60201451980f --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 40 +++++++++++-------------- media/libstagefright/codecs/aacdec/SoftAAC2.h | 3 +- 2 files changed, 19 insertions(+), 24 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 863b908..fb27dca 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -137,6 +137,7 @@ status_t SoftAAC2::initDecoder() { mOutputDelayRingBuffer = new short[mOutputDelayRingBufferSize]; mOutputDelayRingBufferWritePos = 0; mOutputDelayRingBufferReadPos = 0; + mOutputDelayRingBufferFilled = 0; if (mAACDecoder == NULL) { ALOGE("AAC decoder is null. TODO: Can not call aacDecoder_SetParam in the following code"); @@ -411,6 +412,10 @@ bool SoftAAC2::outputDelayRingBufferPutSamples(INT_PCM *samples, int32_t numSamp if (numSamples == 0) { return true; } + if (outputDelayRingBufferSpaceLeft() < numSamples) { + ALOGE("RING BUFFER WOULD OVERFLOW"); + return false; + } if (mOutputDelayRingBufferWritePos + numSamples <= mOutputDelayRingBufferSize && (mOutputDelayRingBufferReadPos <= mOutputDelayRingBufferWritePos || mOutputDelayRingBufferReadPos > mOutputDelayRingBufferWritePos + numSamples)) { @@ -422,10 +427,6 @@ bool SoftAAC2::outputDelayRingBufferPutSamples(INT_PCM *samples, int32_t numSamp if (mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferSize) { mOutputDelayRingBufferWritePos -= mOutputDelayRingBufferSize; } - if (mOutputDelayRingBufferWritePos == mOutputDelayRingBufferReadPos) { - ALOGE("RING BUFFER OVERFLOW"); - return false; - } } else { ALOGV("slow SoftAAC2::outputDelayRingBufferPutSamples()"); @@ -435,16 +436,19 @@ bool SoftAAC2::outputDelayRingBufferPutSamples(INT_PCM *samples, int32_t numSamp if (mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferSize) { mOutputDelayRingBufferWritePos -= mOutputDelayRingBufferSize; } - if (mOutputDelayRingBufferWritePos == mOutputDelayRingBufferReadPos) { - ALOGE("RING BUFFER OVERFLOW"); - return false; - } } } + mOutputDelayRingBufferFilled += numSamples; return true; } int32_t SoftAAC2::outputDelayRingBufferGetSamples(INT_PCM *samples, int32_t numSamples) { + + if (numSamples > mOutputDelayRingBufferFilled) { + ALOGE("RING BUFFER WOULD UNDERRUN"); + return -1; + } + if (mOutputDelayRingBufferReadPos + numSamples <= mOutputDelayRingBufferSize && (mOutputDelayRingBufferWritePos < mOutputDelayRingBufferReadPos || mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferReadPos + numSamples)) { @@ -463,10 +467,6 @@ int32_t SoftAAC2::outputDelayRingBufferGetSamples(INT_PCM *samples, int32_t numS ALOGV("slow SoftAAC2::outputDelayRingBufferGetSamples()"); for (int32_t i = 0; i < numSamples; i++) { - if (mOutputDelayRingBufferWritePos == mOutputDelayRingBufferReadPos) { - ALOGE("RING BUFFER UNDERRUN"); - return -1; - } if (samples != 0) { samples[i] = mOutputDelayRingBuffer[mOutputDelayRingBufferReadPos]; } @@ -476,22 +476,15 @@ int32_t SoftAAC2::outputDelayRingBufferGetSamples(INT_PCM *samples, int32_t numS } } } + mOutputDelayRingBufferFilled -= numSamples; return numSamples; } int32_t SoftAAC2::outputDelayRingBufferSamplesAvailable() { - int32_t available = mOutputDelayRingBufferWritePos - mOutputDelayRingBufferReadPos; - if (available < 0) { - available += mOutputDelayRingBufferSize; - } - if (available < 0) { - ALOGE("FATAL RING BUFFER ERROR"); - return 0; - } - return available; + return mOutputDelayRingBufferFilled; } -int32_t SoftAAC2::outputDelayRingBufferSamplesLeft() { +int32_t SoftAAC2::outputDelayRingBufferSpaceLeft() { return mOutputDelayRingBufferSize - outputDelayRingBufferSamplesAvailable(); } @@ -658,7 +651,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { AAC_DECODER_ERROR decoderErr; do { - if (outputDelayRingBufferSamplesLeft() < + if (outputDelayRingBufferSpaceLeft() < (mStreamInfo->frameSize * mStreamInfo->numChannels)) { ALOGV("skipping decode: not enough space left in ringbuffer"); break; @@ -1032,6 +1025,7 @@ void SoftAAC2::onReset() { mOutputDelayCompensated = 0; mOutputDelayRingBufferWritePos = 0; mOutputDelayRingBufferReadPos = 0; + mOutputDelayRingBufferFilled = 0; mEndOfInput = false; mEndOfOutput = false; mBufferTimestamps.clear(); diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h index 9fcb598..c3e4459 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.h +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h @@ -85,10 +85,11 @@ private: short *mOutputDelayRingBuffer; int32_t mOutputDelayRingBufferWritePos; int32_t mOutputDelayRingBufferReadPos; + int32_t mOutputDelayRingBufferFilled; bool outputDelayRingBufferPutSamples(INT_PCM *samples, int numSamples); int32_t outputDelayRingBufferGetSamples(INT_PCM *samples, int numSamples); int32_t outputDelayRingBufferSamplesAvailable(); - int32_t outputDelayRingBufferSamplesLeft(); + int32_t outputDelayRingBufferSpaceLeft(); DISALLOW_EVIL_CONSTRUCTORS(SoftAAC2); }; -- cgit v1.1 From dc43dfa1294470a4413c37e863ef3b621da8681f Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 7 May 2014 15:33:04 -0700 Subject: mediaplayer: schedule video frames in VSYNC valleys Bug: 14659809 Change-Id: Ic340ac61ad4778b493625c79c2cb4f747ff54ede --- media/libmediaplayerservice/Android.mk | 1 + .../libmediaplayerservice/VideoFrameScheduler.cpp | 130 +++++++++++++++++++++ media/libmediaplayerservice/VideoFrameScheduler.h | 60 ++++++++++ media/libmediaplayerservice/nuplayer/Android.mk | 1 + .../nuplayer/NuPlayerDecoder.cpp | 4 +- .../nuplayer/NuPlayerRenderer.cpp | 40 ++++--- .../nuplayer/NuPlayerRenderer.h | 2 + 7 files changed, 224 insertions(+), 14 deletions(-) create mode 100644 media/libmediaplayerservice/VideoFrameScheduler.cpp create mode 100644 media/libmediaplayerservice/VideoFrameScheduler.h (limited to 'media') diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index adc066d..2cf5710 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -22,6 +22,7 @@ LOCAL_SRC_FILES:= \ StagefrightPlayer.cpp \ StagefrightRecorder.cpp \ TestPlayerStub.cpp \ + VideoFrameScheduler.cpp \ LOCAL_SHARED_LIBRARIES := \ libbinder \ diff --git a/media/libmediaplayerservice/VideoFrameScheduler.cpp b/media/libmediaplayerservice/VideoFrameScheduler.cpp new file mode 100644 index 0000000..dd38d5d --- /dev/null +++ b/media/libmediaplayerservice/VideoFrameScheduler.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "VideoFrameScheduler" +#include +#define ATRACE_TAG ATRACE_TAG_VIDEO +#include + +#include + +#include +#include +#include + +#include + +#include "VideoFrameScheduler.h" + +namespace android { + +static const nsecs_t kNanosIn1s = 1000000000; + +/* ======================================================================= */ +/* Frame Scheduler */ +/* ======================================================================= */ + +static const nsecs_t kDefaultVsyncPeriod = kNanosIn1s / 60; // 60Hz +static const nsecs_t kVsyncRefreshPeriod = kNanosIn1s; // 1 sec + +VideoFrameScheduler::VideoFrameScheduler() + : mVsyncTime(0), + mVsyncPeriod(0), + mVsyncRefreshAt(0) { +} + +void VideoFrameScheduler::updateVsync() { + mVsyncRefreshAt = systemTime(SYSTEM_TIME_MONOTONIC) + kVsyncRefreshPeriod; + mVsyncPeriod = 0; + mVsyncTime = 0; + + // TODO: schedule frames for the destination surface + // For now, surface flinger only schedules frames on the primary display + if (mComposer == NULL) { + String16 name("SurfaceFlinger"); + sp sm = defaultServiceManager(); + mComposer = interface_cast(sm->checkService(name)); + } + if (mComposer != NULL) { + DisplayStatInfo stats; + status_t res = mComposer->getDisplayStats(NULL /* display */, &stats); + if (res == OK) { + ALOGV("vsync time:%lld period:%lld", + (long long)stats.vsyncTime, (long long)stats.vsyncPeriod); + mVsyncTime = stats.vsyncTime; + mVsyncPeriod = stats.vsyncPeriod; + } else { + ALOGW("getDisplayStats returned %d", res); + } + } else { + ALOGW("could not get surface mComposer service"); + } +} + +void VideoFrameScheduler::init() { + updateVsync(); +} + +nsecs_t VideoFrameScheduler::getVsyncPeriod() { + if (mVsyncPeriod > 0) { + return mVsyncPeriod; + } + return kDefaultVsyncPeriod; +} + +nsecs_t VideoFrameScheduler::schedule(nsecs_t renderTime) { + nsecs_t origRenderTime = renderTime; + + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + if (now >= mVsyncRefreshAt) { + updateVsync(); + } + + // without VSYNC info, there is nothing to do + if (mVsyncPeriod == 0) { + ALOGV("no vsync: render=%lld", (long long)renderTime); + return renderTime; + } + + // ensure vsync time is well before (corrected) render time + if (mVsyncTime > renderTime - 4 * mVsyncPeriod) { + mVsyncTime -= + ((mVsyncTime - renderTime) / mVsyncPeriod + 5) * mVsyncPeriod; + } + + // Video presentation takes place at the VSYNC _after_ renderTime. Adjust renderTime + // so this effectively becomes a rounding operation (to the _closest_ VSYNC.) + renderTime -= mVsyncPeriod / 2; + + // align rendertime to the center between VSYNC edges + renderTime -= (renderTime - mVsyncTime) % mVsyncPeriod; + renderTime += mVsyncPeriod / 2; + ALOGV("adjusting render: %lld => %lld", (long long)origRenderTime, (long long)renderTime); + ATRACE_INT("FRAME_FLIP_IN(ms)", (renderTime - now) / 1000000); + return renderTime; +} + +void VideoFrameScheduler::release() { + mComposer.clear(); +} + +VideoFrameScheduler::~VideoFrameScheduler() { + release(); +} + +} // namespace android + diff --git a/media/libmediaplayerservice/VideoFrameScheduler.h b/media/libmediaplayerservice/VideoFrameScheduler.h new file mode 100644 index 0000000..9119e45 --- /dev/null +++ b/media/libmediaplayerservice/VideoFrameScheduler.h @@ -0,0 +1,60 @@ +/* + * Copyright 2014, 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 VIDEO_FRAME_SCHEDULER_H_ +#define VIDEO_FRAME_SCHEDULER_H_ + +#include +#include + +#include + +namespace android { + +struct ISurfaceComposer; + +struct VideoFrameScheduler : public RefBase { + VideoFrameScheduler(); + + // (re)initialize scheduler + void init(); + // get adjusted nanotime for a video frame render at renderTime + nsecs_t schedule(nsecs_t renderTime); + + // returns the vsync period for the main display + nsecs_t getVsyncPeriod(); + + void release(); + +protected: + virtual ~VideoFrameScheduler(); + +private: + void updateVsync(); + + nsecs_t mVsyncTime; // vsync timing from display + nsecs_t mVsyncPeriod; + nsecs_t mVsyncRefreshAt; // next time to refresh timing info + + sp mComposer; + + DISALLOW_EVIL_CONSTRUCTORS(VideoFrameScheduler); +}; + +} // namespace android + +#endif // VIDEO_FRAME_SCHEDULER_H_ + diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk index 0dd2b61..676c0a6 100644 --- a/media/libmediaplayerservice/nuplayer/Android.mk +++ b/media/libmediaplayerservice/nuplayer/Android.mk @@ -19,6 +19,7 @@ LOCAL_C_INCLUDES := \ $(TOP)/frameworks/av/media/libstagefright/mpeg2ts \ $(TOP)/frameworks/av/media/libstagefright/rtsp \ $(TOP)/frameworks/av/media/libstagefright/timedtext \ + $(TOP)/frameworks/av/media/libmediaplayerservice \ $(TOP)/frameworks/native/include/media/openmax LOCAL_MODULE:= libstagefright_nuplayer diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 87f85e7..915dd81 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -470,7 +470,9 @@ void NuPlayer::Decoder::onRenderBuffer(const sp &msg) { size_t bufferIx; CHECK(msg->findSize("buffer-ix", &bufferIx)); if (msg->findInt32("render", &render) && render) { - err = mCodec->renderOutputBufferAndRelease(bufferIx); + int64_t timestampNs; + CHECK(msg->findInt64("timestampNs", ×tampNs)); + err = mCodec->renderOutputBufferAndRelease(bufferIx, timestampNs); } else { err = mCodec->releaseOutputBuffer(bufferIx); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 7674616..9934e06 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include namespace android { @@ -502,16 +504,20 @@ void NuPlayer::Renderer::postDrainVideoQueue() { sp msg = new AMessage(kWhatDrainVideoQueue, id()); msg->setInt32("generation", mVideoQueueGeneration); - int64_t delayUs; - if (entry.mBuffer == NULL) { // EOS doesn't carry a timestamp. - delayUs = 0; - } else if (mFlags & FLAG_REAL_TIME) { + msg->post(); + mDrainVideoQueuePending = true; + return; + } + + int64_t delayUs; + int64_t nowUs = ALooper::GetNowUs(); + int64_t realTimeUs; + if (mFlags & FLAG_REAL_TIME) { int64_t mediaTimeUs; CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); - - delayUs = mediaTimeUs - ALooper::GetNowUs(); + realTimeUs = mediaTimeUs; } else { int64_t mediaTimeUs; CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); @@ -520,23 +526,26 @@ void NuPlayer::Renderer::postDrainVideoQueue() { mFirstAnchorTimeMediaUs = mediaTimeUs; } if (mAnchorTimeMediaUs < 0) { - delayUs = 0; - if (!mHasAudio) { mAnchorTimeMediaUs = mediaTimeUs; - mAnchorTimeRealUs = ALooper::GetNowUs(); + mAnchorTimeRealUs = nowUs; notifyPosition(); } + realTimeUs = nowUs; } else { - int64_t realTimeUs = + realTimeUs = (mediaTimeUs - mAnchorTimeMediaUs) + mAnchorTimeRealUs; - - delayUs = realTimeUs - ALooper::GetNowUs(); } } + realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000; + int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000); + + delayUs = realTimeUs - nowUs; + ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs); - msg->post(delayUs); + // post 2 display refreshes before rendering is due + msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0); mDrainVideoQueuePending = true; } @@ -588,6 +597,7 @@ void NuPlayer::Renderer::onDrainVideoQueue() { mVideoLateByUs = 0ll; } + entry->mNotifyConsumed->setInt64("timestampNs", realTimeUs * 1000ll); entry->mNotifyConsumed->setInt32("render", !tooLate); entry->mNotifyConsumed->post(); mVideoQueue.erase(mVideoQueue.begin()); @@ -630,6 +640,10 @@ void NuPlayer::Renderer::onQueueBuffer(const sp &msg) { mHasAudio = true; } else { mHasVideo = true; + if (mVideoScheduler == NULL) { + mVideoScheduler = new VideoFrameScheduler(); + mVideoScheduler->init(); + } } if (dropBufferWhileFlushing(audio, msg)) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 97fdae7..c5a6ec0 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -23,6 +23,7 @@ namespace android { struct ABuffer; +struct VideoFrameScheduler; struct NuPlayer::Renderer : public AHandler { enum Flags { @@ -100,6 +101,7 @@ private: List mAudioQueue; List mVideoQueue; uint32_t mNumFramesWritten; + sp mVideoScheduler; bool mDrainAudioQueuePending; bool mDrainVideoQueuePending; -- cgit v1.1 From b44ce2f84691559672cfaf6bb8fd3a9ac43904f2 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Fri, 19 Sep 2014 14:52:30 -0700 Subject: NuPlayer HLS: better subtitle toggling Bug: 17310061 Change-Id: Iacee1816285425aaad08c32b28591bb0162d5a85 --- media/libstagefright/httplive/LiveSession.cpp | 35 ++++++++++++++++++++++- media/libstagefright/httplive/LiveSession.h | 2 ++ media/libstagefright/httplive/PlaylistFetcher.cpp | 5 +++- media/libstagefright/httplive/PlaylistFetcher.h | 4 ++- 4 files changed, 43 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index b465566..a289637 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -63,6 +63,7 @@ LiveSession::LiveSession( mSwapMask(0), mCheckBandwidthGeneration(0), mSwitchGeneration(0), + mSubtitleGeneration(0), mLastDequeuedTimeUs(0ll), mRealTimeBaseUs(0ll), mReconfigurationInProgress(false), @@ -289,6 +290,11 @@ status_t LiveSession::dequeueAccessUnit( mLastDequeuedTimeUs = timeUs; mRealTimeBaseUs = ALooper::GetNowUs() - timeUs; } else if (stream == STREAMTYPE_SUBTITLES) { + int32_t subtitleGeneration; + if ((*accessUnit)->meta()->findInt32("subtitleGeneration", &subtitleGeneration) + && subtitleGeneration != mSubtitleGeneration) { + return -EAGAIN; + }; (*accessUnit)->meta()->setInt32( "trackIndex", mPlaylist->getSelectedIndex()); (*accessUnit)->meta()->setInt64("baseUs", mRealTimeBaseUs); @@ -759,7 +765,7 @@ sp LiveSession::addFetcher(const char *uri) { notify->setInt32("switchGeneration", mSwitchGeneration); FetcherInfo info; - info.mFetcher = new PlaylistFetcher(notify, this, uri); + info.mFetcher = new PlaylistFetcher(notify, this, uri, mSubtitleGeneration); info.mDurationUs = -1ll; info.mIsPrepared = false; info.mToBeRemoved = false; @@ -1065,6 +1071,24 @@ size_t LiveSession::getBandwidthIndex() { return index; } +int64_t LiveSession::latestMediaSegmentStartTimeUs() { + sp audioMeta = mPacketSources.valueFor(STREAMTYPE_AUDIO)->getLatestDequeuedMeta(); + int64_t minSegmentStartTimeUs = -1, videoSegmentStartTimeUs = -1; + if (audioMeta != NULL) { + audioMeta->findInt64("segmentStartTimeUs", &minSegmentStartTimeUs); + } + + sp videoMeta = mPacketSources.valueFor(STREAMTYPE_VIDEO)->getLatestDequeuedMeta(); + if (videoMeta != NULL + && videoMeta->findInt64("segmentStartTimeUs", &videoSegmentStartTimeUs)) { + if (minSegmentStartTimeUs < 0 || videoSegmentStartTimeUs < minSegmentStartTimeUs) { + minSegmentStartTimeUs = videoSegmentStartTimeUs; + } + + } + return minSegmentStartTimeUs; +} + status_t LiveSession::onSeek(const sp &msg) { int64_t timeUs; CHECK(msg->findInt64("timeUs", &timeUs)); @@ -1117,6 +1141,11 @@ sp LiveSession::getTrackInfo(size_t trackIndex) const { } status_t LiveSession::selectTrack(size_t index, bool select) { + if (mPlaylist == NULL) { + return INVALID_OPERATION; + } + + ++mSubtitleGeneration; status_t err = mPlaylist->selectTrack(index, select); if (err == OK) { sp msg = new AMessage(kWhatChangeConfiguration, id()); @@ -1399,6 +1428,10 @@ void LiveSession::onChangeConfiguration3(const sp &msg) { int32_t discontinuitySeq = -1; sp sources[kMaxStreams]; + if (i == kSubtitleIndex) { + segmentStartTimeUs = latestMediaSegmentStartTimeUs(); + } + // TRICKY: looping from i as earlier streams are already removed from streamMask for (size_t j = i; j < kMaxStreams; ++j) { const AString &streamUri = switching ? mStreams[j].mNewUri : mStreams[j].mUri; diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 6be86cf..7aacca6 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -189,6 +189,7 @@ private: int32_t mCheckBandwidthGeneration; int32_t mSwitchGeneration; + int32_t mSubtitleGeneration; size_t mContinuationCounter; sp mContinuation; @@ -240,6 +241,7 @@ private: const char *url, uint8_t *curPlaylistHash, bool *unchanged); size_t getBandwidthIndex(); + int64_t latestMediaSegmentStartTimeUs(); static int SortByBandwidth(const BandwidthItem *, const BandwidthItem *); static StreamType indexToType(int idx); diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index f78f8b4..30fa868 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -55,7 +55,8 @@ const int32_t PlaylistFetcher::kNumSkipFrames = 10; PlaylistFetcher::PlaylistFetcher( const sp ¬ify, const sp &session, - const char *uri) + const char *uri, + int32_t subtitleGeneration) : mNotify(notify), mStartTimeUsNotify(notify->dup()), mSession(session), @@ -73,6 +74,7 @@ PlaylistFetcher::PlaylistFetcher( mPrepared(false), mNextPTSTimeUs(-1ll), mMonitorQueueGeneration(0), + mSubtitleGeneration(subtitleGeneration), mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY), mFirstPTSValid(false), mAbsoluteTimeAnchorUs(0ll), @@ -1407,6 +1409,7 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( buffer->meta()->setInt64("durationUs", durationUs); buffer->meta()->setInt64("segmentStartTimeUs", getSegmentStartTimeUs(mSeqNumber)); buffer->meta()->setInt32("discontinuitySeq", mDiscontinuitySeq); + buffer->meta()->setInt32("subtitleGeneration", mSubtitleGeneration); packetSource->queueAccessUnit(buffer); return OK; diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index 4b09df1..78c358f 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -49,7 +49,8 @@ struct PlaylistFetcher : public AHandler { PlaylistFetcher( const sp ¬ify, const sp &session, - const char *uri); + const char *uri, + int32_t subtitleGeneration); sp getDataSource(); @@ -133,6 +134,7 @@ private: int64_t mNextPTSTimeUs; int32_t mMonitorQueueGeneration; + const int32_t mSubtitleGeneration; enum RefreshState { INITIAL_MINIMUM_RELOAD_DELAY, -- cgit v1.1 From 705d3290102875409e334e2a80e64221714aa37c Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 19 Sep 2014 15:14:37 -0700 Subject: Make prepare properly report failure again Bug: 17583084 Bug: 17548451 Change-Id: I759d28eaafb520c206d54740c2c0a857b534d23c --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 142107d..cf9c962 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -158,7 +158,12 @@ status_t NuPlayer::GenericSource::initFromDataSource() { int32_t totalBitrate = 0; - for (size_t i = 0; i < extractor->countTracks(); ++i) { + size_t numtracks = extractor->countTracks(); + if (numtracks == 0) { + return UNKNOWN_ERROR; + } + + for (size_t i = 0; i < numtracks; ++i) { sp track = extractor->getTrack(i); sp meta = extractor->getTrackMetaData(i); -- cgit v1.1 From c851b5de495169d7e9528644c2592746021bd968 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 18 Sep 2014 14:14:29 -0700 Subject: mediaplayer: smooth out videoplayback based on framerate Bug: 14659809 Change-Id: I73f6c7224c51ac06487475f9ed395379111ad71f --- .../libmediaplayerservice/VideoFrameScheduler.cpp | 373 ++++++++++++++++++++- media/libmediaplayerservice/VideoFrameScheduler.h | 40 ++- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 7 + .../nuplayer/NuPlayerRenderer.cpp | 25 ++ .../nuplayer/NuPlayerRenderer.h | 4 + 5 files changed, 446 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/VideoFrameScheduler.cpp b/media/libmediaplayerservice/VideoFrameScheduler.cpp index dd38d5d..4251c4e 100644 --- a/media/libmediaplayerservice/VideoFrameScheduler.cpp +++ b/media/libmediaplayerservice/VideoFrameScheduler.cpp @@ -34,6 +34,305 @@ namespace android { static const nsecs_t kNanosIn1s = 1000000000; +template +inline static const T divRound(const T &nom, const T &den) { + if ((nom >= 0) ^ (den >= 0)) { + return (nom - den / 2) / den; + } else { + return (nom + den / 2) / den; + } +} + +template +inline static T abs(const T &a) { + return a < 0 ? -a : a; +} + +template +inline static const T &min(const T &a, const T &b) { + return a < b ? a : b; +} + +template +inline static const T &max(const T &a, const T &b) { + return a > b ? a : b; +} + +template +inline static T periodicError(const T &val, const T &period) { + T err = abs(val) % period; + return (err < (period / 2)) ? err : (period - err); +} + +template +static int compare(const T *lhs, const T *rhs) { + if (*lhs < *rhs) { + return -1; + } else if (*lhs > *rhs) { + return 1; + } else { + return 0; + } +} + +/* ======================================================================= */ +/* PLL */ +/* ======================================================================= */ + +static const size_t kMinSamplesToStartPrime = 3; +static const size_t kMinSamplesToStopPrime = VideoFrameScheduler::kHistorySize; +static const size_t kMinSamplesToEstimatePeriod = 3; +static const size_t kMaxSamplesToEstimatePeriod = VideoFrameScheduler::kHistorySize; + +static const size_t kPrecision = 12; +static const size_t kErrorThreshold = (1 << (kPrecision * 2)) / 10; +static const int64_t kMultiplesThresholdDiv = 4; // 25% +static const int64_t kReFitThresholdDiv = 100; // 1% +static const nsecs_t kMaxAllowedFrameSkip = kNanosIn1s; // 1 sec +static const nsecs_t kMinPeriod = kNanosIn1s / 120; // 120Hz +static const nsecs_t kRefitRefreshPeriod = 10 * kNanosIn1s; // 10 sec + +VideoFrameScheduler::PLL::PLL() + : mPeriod(-1), + mPhase(0), + mPrimed(false), + mSamplesUsedForPriming(0), + mLastTime(-1), + mNumSamples(0) { +} + +void VideoFrameScheduler::PLL::reset(float fps) { + //test(); + + mSamplesUsedForPriming = 0; + mLastTime = -1; + + // set up or reset video PLL + if (fps <= 0.f) { + mPeriod = -1; + mPrimed = false; + } else { + ALOGV("reset at %.1f fps", fps); + mPeriod = (nsecs_t)(1e9 / fps + 0.5); + mPrimed = true; + } + + restart(); +} + +// reset PLL but keep previous period estimate +void VideoFrameScheduler::PLL::restart() { + mNumSamples = 0; + mPhase = -1; +} + +#if 0 + +void VideoFrameScheduler::PLL::test() { + nsecs_t period = kNanosIn1s / 60; + mTimes[0] = 0; + mTimes[1] = period; + mTimes[2] = period * 3; + mTimes[3] = period * 4; + mTimes[4] = period * 7; + mTimes[5] = period * 8; + mTimes[6] = period * 10; + mTimes[7] = period * 12; + mNumSamples = 8; + int64_t a, b, err; + fit(0, period * 12 / 7, 8, &a, &b, &err); + // a = 0.8(5)+ + // b = -0.14097(2)+ + // err = 0.2750578(703)+ + ALOGD("a=%lld (%.6f), b=%lld (%.6f), err=%lld (%.6f)", + (long long)a, (a / (float)(1 << kPrecision)), + (long long)b, (b / (float)(1 << kPrecision)), + (long long)err, (err / (float)(1 << (kPrecision * 2)))); +} + +#endif + +void VideoFrameScheduler::PLL::fit( + nsecs_t phase, nsecs_t period, size_t numSamplesToUse, + int64_t *a, int64_t *b, int64_t *err) { + if (numSamplesToUse > mNumSamples) { + numSamplesToUse = mNumSamples; + } + + int64_t sumX = 0; + int64_t sumXX = 0; + int64_t sumXY = 0; + int64_t sumYY = 0; + int64_t sumY = 0; + + int64_t x = 0; // x usually is in [0..numSamplesToUse) + nsecs_t lastTime; + for (size_t i = 0; i < numSamplesToUse; i++) { + size_t ix = (mNumSamples - numSamplesToUse + i) % kHistorySize; + nsecs_t time = mTimes[ix]; + if (i > 0) { + x += divRound(time - lastTime, period); + } + // y is usually in [-numSamplesToUse..numSamplesToUse+kRefitRefreshPeriod/kMinPeriod) << kPrecision + // ideally in [0..numSamplesToUse), but shifted by -numSamplesToUse during + // priming, and possibly shifted by up to kRefitRefreshPeriod/kMinPeriod + // while we are not refitting. + int64_t y = divRound(time - phase, period >> kPrecision); + sumX += x; + sumY += y; + sumXX += x * x; + sumXY += x * y; + sumYY += y * y; + lastTime = time; + } + + int64_t div = numSamplesToUse * sumXX - sumX * sumX; + int64_t a_nom = numSamplesToUse * sumXY - sumX * sumY; + int64_t b_nom = sumXX * sumY - sumX * sumXY; + *a = divRound(a_nom, div); + *b = divRound(b_nom, div); + // don't use a and b directly as the rounding error is significant + *err = sumYY - divRound(a_nom * sumXY + b_nom * sumY, div); + ALOGV("fitting[%zu] a=%lld (%.6f), b=%lld (%.6f), err=%lld (%.6f)", + numSamplesToUse, + (long long)*a, (*a / (float)(1 << kPrecision)), + (long long)*b, (*b / (float)(1 << kPrecision)), + (long long)*err, (*err / (float)(1 << (kPrecision * 2)))); +} + +void VideoFrameScheduler::PLL::prime(size_t numSamplesToUse) { + if (numSamplesToUse > mNumSamples) { + numSamplesToUse = mNumSamples; + } + CHECK(numSamplesToUse >= 3); // must have at least 3 samples + + // estimate video framerate from deltas between timestamps, and + // 2nd order deltas + Vector deltas; + nsecs_t lastTime, firstTime; + for (size_t i = 0; i < numSamplesToUse; ++i) { + size_t index = (mNumSamples - numSamplesToUse + i) % kHistorySize; + nsecs_t time = mTimes[index]; + if (i > 0) { + if (time - lastTime > kMinPeriod) { + //ALOGV("delta: %lld", (long long)(time - lastTime)); + deltas.push(time - lastTime); + } + } else { + firstTime = time; + } + lastTime = time; + } + deltas.sort(compare); + size_t numDeltas = deltas.size(); + if (numDeltas > 1) { + nsecs_t deltaMinLimit = min(deltas[0] / kMultiplesThresholdDiv, kMinPeriod); + nsecs_t deltaMaxLimit = deltas[numDeltas / 2] * kMultiplesThresholdDiv; + for (size_t i = numDeltas / 2 + 1; i < numDeltas; ++i) { + if (deltas[i] > deltaMaxLimit) { + deltas.resize(i); + numDeltas = i; + break; + } + } + for (size_t i = 1; i < numDeltas; ++i) { + nsecs_t delta2nd = deltas[i] - deltas[i - 1]; + if (delta2nd >= deltaMinLimit) { + //ALOGV("delta2: %lld", (long long)(delta2nd)); + deltas.push(delta2nd); + } + } + } + + // use the one that yields the best match + int64_t bestScore; + for (size_t i = 0; i < deltas.size(); ++i) { + nsecs_t delta = deltas[i]; + int64_t score = 0; +#if 1 + // simplest score: number of deltas that are near multiples + size_t matches = 0; + for (size_t j = 0; j < deltas.size(); ++j) { + nsecs_t err = periodicError(deltas[j], delta); + if (err < delta / kMultiplesThresholdDiv) { + ++matches; + } + } + score = matches; +#if 0 + // could be weighed by the (1 - normalized error) + if (numSamplesToUse >= kMinSamplesToEstimatePeriod) { + int64_t a, b, err; + fit(firstTime, delta, numSamplesToUse, &a, &b, &err); + err = (1 << (2 * kPrecision)) - err; + score *= max(0, err); + } +#endif +#else + // or use the error as a negative score + if (numSamplesToUse >= kMinSamplesToEstimatePeriod) { + int64_t a, b, err; + fit(firstTime, delta, numSamplesToUse, &a, &b, &err); + score = -delta * err; + } +#endif + if (i == 0 || score > bestScore) { + bestScore = score; + mPeriod = delta; + mPhase = firstTime; + } + } + ALOGV("priming[%zu] phase:%lld period:%lld", numSamplesToUse, mPhase, mPeriod); +} + +nsecs_t VideoFrameScheduler::PLL::addSample(nsecs_t time) { + if (mLastTime >= 0 + // if time goes backward, or we skipped rendering + && (time > mLastTime + kMaxAllowedFrameSkip || time < mLastTime)) { + restart(); + } + + mLastTime = time; + mTimes[mNumSamples % kHistorySize] = time; + ++mNumSamples; + + bool doFit = time > mRefitAt; + if ((mPeriod <= 0 || !mPrimed) && mNumSamples >= kMinSamplesToStartPrime) { + prime(kMinSamplesToStopPrime); + ++mSamplesUsedForPriming; + doFit = true; + } + if (mPeriod > 0 && mNumSamples >= kMinSamplesToEstimatePeriod) { + if (mPhase < 0) { + // initialize phase to the current render time + mPhase = time; + doFit = true; + } else if (!doFit) { + int64_t err = periodicError(time - mPhase, mPeriod); + doFit = err > mPeriod / kReFitThresholdDiv; + } + + if (doFit) { + int64_t a, b, err; + mRefitAt = time + kRefitRefreshPeriod; + fit(mPhase, mPeriod, kMaxSamplesToEstimatePeriod, &a, &b, &err); + mPhase += (mPeriod * b) >> kPrecision; + mPeriod = (mPeriod * a) >> kPrecision; + ALOGV("new phase:%lld period:%lld", (long long)mPhase, (long long)mPeriod); + + if (err < kErrorThreshold) { + if (!mPrimed && mSamplesUsedForPriming >= kMinSamplesToStopPrime) { + mPrimed = true; + } + } else { + mPrimed = false; + mSamplesUsedForPriming = 0; + } + } + } + return mPeriod; +} + /* ======================================================================= */ /* Frame Scheduler */ /* ======================================================================= */ @@ -44,7 +343,9 @@ static const nsecs_t kVsyncRefreshPeriod = kNanosIn1s; // 1 sec VideoFrameScheduler::VideoFrameScheduler() : mVsyncTime(0), mVsyncPeriod(0), - mVsyncRefreshAt(0) { + mVsyncRefreshAt(0), + mLastVsyncTime(-1), + mTimeCorrection(0) { } void VideoFrameScheduler::updateVsync() { @@ -75,8 +376,20 @@ void VideoFrameScheduler::updateVsync() { } } -void VideoFrameScheduler::init() { +void VideoFrameScheduler::init(float videoFps) { updateVsync(); + + mLastVsyncTime = -1; + mTimeCorrection = 0; + + mPll.reset(videoFps); +} + +void VideoFrameScheduler::restart() { + mLastVsyncTime = -1; + mTimeCorrection = 0; + + mPll.restart(); } nsecs_t VideoFrameScheduler::getVsyncPeriod() { @@ -110,6 +423,62 @@ nsecs_t VideoFrameScheduler::schedule(nsecs_t renderTime) { // so this effectively becomes a rounding operation (to the _closest_ VSYNC.) renderTime -= mVsyncPeriod / 2; + const nsecs_t videoPeriod = mPll.addSample(origRenderTime); + if (videoPeriod > 0) { + // Smooth out rendering + size_t N = 12; + nsecs_t fiveSixthDev = + abs(((videoPeriod * 5 + mVsyncPeriod) % (mVsyncPeriod * 6)) - mVsyncPeriod) + / (mVsyncPeriod / 100); + // use 20 samples if we are doing 5:6 ratio +- 1% (e.g. playing 50Hz on 60Hz) + if (fiveSixthDev < 12) { /* 12% / 6 = 2% */ + N = 20; + } + + nsecs_t offset = 0; + nsecs_t edgeRemainder = 0; + for (size_t i = 1; i <= N; i++) { + offset += + (renderTime + mTimeCorrection + videoPeriod * i - mVsyncTime) % mVsyncPeriod; + edgeRemainder += (videoPeriod * i) % mVsyncPeriod; + } + mTimeCorrection += mVsyncPeriod / 2 - offset / N; + renderTime += mTimeCorrection; + nsecs_t correctionLimit = mVsyncPeriod * 3 / 5; + edgeRemainder = abs(edgeRemainder / N - mVsyncPeriod / 2); + if (edgeRemainder <= mVsyncPeriod / 3) { + correctionLimit /= 2; + } + + // estimate how many VSYNCs a frame will spend on the display + nsecs_t nextVsyncTime = + renderTime + mVsyncPeriod - ((renderTime - mVsyncTime) % mVsyncPeriod); + if (mLastVsyncTime >= 0) { + size_t minVsyncsPerFrame = videoPeriod / mVsyncPeriod; + size_t vsyncsForLastFrame = divRound(nextVsyncTime - mLastVsyncTime, mVsyncPeriod); + bool vsyncsPerFrameAreNearlyConstant = + periodicError(videoPeriod, mVsyncPeriod) / (mVsyncPeriod / 20) == 0; + + if (mTimeCorrection > correctionLimit && + (vsyncsPerFrameAreNearlyConstant || vsyncsForLastFrame > minVsyncsPerFrame)) { + // remove a VSYNC + mTimeCorrection -= mVsyncPeriod / 2; + renderTime -= mVsyncPeriod / 2; + nextVsyncTime -= mVsyncPeriod; + --vsyncsForLastFrame; + } else if (mTimeCorrection < -correctionLimit && + (vsyncsPerFrameAreNearlyConstant || vsyncsForLastFrame == minVsyncsPerFrame)) { + // add a VSYNC + mTimeCorrection += mVsyncPeriod / 2; + renderTime += mVsyncPeriod / 2; + nextVsyncTime += mVsyncPeriod; + ++vsyncsForLastFrame; + } + ATRACE_INT("FRAME_VSYNCS", vsyncsForLastFrame); + } + mLastVsyncTime = nextVsyncTime; + } + // align rendertime to the center between VSYNC edges renderTime -= (renderTime - mVsyncTime) % mVsyncPeriod; renderTime += mVsyncPeriod / 2; diff --git a/media/libmediaplayerservice/VideoFrameScheduler.h b/media/libmediaplayerservice/VideoFrameScheduler.h index 9119e45..19f0787 100644 --- a/media/libmediaplayerservice/VideoFrameScheduler.h +++ b/media/libmediaplayerservice/VideoFrameScheduler.h @@ -30,7 +30,9 @@ struct VideoFrameScheduler : public RefBase { VideoFrameScheduler(); // (re)initialize scheduler - void init(); + void init(float videoFps = -1); + // use in case of video render-time discontinuity, e.g. seek + void restart(); // get adjusted nanotime for a video frame render at renderTime nsecs_t schedule(nsecs_t renderTime); @@ -39,16 +41,52 @@ struct VideoFrameScheduler : public RefBase { void release(); + static const size_t kHistorySize = 8; + protected: virtual ~VideoFrameScheduler(); private: + struct PLL { + PLL(); + + // reset PLL to new PLL + void reset(float fps = -1); + // keep current estimate, but restart phase + void restart(); + // returns period + nsecs_t addSample(nsecs_t time); + + private: + nsecs_t mPeriod; + nsecs_t mPhase; + + bool mPrimed; // have an estimate for the period + size_t mSamplesUsedForPriming; + + nsecs_t mLastTime; // last input time + nsecs_t mRefitAt; // next input time to fit at + + size_t mNumSamples; // can go past kHistorySize + nsecs_t mTimes[kHistorySize]; + + void test(); + void fit(nsecs_t phase, nsecs_t period, size_t numSamples, + int64_t *a, int64_t *b, int64_t *err); + void prime(size_t numSamples); + }; + void updateVsync(); nsecs_t mVsyncTime; // vsync timing from display nsecs_t mVsyncPeriod; nsecs_t mVsyncRefreshAt; // next time to refresh timing info + nsecs_t mLastVsyncTime; // estimated vsync time for last frame + nsecs_t mTimeCorrection; // running adjustment + + PLL mPll; // PLL for video frame rate based on render time + sp mComposer; DISALLOW_EVIL_CONSTRUCTORS(VideoFrameScheduler); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index cdbea9f..dad480d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -643,6 +643,13 @@ void NuPlayer::onMessageReceived(const sp &msg) { mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO); mRendererLooper->registerHandler(mRenderer); + sp meta = getFileMeta(); + int32_t rate; + if (meta != NULL + && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) { + mRenderer->setVideoFrameRate(rate); + } + postScanSources(); break; } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 9934e06..a8c8818 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -139,6 +139,12 @@ void NuPlayer::Renderer::resume() { (new AMessage(kWhatResume, id()))->post(); } +void NuPlayer::Renderer::setVideoFrameRate(float fps) { + sp msg = new AMessage(kWhatSetVideoFrameRate, id()); + msg->setFloat("frame-rate", fps); + msg->post(); +} + void NuPlayer::Renderer::onMessageReceived(const sp &msg) { switch (msg->what()) { case kWhatStopAudioSink: @@ -239,6 +245,14 @@ void NuPlayer::Renderer::onMessageReceived(const sp &msg) { break; } + case kWhatSetVideoFrameRate: + { + float fps; + CHECK(msg->findFloat("frame-rate", &fps)); + onSetVideoFrameRate(fps); + break; + } + case kWhatAudioOffloadTearDown: { onAudioOffloadTearDown(); @@ -809,6 +823,10 @@ void NuPlayer::Renderer::onFlush(const sp &msg) { mDrainVideoQueuePending = false; ++mVideoQueueGeneration; + if (mVideoScheduler != NULL) { + mVideoScheduler->restart(); + } + prepareForMediaRenderingStart(); } @@ -960,6 +978,13 @@ void NuPlayer::Renderer::onResume() { } } +void NuPlayer::Renderer::onSetVideoFrameRate(float fps) { + if (mVideoScheduler == NULL) { + mVideoScheduler = new VideoFrameScheduler(); + } + mVideoScheduler->init(fps); +} + // TODO: Remove unnecessary calls to getPlayedOutAudioDurationUs() // as it acquires locks and may query the audio driver. // diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index c5a6ec0..e28071f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -57,6 +57,8 @@ struct NuPlayer::Renderer : public AHandler { void pause(); void resume(); + void setVideoFrameRate(float fps); + enum { kWhatEOS = 'eos ', kWhatFlushComplete = 'fluC', @@ -83,6 +85,7 @@ private: kWhatResume = 'resm', kWhatStopAudioSink = 'stpA', kWhatDisableOffloadAudio = 'noOA', + kWhatSetVideoFrameRate = 'sVFR', }; struct QueueEntry { @@ -149,6 +152,7 @@ private: void onDisableOffloadAudio(); void onPause(); void onResume(); + void onSetVideoFrameRate(float fps); void onAudioOffloadTearDown(); void notifyEOS(bool audio, status_t finalResult, int64_t delayUs = 0); -- cgit v1.1 From 96e92b58b7e9647b4c7c2f54b62a1b357ab06b66 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Thu, 18 Sep 2014 17:36:20 -0700 Subject: MediaBuffer: ABuffer will release MediaBuffer when it's destructed. Bug: 17454455 Change-Id: Ia423bcc2e1fa39137f114eac44912ed15357bb99 --- .../nuplayer/GenericSource.cpp | 2 +- .../nuplayer/NuPlayerDecoder.cpp | 21 ++-------- media/libstagefright/ACodec.cpp | 23 +++------- media/libstagefright/MediaCodecSource.cpp | 19 ++------- media/libstagefright/foundation/ABuffer.cpp | 23 +++++++++- .../libstagefright/mpeg2ts/AnotherPacketSource.cpp | 5 --- .../wifi-display/source/Converter.cpp | 49 ++++++---------------- .../wifi-display/source/MediaPuller.cpp | 2 +- 8 files changed, 48 insertions(+), 96 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 511871d..a0870fd 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -1097,8 +1097,8 @@ sp NuPlayer::GenericSource::mediaBufferToABuffer( if (mIsWidevine && !audio) { // data is already provided in the buffer ab = new ABuffer(NULL, mb->range_length()); - ab->meta()->setPointer("mediaBuffer", mb); mb->add_ref(); + ab->setMediaBufferBase(mb); } else { ab = new ABuffer(outLength); memcpy(ab->data(), diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 87f85e7..601cd40 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -283,14 +283,9 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { // handle widevine classic source - that fills an arbitrary input buffer MediaBuffer *mediaBuffer = NULL; - if (hasBuffer && buffer->meta()->findPointer( - "mediaBuffer", (void **)&mediaBuffer)) { - if (mediaBuffer == NULL) { - // received no actual buffer - ALOGW("[%s] received null MediaBuffer %s", - mComponentName.c_str(), msg->debugString().c_str()); - buffer = NULL; - } else { + if (hasBuffer) { + mediaBuffer = (MediaBuffer *)(buffer->getMediaBufferBase()); + if (mediaBuffer != NULL) { // likely filled another buffer than we requested: adjust buffer index size_t ix; for (ix = 0; ix < mInputBuffers.size(); ix++) { @@ -598,16 +593,6 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { { if (!isStaleReply(msg)) { onInputBufferFilled(msg); - } else { - /* release any MediaBuffer passed in the stale buffer */ - sp buffer; - MediaBuffer *mediaBuffer = NULL; - if (msg->findBuffer("buffer", &buffer) && - buffer->meta()->findPointer( - "mediaBuffer", (void **)&mediaBuffer) && - mediaBuffer != NULL) { - mediaBuffer->release(); - } } break; diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 9b03b71..3c04859 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -3782,23 +3782,12 @@ bool ACodec::BaseState::onOMXEmptyBufferDone(IOMX::buffer_id bufferID) { CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_COMPONENT); info->mStatus = BufferInfo::OWNED_BY_US; - const sp &bufferMeta = info->mData->meta(); - void *mediaBuffer; - if (bufferMeta->findPointer("mediaBuffer", &mediaBuffer) - && mediaBuffer != NULL) { - // We're in "store-metadata-in-buffers" mode, the underlying - // OMX component had access to data that's implicitly refcounted - // by this "mediaBuffer" object. Now that the OMX component has - // told us that it's done with the input buffer, we can decrement - // the mediaBuffer's reference count. - - ALOGV("releasing mbuf %p", mediaBuffer); - - ((MediaBuffer *)mediaBuffer)->release(); - mediaBuffer = NULL; - - bufferMeta->setPointer("mediaBuffer", NULL); - } + // We're in "store-metadata-in-buffers" mode, the underlying + // OMX component had access to data that's implicitly refcounted + // by this "MediaBuffer" object. Now that the OMX component has + // told us that it's done with the input buffer, we can decrement + // the mediaBuffer's reference count. + info->mData->setMediaBufferBase(NULL); PortMode mode = getPortMode(kPortIndexInput); diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index 1a80dcc..27cd231 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -37,19 +37,6 @@ namespace android { -static void ReleaseMediaBufferReference(const sp &accessUnit) { - void *mbuf; - if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf) - && mbuf != NULL) { - ALOGV("releasing mbuf %p", mbuf); - - accessUnit->meta()->setPointer("mediaBuffer", NULL); - - static_cast(mbuf)->release(); - mbuf = NULL; - } -} - struct MediaCodecSource::Puller : public AHandler { Puller(const sp &source); @@ -477,7 +464,7 @@ void MediaCodecSource::releaseEncoder() { for (size_t i = 0; i < mEncoderInputBuffers.size(); ++i) { sp accessUnit = mEncoderInputBuffers.itemAt(i); - ReleaseMediaBufferReference(accessUnit); + accessUnit->setMediaBufferBase(NULL); } mEncoderInputBuffers.clear(); @@ -608,8 +595,8 @@ status_t MediaCodecSource::feedEncoderInputBuffers() { if (mIsVideo) { // video encoder will release MediaBuffer when done // with underlying data. - mEncoderInputBuffers.itemAt(bufferIndex)->meta() - ->setPointer("mediaBuffer", mbuf); + mEncoderInputBuffers.itemAt(bufferIndex)->setMediaBufferBase( + mbuf); } else { mbuf->release(); } diff --git a/media/libstagefright/foundation/ABuffer.cpp b/media/libstagefright/foundation/ABuffer.cpp index c93c7e8..b214870 100644 --- a/media/libstagefright/foundation/ABuffer.cpp +++ b/media/libstagefright/foundation/ABuffer.cpp @@ -19,11 +19,13 @@ #include "ADebug.h" #include "ALooper.h" #include "AMessage.h" +#include "MediaBufferBase.h" namespace android { ABuffer::ABuffer(size_t capacity) - : mData(malloc(capacity)), + : mMediaBufferBase(NULL), + mData(malloc(capacity)), mCapacity(capacity), mRangeOffset(0), mRangeLength(capacity), @@ -32,7 +34,8 @@ ABuffer::ABuffer(size_t capacity) } ABuffer::ABuffer(void *data, size_t capacity) - : mData(data), + : mMediaBufferBase(NULL), + mData(data), mCapacity(capacity), mRangeOffset(0), mRangeLength(capacity), @@ -59,6 +62,8 @@ ABuffer::~ABuffer() { if (mFarewell != NULL) { mFarewell->post(); } + + setMediaBufferBase(NULL); } void ABuffer::setRange(size_t offset, size_t size) { @@ -80,5 +85,19 @@ sp ABuffer::meta() { return mMeta; } +MediaBufferBase *ABuffer::getMediaBufferBase() { + if (mMediaBufferBase != NULL) { + mMediaBufferBase->add_ref(); + } + return mMediaBufferBase; +} + +void ABuffer::setMediaBufferBase(MediaBufferBase *mediaBuffer) { + if (mMediaBufferBase != NULL) { + mMediaBufferBase->release(); + } + mMediaBufferBase = mediaBuffer; +} + } // namespace android diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index c74c3e7..a03f6f9 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -254,11 +254,6 @@ void AnotherPacketSource::queueDiscontinuity( int32_t oldDiscontinuityType; if (!oldBuffer->meta()->findInt32( "discontinuity", &oldDiscontinuityType)) { - MediaBuffer *mbuf = NULL; - oldBuffer->meta()->findPointer("mediaBuffer", (void**)&mbuf); - if (mbuf != NULL) { - mbuf->release(); - } it = mBuffers.erase(it); continue; } diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp index 753b3ec..2834a66 100644 --- a/media/libstagefright/wifi-display/source/Converter.cpp +++ b/media/libstagefright/wifi-display/source/Converter.cpp @@ -74,19 +74,6 @@ Converter::Converter( } } -static void ReleaseMediaBufferReference(const sp &accessUnit) { - void *mbuf; - if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf) - && mbuf != NULL) { - ALOGV("releasing mbuf %p", mbuf); - - accessUnit->meta()->setPointer("mediaBuffer", NULL); - - static_cast(mbuf)->release(); - mbuf = NULL; - } -} - void Converter::releaseEncoder() { if (mEncoder == NULL) { return; @@ -95,18 +82,7 @@ void Converter::releaseEncoder() { mEncoder->release(); mEncoder.clear(); - while (!mInputBufferQueue.empty()) { - sp accessUnit = *mInputBufferQueue.begin(); - mInputBufferQueue.erase(mInputBufferQueue.begin()); - - ReleaseMediaBufferReference(accessUnit); - } - - for (size_t i = 0; i < mEncoderInputBuffers.size(); ++i) { - sp accessUnit = mEncoderInputBuffers.itemAt(i); - ReleaseMediaBufferReference(accessUnit); - } - + mInputBufferQueue.clear(); mEncoderInputBuffers.clear(); mEncoderOutputBuffers.clear(); } @@ -328,7 +304,7 @@ void Converter::onMessageReceived(const sp &msg) { sp accessUnit; CHECK(msg->findBuffer("accessUnit", &accessUnit)); - ReleaseMediaBufferReference(accessUnit); + accessUnit->setMediaBufferBase(NULL); } break; } @@ -351,15 +327,16 @@ void Converter::onMessageReceived(const sp &msg) { ALOGI("dropping frame."); } - ReleaseMediaBufferReference(accessUnit); + accessUnit->setMediaBufferBase(NULL); break; } #if 0 - void *mbuf; - if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf) - && mbuf != NULL) { + MediaBuffer *mbuf = + (MediaBuffer *)(accessUnit->getMediaBufferBase()); + if (mbuf != NULL) { ALOGI("queueing mbuf %p", mbuf); + mbuf->release(); } #endif @@ -647,13 +624,13 @@ status_t Converter::feedEncoderInputBuffers() { buffer->data(), buffer->size()); - void *mediaBuffer; - if (buffer->meta()->findPointer("mediaBuffer", &mediaBuffer) - && mediaBuffer != NULL) { - mEncoderInputBuffers.itemAt(bufferIndex)->meta() - ->setPointer("mediaBuffer", mediaBuffer); + MediaBuffer *mediaBuffer = + (MediaBuffer *)(buffer->getMediaBufferBase()); + if (mediaBuffer != NULL) { + mEncoderInputBuffers.itemAt(bufferIndex)->setMediaBufferBase( + mediaBuffer); - buffer->meta()->setPointer("mediaBuffer", NULL); + buffer->setMediaBufferBase(NULL); } } else { flags = MediaCodec::BUFFER_FLAG_EOS; diff --git a/media/libstagefright/wifi-display/source/MediaPuller.cpp b/media/libstagefright/wifi-display/source/MediaPuller.cpp index 7e8891d..86b918f 100644 --- a/media/libstagefright/wifi-display/source/MediaPuller.cpp +++ b/media/libstagefright/wifi-display/source/MediaPuller.cpp @@ -179,7 +179,7 @@ void MediaPuller::onMessageReceived(const sp &msg) { } else { // video encoder will release MediaBuffer when done // with underlying data. - accessUnit->meta()->setPointer("mediaBuffer", mbuf); + accessUnit->setMediaBufferBase(mbuf); } sp notify = mNotify->dup(); -- cgit v1.1 From 57568df014f8629ebc5ca8bce9da796dd187401b Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Mon, 22 Sep 2014 10:16:29 -0700 Subject: NuPlayer: use generation to filter out stale message from renderer. Clean up generation number for decoders. Bug: 17507846 Change-Id: Ibd2cfe11f89f404882d66c384b5198dc641f5e71 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 26 +++++++++++++++++------ media/libmediaplayerservice/nuplayer/NuPlayer.h | 1 + 2 files changed, 20 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index dad480d..b589909 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -155,6 +155,7 @@ NuPlayer::NuPlayer() mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER), mAudioDecoderGeneration(0), mVideoDecoderGeneration(0), + mRendererGeneration(0), mAudioEOS(false), mVideoEOS(false), mScanSourcesPending(false), @@ -633,10 +634,10 @@ void NuPlayer::onMessageReceived(const sp &msg) { flags |= Renderer::FLAG_OFFLOAD_AUDIO; } - mRenderer = new Renderer( - mAudioSink, - new AMessage(kWhatRendererNotify, id()), - flags); + sp notify = new AMessage(kWhatRendererNotify, id()); + ++mRendererGeneration; + notify->setInt32("generation", mRendererGeneration); + mRenderer = new Renderer(mAudioSink, notify, flags); mRendererLooper = new ALooper; mRendererLooper->setName("NuPlayerRenderer"); @@ -813,11 +814,13 @@ void NuPlayer::onMessageReceived(const sp &msg) { ALOGV("%s shutdown completed", audio ? "audio" : "video"); if (audio) { mAudioDecoder.clear(); + ++mAudioDecoderGeneration; CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER); mFlushingAudio = SHUT_DOWN; } else { mVideoDecoder.clear(); + ++mVideoDecoderGeneration; CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER); mFlushingVideo = SHUT_DOWN; @@ -835,9 +838,11 @@ void NuPlayer::onMessageReceived(const sp &msg) { mRenderer->queueEOS(audio, err); if (audio && mFlushingAudio != NONE) { mAudioDecoder.clear(); + ++mAudioDecoderGeneration; mFlushingAudio = SHUT_DOWN; } else if (!audio && mFlushingVideo != NONE){ mVideoDecoder.clear(); + ++mVideoDecoderGeneration; mFlushingVideo = SHUT_DOWN; } finishFlushIfPossible(); @@ -857,6 +862,14 @@ void NuPlayer::onMessageReceived(const sp &msg) { case kWhatRendererNotify: { + int32_t requesterGeneration = mRendererGeneration - 1; + CHECK(msg->findInt32("generation", &requesterGeneration)); + if (requesterGeneration != mRendererGeneration) { + ALOGV("got message from old renderer, generation(%d:%d)", + requesterGeneration, mRendererGeneration); + return; + } + int32_t what; CHECK(msg->findInt32("what", &what)); @@ -919,6 +932,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { CHECK(msg->findInt64("positionUs", &positionUs)); closeAudioSink(); mAudioDecoder.clear(); + ++mAudioDecoderGeneration; mRenderer->flush(true /* audio */); if (mVideoDecoder != NULL) { mRenderer->flush(false /* audio */); @@ -1849,9 +1863,6 @@ void NuPlayer::performReset() { ++mScanSourcesGeneration; mScanSourcesPending = false; - ++mAudioDecoderGeneration; - ++mVideoDecoderGeneration; - if (mRendererLooper != NULL) { if (mRenderer != NULL) { mRendererLooper->unregisterHandler(mRenderer->id()); @@ -1860,6 +1871,7 @@ void NuPlayer::performReset() { mRendererLooper.clear(); } mRenderer.clear(); + ++mRendererGeneration; if (mSource != NULL) { mSource->stop(); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 7197e5f..eee96ca 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -137,6 +137,7 @@ private: sp mRendererLooper; int32_t mAudioDecoderGeneration; int32_t mVideoDecoderGeneration; + int32_t mRendererGeneration; List > mDeferredActions; -- cgit v1.1 From dc9f58dc23a86d0635fd8601d1cbc8d47bab0303 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Thu, 18 Sep 2014 14:45:57 -0700 Subject: MediaCodec: Fix deallocated pointer reference when calling reset() The name pointer argument in MediaCodec::init() was being implicitly deallocated. Bug: 17499622 Change-Id: If9409f95674e52d1478f969f77693c4d27ff1ff2 --- media/libstagefright/MediaCodec.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 0bfc6e4..6c98c52 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -179,7 +179,7 @@ void MediaCodec::PostReplyWithError(int32_t replyID, int32_t err) { response->postReply(replyID); } -status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) { +status_t MediaCodec::init(const AString &name, bool nameIsType, bool encoder) { // save init parameters for reset mInitName = name; mInitNameIsType = nameIsType; @@ -191,7 +191,7 @@ status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) { // queue. mCodec = new ACodec; bool needDedicatedLooper = false; - if (nameIsType && !strncasecmp(name, "video/", 6)) { + if (nameIsType && !strncasecmp(name.c_str(), "video/", 6)) { needDedicatedLooper = true; } else { AString tmp = name; @@ -357,7 +357,7 @@ status_t MediaCodec::reset() { mHaveInputSurface = false; if (err == OK) { - err = init(mInitName.c_str(), mInitNameIsType, mInitIsEncoder); + err = init(mInitName, mInitNameIsType, mInitIsEncoder); } return err; } -- cgit v1.1 From f5b1db11734358d979a23a1ac4903872186ef60b Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Tue, 9 Sep 2014 10:11:08 -0700 Subject: NuPlayer: add pause timeout event for offload audio. Bug: 17375249 Change-Id: Ie59c6b372e9ad2aace3d1e27b9896d79de35d722 --- .../nuplayer/NuPlayerRenderer.cpp | 40 +++++++++++++++++++++- .../nuplayer/NuPlayerRenderer.h | 7 ++++ 2 files changed, 46 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 7674616..4ffcea6 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -30,6 +30,10 @@ namespace android { +// Maximum time in paused state when offloading audio decompression. When elapsed, the AudioSink +// is closed to allow the audio DSP to power down. +static const int64_t kOffloadPauseMaxUs = 60000000ll; + // static const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll; @@ -59,7 +63,9 @@ NuPlayer::Renderer::Renderer( mVideoRenderingStartGeneration(0), mAudioRenderingStartGeneration(0), mLastPositionUpdateUs(-1ll), - mVideoLateByUs(0ll) { + mVideoLateByUs(0ll), + mAudioOffloadPauseTimeoutGeneration(0), + mAudioOffloadTornDown(false) { } NuPlayer::Renderer::~Renderer() { @@ -243,6 +249,17 @@ void NuPlayer::Renderer::onMessageReceived(const sp &msg) { break; } + case kWhatAudioOffloadPauseTimeout: + { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + if (generation != mAudioOffloadPauseTimeoutGeneration) { + break; + } + onAudioOffloadTearDown(); + break; + } + default: TRESPASS(); break; @@ -919,6 +936,7 @@ void NuPlayer::Renderer::onPause() { if (mHasAudio) { mAudioSink->pause(); + startAudioOffloadPauseTimeout(); } ALOGV("now paused audio queue has %d entries, video has %d entries", @@ -931,6 +949,7 @@ void NuPlayer::Renderer::onResume() { } if (mHasAudio) { + cancelAudioOffloadPauseTimeout(); mAudioSink->start(); } @@ -1012,6 +1031,11 @@ int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) { } void NuPlayer::Renderer::onAudioOffloadTearDown() { + if (mAudioOffloadTornDown) { + return; + } + mAudioOffloadTornDown = true; + int64_t firstAudioTimeUs; { Mutex::Autolock autoLock(mLock); @@ -1030,5 +1054,19 @@ void NuPlayer::Renderer::onAudioOffloadTearDown() { notify->post(); } +void NuPlayer::Renderer::startAudioOffloadPauseTimeout() { + if (offloadingAudio()) { + sp msg = new AMessage(kWhatAudioOffloadPauseTimeout, id()); + msg->setInt32("generation", mAudioOffloadPauseTimeoutGeneration); + msg->post(kOffloadPauseMaxUs); + } +} + +void NuPlayer::Renderer::cancelAudioOffloadPauseTimeout() { + if (offloadingAudio()) { + ++mAudioOffloadPauseTimeoutGeneration; + } +} + } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 97fdae7..aba3c81 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -63,6 +63,7 @@ struct NuPlayer::Renderer : public AHandler { kWhatVideoRenderingStart = 'vdrd', kWhatMediaRenderingStart = 'mdrd', kWhatAudioOffloadTearDown = 'aOTD', + kWhatAudioOffloadPauseTimeout = 'aOPT', }; protected: @@ -127,6 +128,9 @@ private: int64_t mLastPositionUpdateUs; int64_t mVideoLateByUs; + int32_t mAudioOffloadPauseTimeoutGeneration; + bool mAudioOffloadTornDown; + size_t fillAudioBuffer(void *buffer, size_t size); bool onDrainAudioQueue(); @@ -162,6 +166,9 @@ private: bool offloadingAudio() const { return (mFlags & FLAG_OFFLOAD_AUDIO) != 0; } + void startAudioOffloadPauseTimeout(); + void cancelAudioOffloadPauseTimeout(); + DISALLOW_EVIL_CONSTRUCTORS(Renderer); }; -- cgit v1.1 From 217bde880be6f4d937caf9555ea98942883ebda0 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Mon, 22 Sep 2014 12:25:36 -0700 Subject: fix crash when makeHTTPConnection fails with null pointer Bug: 17608108 Change-Id: I4bdf6d09ae565418be3d6677b5ccac9072fb9b2c --- media/libstagefright/DataSource.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 9d6fd78..a72cbd5 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -199,7 +199,18 @@ sp DataSource::CreateFromURI( } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8) || isWidevine) { - sp httpSource = new MediaHTTP(httpService->makeHTTPConnection()); + if (httpService == NULL) { + ALOGE("Invalid http service!"); + return NULL; + } + + sp conn = httpService->makeHTTPConnection(); + if (conn == NULL) { + ALOGE("Failed to make http connection from http service!"); + return NULL; + } + + sp httpSource = new MediaHTTP(conn); String8 tmp; if (isWidevine) { -- cgit v1.1 From 820c4893fdec784321826fd903da34fe3d609b93 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Mon, 22 Sep 2014 16:52:49 -0700 Subject: MyHandler: set ip address to an invalid one when getsockname() returns error. Bug: 17556472 Change-Id: I0387c78727d9a18abddcfdb4b480f4b1412bbc9f --- media/libstagefright/rtsp/MyHandler.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index f3dfc59..423a420 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -254,7 +254,9 @@ struct MyHandler : public AHandler { static void addSDES(int s, const sp &buffer) { struct sockaddr_in addr; socklen_t addrSize = sizeof(addr); - CHECK_EQ(0, getsockname(s, (sockaddr *)&addr, &addrSize)); + if (getsockname(s, (sockaddr *)&addr, &addrSize) != 0) { + inet_aton("0.0.0.0", &(addr.sin_addr)); + } uint8_t *data = buffer->data() + buffer->size(); data[0] = 0x80 | 1; -- cgit v1.1 From e427abf1ea252ff305fc33aacdd2e83cf34891b5 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Mon, 22 Sep 2014 15:21:11 -0700 Subject: NuPlayer will notify SeekComplete only when requested so. Bug: 17596535 Change-Id: I6b744fdcf80f11d521d26c7c8b45f7de70aa0dc3 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 35 ++++++++++++++-------- media/libmediaplayerservice/nuplayer/NuPlayer.h | 7 +++-- .../nuplayer/NuPlayerDriver.cpp | 6 ++-- 3 files changed, 29 insertions(+), 19 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index dad480d..d2caf65 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -64,16 +64,18 @@ private: }; struct NuPlayer::SeekAction : public Action { - SeekAction(int64_t seekTimeUs) - : mSeekTimeUs(seekTimeUs) { + SeekAction(int64_t seekTimeUs, bool needNotify) + : mSeekTimeUs(seekTimeUs), + mNeedNotify(needNotify) { } virtual void execute(NuPlayer *player) { - player->performSeek(mSeekTimeUs); + player->performSeek(mSeekTimeUs, mNeedNotify); } private: int64_t mSeekTimeUs; + bool mNeedNotify; DISALLOW_EVIL_CONSTRUCTORS(SeekAction); }; @@ -323,9 +325,10 @@ void NuPlayer::resetAsync() { (new AMessage(kWhatReset, id()))->post(); } -void NuPlayer::seekToAsync(int64_t seekTimeUs) { +void NuPlayer::seekToAsync(int64_t seekTimeUs, bool needNotify) { sp msg = new AMessage(kWhatSeek, id()); msg->setInt64("seekTimeUs", seekTimeUs); + msg->setInt32("needNotify", needNotify); msg->post(); } @@ -560,7 +563,8 @@ void NuPlayer::onMessageReceived(const sp &msg) { // the extractor may not yet be started and will assert. // If the video decoder is not set (perhaps audio only in this case) // do not perform a seek as it is not needed. - mDeferredActions.push_back(new SeekAction(mCurrentPositionUs)); + mDeferredActions.push_back( + new SeekAction(mCurrentPositionUs, false /* needNotify */)); } // If there is a new surface texture, instantiate decoders @@ -926,7 +930,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { mRenderer->signalDisableOffloadAudio(); mOffloadAudio = false; - performSeek(positionUs); + performSeek(positionUs, false /* needNotify */); instantiateDecoder(true /* audio */, &mAudioDecoder); } break; @@ -955,14 +959,18 @@ void NuPlayer::onMessageReceived(const sp &msg) { case kWhatSeek: { int64_t seekTimeUs; + int32_t needNotify; CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); + CHECK(msg->findInt32("needNotify", &needNotify)); - ALOGV("kWhatSeek seekTimeUs=%lld us", seekTimeUs); + ALOGV("kWhatSeek seekTimeUs=%lld us, needNotify=%d", + seekTimeUs, needNotify); mDeferredActions.push_back( new SimpleAction(&NuPlayer::performDecoderFlush)); - mDeferredActions.push_back(new SeekAction(seekTimeUs)); + mDeferredActions.push_back( + new SeekAction(seekTimeUs, needNotify)); processDeferredActions(); break; @@ -1774,10 +1782,11 @@ void NuPlayer::processDeferredActions() { } } -void NuPlayer::performSeek(int64_t seekTimeUs) { - ALOGV("performSeek seekTimeUs=%lld us (%.2f secs)", +void NuPlayer::performSeek(int64_t seekTimeUs, bool needNotify) { + ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), needNotify(%d)", seekTimeUs, - seekTimeUs / 1E6); + seekTimeUs / 1E6, + needNotify); if (mSource == NULL) { // This happens when reset occurs right before the loop mode @@ -1794,7 +1803,9 @@ void NuPlayer::performSeek(int64_t seekTimeUs) { sp driver = mDriver.promote(); if (driver != NULL) { driver->notifyPosition(seekTimeUs); - driver->notifySeekComplete(); + if (needNotify) { + driver->notifySeekComplete(); + } } } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 7197e5f..18cfe86 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -59,8 +59,9 @@ struct NuPlayer : public AHandler { // Will notify the driver through "notifyResetComplete" once finished. void resetAsync(); - // Will notify the driver through "notifySeekComplete" once finished. - void seekToAsync(int64_t seekTimeUs); + // Will notify the driver through "notifySeekComplete" once finished + // and needNotify is true. + void seekToAsync(int64_t seekTimeUs, bool needNotify = false); status_t setVideoScalingMode(int32_t mode); status_t getTrackInfo(Parcel* reply) const; @@ -214,7 +215,7 @@ private: void processDeferredActions(); - void performSeek(int64_t seekTimeUs); + void performSeek(int64_t seekTimeUs, bool needNotify); void performDecoderFlush(); void performDecoderShutdown(bool audio, bool video); void performReset(); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 7ec9876..a9bca49 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -240,9 +240,7 @@ status_t NuPlayerDriver::start() { mPlayer->start(); if (mStartupSeekTimeUs >= 0) { - if (mStartupSeekTimeUs == 0) { - notifySeekComplete_l(); - } else { + if (mStartupSeekTimeUs > 0) { mPlayer->seekToAsync(mStartupSeekTimeUs); } @@ -369,7 +367,7 @@ status_t NuPlayerDriver::seekTo(int msec) { mAtEOS = false; // seeks can take a while, so we essentially paused notifyListener_l(MEDIA_PAUSED); - mPlayer->seekToAsync(seekTimeUs); + mPlayer->seekToAsync(seekTimeUs, true /* needNotify */); break; } -- cgit v1.1 From 1aa26f787afc525e0deae31d856dce74a4b28a0f Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Fri, 12 Sep 2014 11:57:27 -0700 Subject: stagefright: add adaptive playback support to SoftHEVC decoder. Bug: 17326758 Change-Id: I245e2bd1490e810094ca550fdddfa87075bc2056 --- media/libstagefright/codecs/hevcdec/SoftHEVC.cpp | 189 +++++++++++++-------- media/libstagefright/codecs/hevcdec/SoftHEVC.h | 16 +- .../include/SoftVideoDecoderOMXComponent.h | 3 + .../omx/SoftVideoDecoderOMXComponent.cpp | 17 +- 4 files changed, 141 insertions(+), 84 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp index b0d0827..f4cba54 100644 --- a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp +++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp @@ -67,22 +67,16 @@ SoftHEVC::SoftHEVC( : SoftVideoDecoderOMXComponent(name, componentName, codingType, kProfileLevels, ARRAY_SIZE(kProfileLevels), 320 /* width */, 240 /* height */, callbacks, - appData, component) { + appData, component), + mMemRecords(NULL), + mFlushOutBuffer(NULL), + mOmxColorFormat(OMX_COLOR_FormatYUV420Planar), + mIvColorFormat(IV_YUV_420P), + mNewWidth(mWidth), + mNewHeight(mHeight), + mChangingResolution(false) { initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE); - - mOmxColorFormat = OMX_COLOR_FormatYUV420Planar; - mStride = mWidth; - - if (OMX_COLOR_FormatYUV420Planar == mOmxColorFormat) { - mIvColorFormat = IV_YUV_420P; - } else if (OMX_COLOR_FormatYUV420SemiPlanar == mOmxColorFormat) { - mIvColorFormat = IV_YUV_420SP_UV; - } - - mInitWidth = mWidth; - mInitHeight = mHeight; - CHECK_EQ(initDecoder(), (status_t)OK); } @@ -144,7 +138,7 @@ status_t SoftHEVC::setParams(size_t stride) { s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t); - ALOGD("Set the run-time (dynamic) parameters"); + ALOGV("Set the run-time (dynamic) parameters stride = %u", stride); status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op); @@ -188,7 +182,7 @@ status_t SoftHEVC::resetDecoder() { } /* Set the run-time (dynamic) parameters */ - setParams(0); + setParams(outputBufferWidth()); /* Set number of cores/threads to be used by the codec */ setNumCores(); @@ -250,23 +244,25 @@ status_t SoftHEVC::initDecoder() { WORD32 i4_level; mNumCores = GetCPUCoreCount(); - mMemRecords = NULL; - mFlushOutBuffer = NULL; /* Initialize number of ref and reorder modes (for HEVC) */ u4_num_reorder_frames = 16; u4_num_ref_frames = 16; u4_share_disp_buf = 0; - if ((mWidth * mHeight) > (1920 * 1088)) { + uint32_t displayStride = outputBufferWidth(); + uint32_t displayHeight = outputBufferHeight(); + uint32_t displaySizeY = displayStride * displayHeight; + + if (displaySizeY > (1920 * 1088)) { i4_level = 50; - } else if ((mWidth * mHeight) > (1280 * 720)) { + } else if (displaySizeY > (1280 * 720)) { i4_level = 40; - } else if ((mWidth * mHeight) > (960 * 540)) { + } else if (displaySizeY > (960 * 540)) { i4_level = 31; - } else if ((mWidth * mHeight) > (640 * 360)) { + } else if (displaySizeY > (640 * 360)) { i4_level = 30; - } else if ((mWidth * mHeight) > (352 * 288)) { + } else if (displaySizeY > (352 * 288)) { i4_level = 21; } else { i4_level = 20; @@ -317,8 +313,8 @@ status_t SoftHEVC::initDecoder() { s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC; s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords; - s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = mWidth; - s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = mHeight; + s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = displayStride; + s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = displayHeight; s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size = sizeof(ivdext_fill_mem_rec_op_t); @@ -363,8 +359,8 @@ status_t SoftHEVC::initDecoder() { s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t); s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT; s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords; - s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = mWidth; - s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight; + s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = displayStride; + s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = displayHeight; s_init_ip.i4_level = i4_level; s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames; @@ -395,7 +391,7 @@ status_t SoftHEVC::initDecoder() { resetPlugin(); /* Set the run time (dynamic) parameters */ - setParams(0); + setParams(displayStride); /* Set number of cores/threads to be used by the codec */ setNumCores(); @@ -404,12 +400,15 @@ status_t SoftHEVC::initDecoder() { logVersion(); /* Allocate internal picture buffer */ - mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, mStride * mHeight * 3 / 2); + uint32_t bufferSize = displaySizeY * 3 / 2; + mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize); if (NULL == mFlushOutBuffer) { - ALOGE("Could not allocate flushOutputBuffer of size %zu", mStride * mHeight * 3 / 2); + ALOGE("Could not allocate flushOutputBuffer of size %zu", bufferSize); return NO_MEMORY; } + mInitNeeded = false; + mFlushNeeded = false; return OK; } @@ -428,11 +427,17 @@ status_t SoftHEVC::deInitDecoder() { ps_mem_rec++; } ivd_aligned_free(mMemRecords); + mMemRecords = NULL; } if(mFlushOutBuffer) { ivd_aligned_free(mFlushOutBuffer); + mFlushOutBuffer = NULL; } + + mInitNeeded = true; + mChangingResolution = false; + return OK; } @@ -449,6 +454,7 @@ status_t SoftHEVC::reInitDecoder() { } return OK; } + void SoftHEVC::onReset() { ALOGD("onReset called"); SoftVideoDecoderOMXComponent::onReset(); @@ -457,12 +463,22 @@ void SoftHEVC::onReset() { resetPlugin(); } +OMX_ERRORTYPE SoftHEVC::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) { + const uint32_t oldWidth = mWidth; + const uint32_t oldHeight = mHeight; + OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params); + if (mWidth != oldWidth || mHeight != oldHeight) { + reInitDecoder(); + } + return ret; +} + void SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip, ivd_video_decode_op_t *ps_dec_op, OMX_BUFFERHEADERTYPE *inHeader, OMX_BUFFERHEADERTYPE *outHeader, - size_t sizeY, size_t timeStampIx) { + size_t sizeY = outputBufferWidth() * outputBufferHeight(); size_t sizeUV; uint8_t *pBuf; @@ -502,8 +518,6 @@ void SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip, return; } void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { - ALOGD("onPortFlushCompleted on port %d", portIndex); - /* Once the output buffers are flushed, ignore any buffers that are held in decoder */ if (kOutputPortIndex == portIndex) { setFlushMode(); @@ -514,7 +528,7 @@ void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { IV_API_CALL_STATUS_T status; size_t sizeY, sizeUV; - setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, mStride * mHeight, 0); + setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0); status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); @@ -527,8 +541,6 @@ void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { } void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { - IV_API_CALL_STATUS_T status; - UNUSED(portIndex); if (mOutputPortSettingsChange != NONE) { @@ -548,7 +560,7 @@ void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { setFlushMode(); } - while (outQueue.size() == kNumBuffers) { + while (!outQueue.empty()) { BufferInfo *inInfo; OMX_BUFFERHEADERTYPE *inHeader; @@ -586,6 +598,16 @@ void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { } } + // When there is an init required and the decoder is not in flush mode, + // update output port's definition and reinitialize decoder. + if (mInitNeeded && !mIsInFlush) { + bool portWillReset = false; + handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight); + + CHECK_EQ(reInitDecoder(), (status_t)OK); + return; + } + /* Get a free slot in timestamp array to hold input timestamp */ { size_t i; @@ -608,68 +630,91 @@ void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { WORD32 timeDelay, timeTaken; size_t sizeY, sizeUV; - setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, - mStride * mHeight, timeStampIx); + setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); GETTIME(&mTimeStart, NULL); /* Compute time elapsed between end of previous decode() * to start of current decode() */ TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); - status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, - (void *)&s_dec_op); + IV_API_CALL_STATUS_T status; + status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); + // FIXME: Compare |status| to IHEVCD_UNSUPPORTED_DIMENSIONS, which is not one of the + // IV_API_CALL_STATUS_T, seems be wrong. But this is what the decoder returns right now. + // The decoder should be fixed so that |u4_error_code| instead of |status| returns + // IHEVCD_UNSUPPORTED_DIMENSIONS. + bool unsupportedDimensions = + ((IHEVCD_UNSUPPORTED_DIMENSIONS == status) + || (IHEVCD_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code)); + bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF)); GETTIME(&mTimeEnd, NULL); /* Compute time taken for decode() */ TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); - ALOGD("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, - s_dec_op.u4_num_bytes_consumed); + ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, + s_dec_op.u4_num_bytes_consumed); + if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) { + mFlushNeeded = true; + } + + if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { + /* If the input did not contain picture data, then ignore + * the associated timestamp */ + mTimeStampsValid[timeStampIx] = false; + } - /* If width and height are greater than the - * the dimensions used during codec create, then - * delete the current instance and recreate an instance with - * new dimensions */ + // This is needed to handle CTS DecoderTest testCodecResetsHEVCWithoutSurface, + // which is not sending SPS/PPS after port reconfiguration and flush to the codec. + if (unsupportedDimensions && !mFlushNeeded) { + bool portWillReset = false; + handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht); - if(IHEVCD_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code) { - mInitWidth = s_dec_op.u4_pic_wd; - mInitHeight = s_dec_op.u4_pic_ht; - mStride = mInitWidth; CHECK_EQ(reInitDecoder(), (status_t)OK); - setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, - mStride * mHeight, timeStampIx); + setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); - status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, - (void *)&s_dec_op); + ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); + return; } - if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { - /* If the input did not contain picture data, then ignore - * the associated timestamp */ - mTimeStampsValid[timeStampIx] = false; + + // If the decoder is in the changing resolution mode and there is no output present, + // that means the switching is done and it's ready to reset the decoder and the plugin. + if (mChangingResolution && !s_dec_op.u4_output_present) { + mChangingResolution = false; + resetDecoder(); + resetPlugin(); + continue; + } + + if (unsupportedDimensions || resChanged) { + mChangingResolution = true; + if (mFlushNeeded) { + setFlushMode(); + } + + if (unsupportedDimensions) { + mNewWidth = s_dec_op.u4_pic_wd; + mNewHeight = s_dec_op.u4_pic_ht; + mInitNeeded = true; + } + continue; } - /* If valid height and width are decoded, - * then look at change in resolution */ if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { uint32_t width = s_dec_op.u4_pic_wd; uint32_t height = s_dec_op.u4_pic_ht; + bool portWillReset = false; + handlePortSettingsChange(&portWillReset, width, height); - if ((width != mWidth) || (height != mHeight)) { - mWidth = width; - mHeight = height; - mStride = mWidth; - - updatePortDefinitions(); - - notify(OMX_EventPortSettingsChanged, 1, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; + if (portWillReset) { + resetDecoder(); return; } } if (s_dec_op.u4_output_present) { - outHeader->nFilledLen = (mStride * mHeight * 3) / 2; + outHeader->nFilledLen = (mWidth * mHeight * 3) / 2; outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts]; mTimeStampsValid[s_dec_op.u4_ts] = false; @@ -711,7 +756,7 @@ void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { } } -} // namespace android +} // namespace android android::SoftOMXComponent *createSoftOMXComponent(const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.h b/media/libstagefright/codecs/hevcdec/SoftHEVC.h index 233db0c..a91f528 100644 --- a/media/libstagefright/codecs/hevcdec/SoftHEVC.h +++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.h @@ -62,6 +62,7 @@ protected: virtual void onQueueFilled(OMX_U32 portIndex); virtual void onPortFlushCompleted(OMX_U32 portIndex); virtual void onReset(); + virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params); private: // Number of input and output buffers enum { @@ -72,12 +73,6 @@ private: iv_mem_rec_t *mMemRecords; // Memory records requested by the codec size_t mNumMemRecords; // Number of memory records requested by the codec - uint32_t mNewWidth; // New width after change in resolution - uint32_t mNewHeight; // New height after change in resolution - uint32_t mInitWidth; // Width used during codec creation - uint32_t mInitHeight; // Height used during codec creation - size_t mStride; // Stride to be used for display buffers - size_t mNumCores; // Number of cores to be uesd by the codec struct timeval mTimeStart; // Time at the start of decode() @@ -98,7 +93,13 @@ private: bool mIsInFlush; // codec is flush mode bool mReceivedEOS; // EOS is receieved on input port - bool mIsAdapting; // plugin in middle of change in resolution + bool mInitNeeded; + uint32_t mNewWidth; + uint32_t mNewHeight; + // The input stream has changed to a different resolution, which is still supported by the + // codec. So the codec is switching to decode the new resolution. + bool mChangingResolution; + bool mFlushNeeded; status_t initDecoder(); status_t deInitDecoder(); @@ -114,7 +115,6 @@ private: ivd_video_decode_op_t *ps_dec_op, OMX_BUFFERHEADERTYPE *inHeader, OMX_BUFFERHEADERTYPE *outHeader, - size_t sizeY, size_t timeStampIx); DISALLOW_EVIL_CONSTRUCTORS (SoftHEVC); diff --git a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h index 8cb8ed7..37b1fe1 100644 --- a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h +++ b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h @@ -65,6 +65,9 @@ protected: virtual void updatePortDefinitions(bool updateCrop = true); + uint32_t outputBufferWidth(); + uint32_t outputBufferHeight(); + void handlePortSettingsChange( bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged = false, bool fakeStride = false); diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp index 1cb1859..5853469 100644 --- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp +++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp @@ -133,8 +133,8 @@ void SoftVideoDecoderOMXComponent::updatePortDefinitions(bool updateCrop) { def->nBufferSize = def->format.video.nFrameWidth * def->format.video.nFrameHeight * 3 / 2; def = &editPortInfo(kOutputPortIndex)->mDef; - def->format.video.nFrameWidth = mIsAdaptive ? mAdaptiveMaxWidth : mWidth; - def->format.video.nFrameHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight; + def->format.video.nFrameWidth = outputBufferWidth(); + def->format.video.nFrameHeight = outputBufferHeight(); def->format.video.nStride = def->format.video.nFrameWidth; def->format.video.nSliceHeight = def->format.video.nFrameHeight; @@ -150,6 +150,15 @@ void SoftVideoDecoderOMXComponent::updatePortDefinitions(bool updateCrop) { } } + +uint32_t SoftVideoDecoderOMXComponent::outputBufferWidth() { + return mIsAdaptive ? mAdaptiveMaxWidth : mWidth; +} + +uint32_t SoftVideoDecoderOMXComponent::outputBufferHeight() { + return mIsAdaptive ? mAdaptiveMaxHeight : mHeight; +} + void SoftVideoDecoderOMXComponent::handlePortSettingsChange( bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged, bool fakeStride) { *portWillReset = false; @@ -199,9 +208,9 @@ void SoftVideoDecoderOMXComponent::handlePortSettingsChange( void SoftVideoDecoderOMXComponent::copyYV12FrameToOutputBuffer( uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV, size_t srcYStride, size_t srcUStride, size_t srcVStride) { - size_t dstYStride = mIsAdaptive ? mAdaptiveMaxWidth : mWidth; + size_t dstYStride = outputBufferWidth(); size_t dstUVStride = dstYStride / 2; - size_t dstHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight; + size_t dstHeight = outputBufferHeight(); uint8_t *dstStart = dst; for (size_t i = 0; i < mHeight; ++i) { -- cgit v1.1 From 7e9f7f7a9fb6c5d93fc9163e32936f3ea284caad Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Tue, 23 Sep 2014 10:55:35 -0700 Subject: NuPlayer: change assert to conditional check. Bug: 17491050 Change-Id: I657866c5342c227d57617eb89955897171eb5976 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 26 +++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index b589909..2ea12ae 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -984,17 +984,31 @@ void NuPlayer::onMessageReceived(const sp &msg) { case kWhatPause: { - CHECK(mRenderer != NULL); - mSource->pause(); - mRenderer->pause(); + if (mSource != NULL) { + mSource->pause(); + } else { + ALOGW("pause called when source is gone or not set"); + } + if (mRenderer != NULL) { + mRenderer->pause(); + } else { + ALOGW("pause called when renderer is gone or not set"); + } break; } case kWhatResume: { - CHECK(mRenderer != NULL); - mSource->resume(); - mRenderer->resume(); + if (mSource != NULL) { + mSource->resume(); + } else { + ALOGW("resume called when source is gone or not set"); + } + if (mRenderer != NULL) { + mRenderer->resume(); + } else { + ALOGW("resume called when renderer is gone or not set"); + } break; } -- cgit v1.1 From 0837d0ac1b572923a27f1b0b742960fc64a6b162 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Tue, 23 Sep 2014 17:49:02 -0700 Subject: stagefright: return encrypted input buffer for secure codecs Bug: 17630446 Change-Id: I8a9352bcd00a3f4eb6fd2797d6809a8c1edc8482 --- media/libstagefright/MediaCodec.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 6c98c52..b56819c 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -589,7 +589,12 @@ status_t MediaCodec::getBufferAndFormat( if (index < buffers->size()) { const BufferInfo &info = buffers->itemAt(index); if (info.mOwnedByClient) { - *buffer = info.mData; + // by the time buffers array is initialized, crypto is set + if (portIndex == kPortIndexInput && mCrypto != NULL) { + *buffer = info.mEncryptedData; + } else { + *buffer = info.mData; + } *format = info.mFormat; } } -- cgit v1.1 From 9f3d1cffe3bbec35c1fb7fc7e206428728ac234e Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 23 Sep 2014 22:22:30 -0700 Subject: NuCachedSource2: more fixes for source read hang - Do not try to read from HTTP source if already disconnecting - Let NuCachedSource2::readAt() return immediately when disconnecting Bug: 17613805 Change-Id: Ibca4d3a4288ae9a9e2f5658a4240ace54efeb220 --- media/libstagefright/NuCachedSource2.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index be2a873..f469d4d 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -254,6 +254,10 @@ void NuCachedSource2::disconnect() { // set mDisconnecting to true, if a fetch returns after // this, the source will be marked as EOS. mDisconnecting = true; + + // explicitly signal mCondition so that the pending readAt() + // will immediately return + mCondition.signal(); } // explicitly disconnect from the source, to allow any @@ -325,7 +329,11 @@ void NuCachedSource2::fetchInternal() { Mutex::Autolock autoLock(mLock); - if (err == ERROR_UNSUPPORTED || err == -EPIPE) { + if (mDisconnecting) { + mNumRetriesLeft = 0; + mFinalStatus = ERROR_END_OF_STREAM; + return; + } else if (err == ERROR_UNSUPPORTED || err == -EPIPE) { // These are errors that are not likely to go away even if we // retry, i.e. the server doesn't support range requests or similar. mNumRetriesLeft = 0; @@ -515,10 +523,14 @@ ssize_t NuCachedSource2::readAt(off64_t offset, void *data, size_t size) { CHECK(mAsyncResult == NULL); msg->post(); - while (mAsyncResult == NULL) { + while (mAsyncResult == NULL && !mDisconnecting) { mCondition.wait(mLock); } + if (mDisconnecting) { + return ERROR_END_OF_STREAM; + } + int32_t result; CHECK(mAsyncResult->findInt32("result", &result)); -- cgit v1.1 From a28785aa9ce323494a6971a38ce1d4d29bf710e4 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Tue, 23 Sep 2014 22:24:26 -0700 Subject: Fix Widevine classic playback errors with NuPlayer bug: 17589961 Change-Id: If16c61b90cf92caa89eecd66aabef5813fd7619b --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index bd75034..f84decd 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -1198,10 +1198,17 @@ void NuPlayer::GenericSource::readBuffer( switch (trackType) { case MEDIA_TRACK_TYPE_VIDEO: track = &mVideoTrack; + if (mIsWidevine) { + maxBuffers = 2; + } break; case MEDIA_TRACK_TYPE_AUDIO: track = &mAudioTrack; - maxBuffers = 64; + if (mIsWidevine) { + maxBuffers = 8; + } else { + maxBuffers = 64; + } break; case MEDIA_TRACK_TYPE_SUBTITLE: track = &mSubtitleTrack; -- cgit v1.1 From b32ebac7e3afb49b41eeccf130c8a96c1dae85d1 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 24 Sep 2014 13:55:10 -0700 Subject: stagefright: use frame height if slice height is 0 This is a workaround for some vendors that set slice height to 0. Android uses slice height is the vertical stride for YUV planar and semiplanar formats. Bug: 13433554 Change-Id: I4da038e7a768dcd8360c33fa1a9ce95a172f16bb --- media/libstagefright/ACodec.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 3c04859..4589ed1 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -2933,13 +2933,6 @@ bool ACodec::describeDefaultColorFormat(DescribeColorFormatParams ¶ms) { image.mNumPlanes = 0; const OMX_COLOR_FORMATTYPE fmt = params.eColorFormat; - // we need stride and slice-height to be non-zero - if (params.nStride == 0 || params.nSliceHeight == 0) { - ALOGW("cannot describe color format 0x%x = %d with stride=%u and sliceHeight=%u", - fmt, fmt, params.nStride, params.nSliceHeight); - return false; - } - image.mWidth = params.nFrameWidth; image.mHeight = params.nFrameHeight; @@ -2952,6 +2945,20 @@ bool ACodec::describeDefaultColorFormat(DescribeColorFormatParams ¶ms) { return false; } + // TEMPORARY FIX for some vendors that advertise sliceHeight as 0 + if (params.nStride != 0 && params.nSliceHeight == 0) { + ALOGW("using sliceHeight=%u instead of what codec advertised (=0)", + params.nFrameHeight); + params.nSliceHeight = params.nFrameHeight; + } + + // we need stride and slice-height to be non-zero + if (params.nStride == 0 || params.nSliceHeight == 0) { + ALOGW("cannot describe color format 0x%x = %d with stride=%u and sliceHeight=%u", + fmt, fmt, params.nStride, params.nSliceHeight); + return false; + } + // set-up YUV format image.mType = MediaImage::MEDIA_IMAGE_TYPE_YUV; image.mNumPlanes = 3; -- cgit v1.1 From 4923cee4fb3b29538d8f46bceeea7d5128242a71 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 24 Sep 2014 14:25:19 -0700 Subject: NuPlayerDecoder: release MediaBuffers when decoder is deleted. Bug: 17454455 Change-Id: Ic984c74826f87f5f3c27756a7e7d52295a529bed --- media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index cdb860c..1b1b1c8 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -53,6 +53,10 @@ NuPlayer::Decoder::Decoder( } NuPlayer::Decoder::~Decoder() { + mDecoderLooper->unregisterHandler(id()); + mDecoderLooper->stop(); + + releaseAndResetMediaBuffers(); } static -- cgit v1.1 From 42a9fd4f382253a2fb7fe6761273841c999606af Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Mon, 22 Sep 2014 13:26:13 -0700 Subject: SoftVideoDecoderOMXComponent: re-config the buffer size when port definition changed. Bug: 17326758 Change-Id: I7c6b85284ae0cbfa54f999851f56db84345b65bf --- .../omx/SoftVideoDecoderOMXComponent.cpp | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'media') diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp index 5853469..b5d19bc 100644 --- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp +++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp @@ -343,6 +343,40 @@ OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalSetParameter( return OMX_ErrorNone; } + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *newParams = + (OMX_PARAM_PORTDEFINITIONTYPE *)params; + OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &newParams->format.video; + OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(newParams->nPortIndex)->mDef; + + uint32_t oldWidth = def->format.video.nFrameWidth; + uint32_t oldHeight = def->format.video.nFrameHeight; + uint32_t newWidth = video_def->nFrameWidth; + uint32_t newHeight = video_def->nFrameHeight; + if (newWidth != oldWidth || newHeight != oldHeight) { + bool outputPort = (newParams->nPortIndex == kOutputPortIndex); + def->format.video.nFrameWidth = + (mIsAdaptive && outputPort) ? mAdaptiveMaxWidth : newWidth; + def->format.video.nFrameHeight = + (mIsAdaptive && outputPort) ? mAdaptiveMaxHeight : newHeight; + def->format.video.nStride = def->format.video.nFrameWidth; + def->format.video.nSliceHeight = def->format.video.nFrameHeight; + def->nBufferSize = + def->format.video.nFrameWidth * def->format.video.nFrameHeight * 3 / 2; + if (outputPort) { + mWidth = newWidth; + mHeight = newHeight; + mCropLeft = 0; + mCropTop = 0; + mCropWidth = newWidth; + mCropHeight = newHeight; + } + newParams->nBufferSize = def->nBufferSize; + } + return SimpleSoftOMXComponent::internalSetParameter(index, params); + } + default: return SimpleSoftOMXComponent::internalSetParameter(index, params); } -- cgit v1.1 From d5a2f55034022f2d0425fa0701894d0c4787b726 Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Wed, 24 Sep 2014 14:55:23 -0700 Subject: stagefright: fix cropping handling for SoftAVC and SoftMEPEG4. Bug: 17326758 Change-Id: I9b0c281d92cf1803e275b1768e9edab9404ea577 --- .../libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp | 20 ++++++++++++-------- media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp | 14 ++++++++------ media/libstagefright/codecs/on2/h264dec/SoftAVC.h | 2 +- .../include/SoftVideoDecoderOMXComponent.h | 7 ++++++- .../omx/SoftVideoDecoderOMXComponent.cpp | 6 ++++-- 5 files changed, 31 insertions(+), 18 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp index 5b2ab84..d98fa80 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp @@ -295,19 +295,23 @@ bool SoftMPEG4::handlePortSettingsChange() { ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d", disp_width, disp_height, buf_width, buf_height); - bool cropChanged = false; - if (mCropWidth != disp_width || mCropHeight != disp_height) { - mCropLeft = 0; - mCropTop = 0; - mCropWidth = disp_width; - mCropHeight = disp_height; - cropChanged = true; + CropSettingsMode cropSettingsMode = kCropUnSet; + if (disp_width != buf_width || disp_height != buf_height) { + cropSettingsMode = kCropSet; + + if (mCropWidth != disp_width || mCropHeight != disp_height) { + mCropLeft = 0; + mCropTop = 0; + mCropWidth = disp_width; + mCropHeight = disp_height; + cropSettingsMode = kCropChanged; + } } bool portWillReset = false; const bool fakeStride = true; SoftVideoDecoderOMXComponent::handlePortSettingsChange( - &portWillReset, buf_width, buf_height, cropChanged, fakeStride); + &portWillReset, buf_width, buf_height, cropSettingsMode, fakeStride); if (portWillReset) { if (mMode == MODE_H263) { PVCleanUpVideoDecoder(mHandle); diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp index cf3c3e3..168208f 100644 --- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp +++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp @@ -160,10 +160,11 @@ void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) { H264SwDecInfo decoderInfo; CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK); - bool cropChanged = handleCropChange(decoderInfo); + SoftVideoDecoderOMXComponent::CropSettingsMode cropSettingsMode = + handleCropParams(decoderInfo); handlePortSettingsChange( &portWillReset, decoderInfo.picWidth, decoderInfo.picHeight, - cropChanged); + cropSettingsMode); } } else { if (portWillReset) { @@ -209,9 +210,10 @@ void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) { } } -bool SoftAVC::handleCropChange(const H264SwDecInfo& decInfo) { +SoftVideoDecoderOMXComponent::CropSettingsMode SoftAVC::handleCropParams( + const H264SwDecInfo& decInfo) { if (!decInfo.croppingFlag) { - return false; + return kCropUnSet; } const CropParams& crop = decInfo.cropParams; @@ -219,14 +221,14 @@ bool SoftAVC::handleCropChange(const H264SwDecInfo& decInfo) { mCropTop == crop.cropTopOffset && mCropWidth == crop.cropOutWidth && mCropHeight == crop.cropOutHeight) { - return false; + return kCropSet; } mCropLeft = crop.cropLeftOffset; mCropTop = crop.cropTopOffset; mCropWidth = crop.cropOutWidth; mCropHeight = crop.cropOutHeight; - return true; + return kCropChanged; } void SoftAVC::saveFirstOutputBuffer(int32_t picId, uint8_t *data) { diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.h b/media/libstagefright/codecs/on2/h264dec/SoftAVC.h index 253a406..069107d 100644 --- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.h +++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.h @@ -73,7 +73,7 @@ private: void drainAllOutputBuffers(bool eos); void drainOneOutputBuffer(int32_t picId, uint8_t *data); void saveFirstOutputBuffer(int32_t pidId, uint8_t *data); - bool handleCropChange(const H264SwDecInfo& decInfo); + CropSettingsMode handleCropParams(const H264SwDecInfo& decInfo); DISALLOW_EVIL_CONSTRUCTORS(SoftAVC); }; diff --git a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h index 37b1fe1..9e97ebd 100644 --- a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h +++ b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h @@ -68,9 +68,14 @@ protected: uint32_t outputBufferWidth(); uint32_t outputBufferHeight(); + enum CropSettingsMode { + kCropUnSet = 0, + kCropSet, + kCropChanged, + }; void handlePortSettingsChange( bool *portWillReset, uint32_t width, uint32_t height, - bool cropChanged = false, bool fakeStride = false); + CropSettingsMode cropSettingsMode = kCropUnSet, bool fakeStride = false); void copyYV12FrameToOutputBuffer( uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV, diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp index 5853469..a7f7a07 100644 --- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp +++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp @@ -160,15 +160,17 @@ uint32_t SoftVideoDecoderOMXComponent::outputBufferHeight() { } void SoftVideoDecoderOMXComponent::handlePortSettingsChange( - bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged, bool fakeStride) { + bool *portWillReset, uint32_t width, uint32_t height, + CropSettingsMode cropSettingsMode, bool fakeStride) { *portWillReset = false; bool sizeChanged = (width != mWidth || height != mHeight); + bool updateCrop = (cropSettingsMode == kCropUnSet); + bool cropChanged = (cropSettingsMode == kCropChanged); if (sizeChanged || cropChanged) { mWidth = width; mHeight = height; - bool updateCrop = !cropChanged; if ((sizeChanged && !mIsAdaptive) || width > mAdaptiveMaxWidth || height > mAdaptiveMaxHeight) { -- cgit v1.1 From 5d6fb5e41f57a71bd5b2902dc8334825de7bdcc0 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 24 Sep 2014 11:30:21 -0700 Subject: mediaplayer: handle bad input in VideoFrameScheduler Bug: 17626098 Change-Id: I2ae22ed43b35ff532a47818b118dd328ce2abf63 --- media/libmediaplayerservice/VideoFrameScheduler.cpp | 18 +++++++++++++++--- media/libmediaplayerservice/VideoFrameScheduler.h | 3 ++- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/VideoFrameScheduler.cpp b/media/libmediaplayerservice/VideoFrameScheduler.cpp index 4251c4e..1a5f3e0 100644 --- a/media/libmediaplayerservice/VideoFrameScheduler.cpp +++ b/media/libmediaplayerservice/VideoFrameScheduler.cpp @@ -152,7 +152,7 @@ void VideoFrameScheduler::PLL::test() { #endif -void VideoFrameScheduler::PLL::fit( +bool VideoFrameScheduler::PLL::fit( nsecs_t phase, nsecs_t period, size_t numSamplesToUse, int64_t *a, int64_t *b, int64_t *err) { if (numSamplesToUse > mNumSamples) { @@ -187,6 +187,10 @@ void VideoFrameScheduler::PLL::fit( } int64_t div = numSamplesToUse * sumXX - sumX * sumX; + if (div == 0) { + return false; + } + int64_t a_nom = numSamplesToUse * sumXY - sumX * sumY; int64_t b_nom = sumXX * sumY - sumX * sumXY; *a = divRound(a_nom, div); @@ -198,6 +202,7 @@ void VideoFrameScheduler::PLL::fit( (long long)*a, (*a / (float)(1 << kPrecision)), (long long)*b, (*b / (float)(1 << kPrecision)), (long long)*err, (*err / (float)(1 << (kPrecision * 2)))); + return true; } void VideoFrameScheduler::PLL::prime(size_t numSamplesToUse) { @@ -226,7 +231,7 @@ void VideoFrameScheduler::PLL::prime(size_t numSamplesToUse) { deltas.sort(compare); size_t numDeltas = deltas.size(); if (numDeltas > 1) { - nsecs_t deltaMinLimit = min(deltas[0] / kMultiplesThresholdDiv, kMinPeriod); + nsecs_t deltaMinLimit = max(deltas[0] / kMultiplesThresholdDiv, kMinPeriod); nsecs_t deltaMaxLimit = deltas[numDeltas / 2] * kMultiplesThresholdDiv; for (size_t i = numDeltas / 2 + 1; i < numDeltas; ++i) { if (deltas[i] > deltaMaxLimit) { @@ -314,8 +319,15 @@ nsecs_t VideoFrameScheduler::PLL::addSample(nsecs_t time) { if (doFit) { int64_t a, b, err; + if (!fit(mPhase, mPeriod, kMaxSamplesToEstimatePeriod, &a, &b, &err)) { + // samples are not suitable for fitting. this means they are + // also not suitable for priming. + ALOGV("could not fit - keeping old period:%lld", (long long)mPeriod); + return mPeriod; + } + mRefitAt = time + kRefitRefreshPeriod; - fit(mPhase, mPeriod, kMaxSamplesToEstimatePeriod, &a, &b, &err); + mPhase += (mPeriod * b) >> kPrecision; mPeriod = (mPeriod * a) >> kPrecision; ALOGV("new phase:%lld period:%lld", (long long)mPhase, (long long)mPeriod); diff --git a/media/libmediaplayerservice/VideoFrameScheduler.h b/media/libmediaplayerservice/VideoFrameScheduler.h index 19f0787..84b27b4 100644 --- a/media/libmediaplayerservice/VideoFrameScheduler.h +++ b/media/libmediaplayerservice/VideoFrameScheduler.h @@ -71,7 +71,8 @@ private: nsecs_t mTimes[kHistorySize]; void test(); - void fit(nsecs_t phase, nsecs_t period, size_t numSamples, + // returns whether fit was successful + bool fit(nsecs_t phase, nsecs_t period, size_t numSamples, int64_t *a, int64_t *b, int64_t *err); void prime(size_t numSamples); }; -- cgit v1.1 From cf31f1eecf46d599428e115dfee8dd47b76c83fc Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 23 Sep 2014 14:59:01 -0700 Subject: NuPlayer: Fix decoder error handling Upon error, release MediaCodec after flushing data. Report errors when they occur with ALOGE. Fix onInputBufferFilled mInputBufferIsDequeued check. Bug: 17423087 Bug: 17622642 Change-Id: I316601a19d5ec95cf8e14f5bc0418a05ec423041 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 19 ++++++++---- .../nuplayer/NuPlayerDecoder.cpp | 34 +++++++++++++++++----- media/libstagefright/foundation/AMessage.cpp | 2 +- 3 files changed, 40 insertions(+), 15 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index ceedb40..ef4abd4 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -832,24 +832,31 @@ void NuPlayer::onMessageReceived(const sp &msg) { finishFlushIfPossible(); } else if (what == Decoder::kWhatError) { - ALOGE("Received error from %s decoder, aborting playback.", - audio ? "audio" : "video"); - status_t err; if (!msg->findInt32("err", &err)) { err = UNKNOWN_ERROR; } - mRenderer->queueEOS(audio, err); + ALOGE("received error from %s decoder %#x", audio ? "audio" : "video", err); + + ALOGI("shutting down %s", audio ? "audio" : "video"); if (audio && mFlushingAudio != NONE) { + mRenderer->queueEOS(audio, err); mAudioDecoder.clear(); ++mAudioDecoderGeneration; mFlushingAudio = SHUT_DOWN; - } else if (!audio && mFlushingVideo != NONE){ + finishFlushIfPossible(); + } else if (!audio && mFlushingVideo != NONE) { + mRenderer->queueEOS(audio, err); mVideoDecoder.clear(); ++mVideoDecoderGeneration; mFlushingVideo = SHUT_DOWN; + finishFlushIfPossible(); + } else { + mDeferredActions.push_back( + new ShutdownDecoderAction(audio, !audio /* video */)); + processDeferredActions(); + notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); } - finishFlushIfPossible(); } else if (what == Decoder::kWhatDrainThisBuffer) { renderBuffer(audio, msg); } else { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index cdb860c..ed6f674 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -223,7 +223,11 @@ status_t NuPlayer::Decoder::getInputBuffers(Vector > *buffers) const void NuPlayer::Decoder::handleError(int32_t err) { - mCodec->release(); + // We cannot immediately release the codec due to buffers still outstanding + // in the renderer. We signal to the player the error so it can shutdown/release the + // decoder after flushing and increment the generation to discard unnecessary messages. + + ++mBufferGeneration; sp notify = mNotify->dup(); notify->setInt32("what", kWhatError); @@ -238,6 +242,8 @@ bool NuPlayer::Decoder::handleAnInputBuffer() { mComponentName.c_str(), res == OK ? (int)bufferIx : res); if (res != OK) { if (res != -EAGAIN) { + ALOGE("Failed to dequeue input buffer for %s (err=%d)", + mComponentName.c_str(), res); handleError(res); } return false; @@ -311,7 +317,7 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { } } - mInputBufferIsDequeued.editItemAt(bufferIx) = false; + if (buffer == NULL /* includes !hasBuffer */) { int32_t streamErr = ERROR_END_OF_STREAM; @@ -329,12 +335,18 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { 0, 0, MediaCodec::BUFFER_FLAG_EOS); - if (streamErr == ERROR_END_OF_STREAM && err != OK) { + if (err == OK) { + mInputBufferIsDequeued.editItemAt(bufferIx) = false; + } else if (streamErr == ERROR_END_OF_STREAM) { streamErr = err; // err will not be ERROR_END_OF_STREAM } if (streamErr != ERROR_END_OF_STREAM) { + ALOGE("Stream error for %s (err=%d), EOS %s queued", + mComponentName.c_str(), + streamErr, + err == OK ? "successfully" : "unsuccessfully"); handleError(streamErr); } } else { @@ -364,14 +376,18 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { timeUs, flags); if (err != OK) { + if (mediaBuffer != NULL) { + mediaBuffer->release(); + } ALOGE("Failed to queue input buffer for %s (err=%d)", mComponentName.c_str(), err); handleError(err); - } - - if (mediaBuffer != NULL) { - CHECK(mMediaBuffers[bufferIx] == NULL); - mMediaBuffers.editItemAt(bufferIx) = mediaBuffer; + } else { + mInputBufferIsDequeued.editItemAt(bufferIx) = false; + if (mediaBuffer != NULL) { + CHECK(mMediaBuffers[bufferIx] == NULL); + mMediaBuffers.editItemAt(bufferIx) = mediaBuffer; + } } } } @@ -422,6 +438,8 @@ bool NuPlayer::Decoder::handleAnOutputBuffer() { return true; } else if (res != OK) { if (res != -EAGAIN) { + ALOGE("Failed to dequeue output buffer for %s (err=%d)", + mComponentName.c_str(), res); handleError(res); } return false; diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp index bc3e3fb..795e8a6 100644 --- a/media/libstagefright/foundation/AMessage.cpp +++ b/media/libstagefright/foundation/AMessage.cpp @@ -485,7 +485,7 @@ AString AMessage::debugString(int32_t indent) const { { sp buffer = static_cast(item.u.refValue); - if (buffer != NULL && buffer->size() <= 64) { + if (buffer != NULL && buffer->data() != NULL && buffer->size() <= 64) { tmp = StringPrintf("Buffer %s = {\n", item.mName); hexdump(buffer->data(), buffer->size(), indent + 4, &tmp); appendIndent(&tmp, indent + 2); -- cgit v1.1 From a935c76f96b066941b34f81c42b3fe9d00db98c5 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 24 Sep 2014 18:46:45 -0700 Subject: stagefright: Advertise 16x16 alignment requirement for PV codecs Bug: 17648616 Change-Id: Iaf276467ae9361d918feee1f72e13c7a60075819 --- media/libstagefright/data/media_codecs_google_video.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml index c97be28..1cbef39 100644 --- a/media/libstagefright/data/media_codecs_google_video.xml +++ b/media/libstagefright/data/media_codecs_google_video.xml @@ -73,22 +73,22 @@ - - + + - - + + - - + + -- cgit v1.1 From 4edf384a512748b871f24e4c03afaa3c1151ca23 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 25 Sep 2014 14:25:18 -0700 Subject: Fix SoftAAC2 flush If there were less than a full frame worth of samples in the ring buffer, then flush would loop forever trying to empty the ring buffer. Bug: 17646525 Change-Id: I68ec87352a91ce3a96d05e9b3f60a6e7975f9156 --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index fb27dca..e701e9e 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -974,11 +974,15 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { mDecodedSizes.clear(); mLastInHeader = NULL; } else { - while (outputDelayRingBufferSamplesAvailable() > 0) { - int32_t ns = outputDelayRingBufferGetSamples(0, - mStreamInfo->frameSize * mStreamInfo->numChannels); - if (ns != mStreamInfo->frameSize * mStreamInfo->numChannels) { + int avail; + while ((avail = outputDelayRingBufferSamplesAvailable()) > 0) { + if (avail > mStreamInfo->frameSize * mStreamInfo->numChannels) { + avail = mStreamInfo->frameSize * mStreamInfo->numChannels; + } + int32_t ns = outputDelayRingBufferGetSamples(0, avail); + if (ns != avail) { ALOGE("not a complete frame of samples available"); + break; } mOutputBufferCount++; } -- cgit v1.1 From 36f389888e4b2905f0b457f451187fd8d3ed5153 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Thu, 25 Sep 2014 15:27:04 -0700 Subject: NuPlayer: use format obtained from source to tell if video exists. Bug: 17374216 Change-Id: I2d5f90d72b70684475d67ff8f41b803c2880840b --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index ef4abd4..ca596fd 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -559,7 +559,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { static_cast(obj.get()))); if (obj != NULL) { - if (mStarted && mVideoDecoder != NULL) { + if (mStarted && mSource->getFormat(false /* audio */) != NULL) { // Issue a seek to refresh the video screen only if started otherwise // the extractor may not yet be started and will assert. // If the video decoder is not set (perhaps audio only in this case) -- cgit v1.1 From bb6c9a05840d924b502ce0f1868fca4881ada1ed Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 25 Sep 2014 14:11:47 -0700 Subject: audio: fix stream type for accessibility usage Make sure that accessibility prompts are heard when a ringtone is active by forcing stream type to AUDIO_STREAM_RING when phone state is AUDIO_MODE_RINGTONE. Bug: 17558149. Change-Id: Ia3bead8052fca5cbf282c267f7b9b06014fef628 --- media/libmedia/AudioSystem.cpp | 9 +++++++++ media/libmedia/AudioTrack.cpp | 9 ++++++++- media/libmedia/IAudioPolicyService.cpp | 20 +++++++++++++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 1742fbe..dda3657 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -939,6 +939,15 @@ status_t AudioSystem::releaseSoundTriggerSession(audio_session_t session) if (aps == 0) return PERMISSION_DENIED; return aps->releaseSoundTriggerSession(session); } + +audio_mode_t AudioSystem::getPhoneState() +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return AUDIO_MODE_INVALID; + return aps->getPhoneState(); +} + + // --------------------------------------------------------------------------- void AudioSystem::AudioPolicyServiceClient::binderDied(const wp& who __unused) diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index ea7b279..e3beba5 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -2124,9 +2124,16 @@ void AudioTrack::setStreamTypeFromAttributes(audio_attributes_t& aa) { // usage to stream type mapping switch (aa.usage) { + case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY: + // TODO once AudioPolicyManager fully supports audio_attributes_t, + // remove stream change based on phone state + if (AudioSystem::getPhoneState() == AUDIO_MODE_RINGTONE) { + mStreamType = AUDIO_STREAM_RING; + break; + } + /// FALL THROUGH case AUDIO_USAGE_MEDIA: case AUDIO_USAGE_GAME: - case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY: case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: mStreamType = AUDIO_STREAM_MUSIC; return; diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index b57f747..256cb3f 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -67,7 +67,8 @@ enum { REGISTER_CLIENT, GET_OUTPUT_FOR_ATTR, ACQUIRE_SOUNDTRIGGER_SESSION, - RELEASE_SOUNDTRIGGER_SESSION + RELEASE_SOUNDTRIGGER_SESSION, + GET_PHONE_STATE }; class BpAudioPolicyService : public BpInterface @@ -607,6 +608,17 @@ public: } return (status_t)reply.readInt32(); } + + virtual audio_mode_t getPhoneState() + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_PHONE_STATE, data, &reply); + if (status != NO_ERROR) { + return AUDIO_MODE_INVALID; + } + return (audio_mode_t)reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -1057,6 +1069,12 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } break; + case GET_PHONE_STATE: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + reply->writeInt32((int32_t)getPhoneState()); + return NO_ERROR; + } break; + default: return BBinder::onTransact(code, data, reply, flags); } -- cgit v1.1 From ab76066c11e988ca3d3a5d6d74dd510ae080322e Mon Sep 17 00:00:00 2001 From: Rachad Date: Mon, 22 Sep 2014 19:34:31 -0700 Subject: stagefright: do not allocate output buffers for tunneled playback Do not allocate native window buffers for tunneled video playback codecs. Bug: 17112525 Change-Id: I262d8030a9df6188938fde5d62ebce8faf7dba1f --- media/libstagefright/ACodec.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 9b03b71..e812ad0 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -420,7 +420,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); @@ -696,6 +697,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, @@ -903,6 +919,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; @@ -1244,6 +1267,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)) { @@ -1258,6 +1282,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); -- cgit v1.1 From 274084f7bfd3f6bdf5a55cf16ceefed345aa0060 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 29 Sep 2014 16:36:37 -0700 Subject: mediaplayer: make frame-accurate avsync configurable disable by default Bug: 17686015 Change-Id: I3961b1bc9c6d48afc8c5f7f5270528ea6341bc60 --- .../nuplayer/NuPlayerRenderer.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 73ac057..6d10651 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -20,6 +20,8 @@ #include "NuPlayerRenderer.h" +#include + #include #include #include @@ -39,6 +41,16 @@ static const int64_t kOffloadPauseMaxUs = 60000000ll; // static const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll; +static bool sFrameAccurateAVsync = false; + +static void readProperties() { + char value[PROPERTY_VALUE_MAX]; + if (property_get("persist.sys.media.avsync", value, NULL)) { + sFrameAccurateAVsync = + !strcmp("1", value) || !strcasecmp("true", value); + } +} + NuPlayer::Renderer::Renderer( const sp &sink, const sp ¬ify, @@ -68,6 +80,7 @@ NuPlayer::Renderer::Renderer( mVideoLateByUs(0ll), mAudioOffloadPauseTimeoutGeneration(0), mAudioOffloadTornDown(false) { + readProperties(); } NuPlayer::Renderer::~Renderer() { @@ -576,6 +589,11 @@ void NuPlayer::Renderer::postDrainVideoQueue() { ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs); // post 2 display refreshes before rendering is due + // FIXME currently this increases power consumption, so unless frame-accurate + // AV sync is requested, post closer to required render time (at 0.63 vsyncs) + if (!sFrameAccurateAVsync) { + twoVsyncsUs >>= 4; + } msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0); mDrainVideoQueuePending = true; @@ -976,6 +994,8 @@ void NuPlayer::Renderer::onPause() { } void NuPlayer::Renderer::onResume() { + readProperties(); + if (!mPaused) { return; } -- cgit v1.1 From 6300cbe99899da0103c910ba6a35c785261ce433 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 30 Sep 2014 14:53:39 -0700 Subject: Check if info for uri is available before retrieving it. Bug: 17683986 Change-Id: I7a44cd06faf11c22be2ed5ace8ab6e2a5513b66c --- media/libstagefright/httplive/LiveSession.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'media') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 7a9a1a3..fba6b09 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -494,6 +494,10 @@ void LiveSession::onMessageReceived(const sp &msg) { AString uri; CHECK(msg->findString("uri", &uri)); + if (mFetcherInfos.indexOfKey(uri) < 0) { + ALOGE("couldn't find uri"); + break; + } FetcherInfo *info = &mFetcherInfos.editValueFor(uri); info->mIsPrepared = true; -- cgit v1.1 From 4f17dadd3cfd9940893ea042ca8883c6aa6ada07 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Tue, 30 Sep 2014 14:17:38 -0700 Subject: NuCachedSource2: fix disconnect process - clear mAsyncResult - return early from reads if mDisconnecting is set Bug: 17696761 Change-Id: I98bfc3f5f06594915bd58faf71fbcded482664d2 --- media/libstagefright/NuCachedSource2.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'media') diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index f469d4d..bd0a41d 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -456,6 +456,10 @@ void NuCachedSource2::onRead(const sp &msg) { } Mutex::Autolock autoLock(mLock); + if (mDisconnecting) { + mCondition.signal(); + return; + } CHECK(mAsyncResult == NULL); @@ -502,6 +506,9 @@ ssize_t NuCachedSource2::readAt(off64_t offset, void *data, size_t size) { ALOGV("readAt offset %lld, size %zu", offset, size); Mutex::Autolock autoLock(mLock); + if (mDisconnecting) { + return ERROR_END_OF_STREAM; + } // If the request can be completely satisfied from the cache, do so. @@ -528,6 +535,7 @@ ssize_t NuCachedSource2::readAt(off64_t offset, void *data, size_t size) { } if (mDisconnecting) { + mAsyncResult.clear(); return ERROR_END_OF_STREAM; } -- cgit v1.1 From 2965f4eb7dceaf1173f0e2d93c11c28293aeead7 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 30 Sep 2014 22:02:34 -0700 Subject: add AAC audio decoder params for PCM limiter enable Bug: 17470065 Change-Id: Ib67aa1c50e3b6c24c4b12b0f31a996cc6874abd1 --- media/libstagefright/ACodec.cpp | 12 ++++++++++-- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 3c04859..7ca5d9e 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -1359,6 +1359,7 @@ status_t ACodec::configureCodec( int32_t isADTS, aacProfile; int32_t sbrMode; int32_t maxOutputChannelCount; + int32_t pcmLimiterEnable; drcParams_t drc; if (!msg->findInt32("is-adts", &isADTS)) { isADTS = 0; @@ -1373,6 +1374,10 @@ status_t ACodec::configureCodec( if (!msg->findInt32("aac-max-output-channel_count", &maxOutputChannelCount)) { maxOutputChannelCount = -1; } + if (!msg->findInt32("aac-pcm-limiter-enable", &pcmLimiterEnable)) { + // value is unknown + pcmLimiterEnable = -1; + } if (!msg->findInt32("aac-encoded-target-level", &drc.encodedTargetLevel)) { // value is unknown drc.encodedTargetLevel = -1; @@ -1396,7 +1401,8 @@ status_t ACodec::configureCodec( err = setupAACCodec( encoder, numChannels, sampleRate, bitRate, aacProfile, - isADTS != 0, sbrMode, maxOutputChannelCount, drc); + isADTS != 0, sbrMode, maxOutputChannelCount, drc, + pcmLimiterEnable); } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) { err = setupAMRCodec(encoder, false /* isWAMR */, bitRate); @@ -1561,7 +1567,8 @@ status_t ACodec::selectAudioPortFormat( status_t ACodec::setupAACCodec( bool encoder, int32_t numChannels, int32_t sampleRate, int32_t bitRate, int32_t aacProfile, bool isADTS, int32_t sbrMode, - int32_t maxOutputChannelCount, const drcParams_t& drc) { + int32_t maxOutputChannelCount, const drcParams_t& drc, + int32_t pcmLimiterEnable) { if (encoder && isADTS) { return -EINVAL; } @@ -1691,6 +1698,7 @@ status_t ACodec::setupAACCodec( presentation.nHeavyCompression = drc.heavyCompression; presentation.nTargetReferenceLevel = drc.targetRefLevel; presentation.nEncodedTargetLevel = drc.encodedTargetLevel; + presentation.nPCMLimiterEnable = pcmLimiterEnable; status_t res = mOMX->setParameter(mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); if (res == OK) { diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index fb27dca..287fcc8 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -368,6 +368,10 @@ OMX_ERRORTYPE SoftAAC2::internalSetParameter( aacPresParams->nEncodedTargetLevel); updateDrcWrapper = true; } + if (aacPresParams->nPCMLimiterEnable >= 0) { + aacDecoder_SetParam(mAACDecoder, AAC_PCM_LIMITER_ENABLE, + (aacPresParams->nPCMLimiterEnable != 0)); + } if (updateDrcWrapper) { mDrcWrap.update(); } -- cgit v1.1 From 360d6d0924f99b82ebacb5cfb6f7bca95e11b4ee Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Mon, 29 Sep 2014 14:42:35 -0700 Subject: GenericSource: support disconnect before NuCachedSource2 is created Bug: 17672488 Change-Id: I96776c9679fdcfbe9a442c86447c59802b1465ac --- .../nuplayer/GenericSource.cpp | 22 ++++++++++++++-- .../libmediaplayerservice/nuplayer/GenericSource.h | 1 + media/libstagefright/DataSource.cpp | 29 ++++++++++++++++------ 3 files changed, 43 insertions(+), 9 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index f84decd..016a764 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -36,6 +36,7 @@ #include "../../libstagefright/include/DRMExtractor.h" #include "../../libstagefright/include/NuCachedSource2.h" #include "../../libstagefright/include/WVMExtractor.h" +#include "../../libstagefright/include/HTTPBase.h" namespace android { @@ -64,6 +65,7 @@ void NuPlayer::GenericSource::resetDataSource() { mAudioTimeUs = 0; mVideoTimeUs = 0; mHTTPService.clear(); + mHttpSource.clear(); mUri.clear(); mUriHeaders.clear(); mFd = -1; @@ -284,10 +286,23 @@ void NuPlayer::GenericSource::onPrepareAsync() { // delayed data source creation if (mDataSource == NULL) { if (!mUri.empty()) { - mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11); + const char* uri = mUri.c_str(); + mIsWidevine = !strncasecmp(uri, "widevine://", 11); + + if (!strncasecmp("http://", uri, 7) + || !strncasecmp("https://", uri, 8) + || mIsWidevine) { + mHttpSource = DataSource::CreateMediaHTTP(mHTTPService); + if (mHttpSource == NULL) { + ALOGE("Failed to create http source!"); + notifyPreparedAndCleanup(UNKNOWN_ERROR); + return; + } + } mDataSource = DataSource::CreateFromURI( - mHTTPService, mUri.c_str(), &mUriHeaders, &mContentType); + mHTTPService, uri, &mUriHeaders, &mContentType, + static_cast(mHttpSource.get())); } else { // set to false first, if the extractor // comes back as secure, set it to true then. @@ -360,6 +375,7 @@ void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { mSniffedMIME = ""; mDataSource.clear(); mCachedSource.clear(); + mHttpSource.clear(); cancelPollBuffering(); } @@ -479,6 +495,8 @@ void NuPlayer::GenericSource::disconnect() { if (mDataSource->flags() & DataSource::kIsCachingDataSource) { static_cast(mDataSource.get())->disconnect(); } + } else if (mHttpSource != NULL) { + static_cast(mHttpSource.get())->disconnect(); } } diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 24bb6af..5ed4d52 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -126,6 +126,7 @@ private: sp mDataSource; sp mCachedSource; + sp mHttpSource; sp mWVMExtractor; sp mFileMeta; DrmManagerClient *mDrmManagerClient; diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index a72cbd5..c99db84 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -186,7 +186,8 @@ sp DataSource::CreateFromURI( const sp &httpService, const char *uri, const KeyedVector *headers, - String8 *contentType) { + String8 *contentType, + HTTPBase *httpSource) { if (contentType != NULL) { *contentType = ""; } @@ -204,14 +205,15 @@ sp DataSource::CreateFromURI( return NULL; } - sp conn = httpService->makeHTTPConnection(); - if (conn == NULL) { - ALOGE("Failed to make http connection from http service!"); - return NULL; + if (httpSource == NULL) { + sp conn = httpService->makeHTTPConnection(); + if (conn == NULL) { + ALOGE("Failed to make http connection from http service!"); + return NULL; + } + httpSource = new MediaHTTP(conn); } - sp httpSource = new MediaHTTP(conn); - String8 tmp; if (isWidevine) { tmp = String8("http://"); @@ -264,6 +266,19 @@ sp DataSource::CreateFromURI( return source; } +sp DataSource::CreateMediaHTTP(const sp &httpService) { + if (httpService == NULL) { + return NULL; + } + + sp conn = httpService->makeHTTPConnection(); + if (conn == NULL) { + return NULL; + } else { + return new MediaHTTP(conn); + } +} + String8 DataSource::getMIMEType() const { return String8("application/octet-stream"); } -- cgit v1.1 From 482e0235f84ec483c57bab4cb16b5918d0821630 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Wed, 1 Oct 2014 12:59:57 -0700 Subject: camera2: Force DNG previews to render with LSC map. Bug: 17688063 Change-Id: I7f60a3465ab608a6b68d1e38493895cbd40bd7ae --- media/img_utils/src/DngUtils.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp index 14b31ec..d3b4a35 100644 --- a/media/img_utils/src/DngUtils.cpp +++ b/media/img_utils/src/DngUtils.cpp @@ -229,7 +229,9 @@ status_t OpcodeListBuilder::addGainMap(uint32_t top, err = mEndianOut.write(version, 0, NELEMS(version)); if (err != OK) return err; - uint32_t flags = FLAG_OPTIONAL | FLAG_OPTIONAL_FOR_PREVIEW; + // Do not include optional flag for preview, as this can have a large effect on the output. + uint32_t flags = FLAG_OPTIONAL; + err = mEndianOut.write(&flags, 0, 1); if (err != OK) return err; -- cgit v1.1 From 2abde2c118a94f843a7450818c925d3f0b673cd3 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 30 Sep 2014 14:40:32 -0700 Subject: NuPlayer: Fix flush mode decoder error handling Explicitly handle each flush mode upon decoder error. Do not clear out affected decoder immediately. Alter logcat messages for better diagnostics. Bug: 17638878 Bug: 17679341 Change-Id: I219796c04d65d7c4dd61c0d4f99f9f580241a68b --- .../nuplayer/GenericSource.cpp | 31 +++++++++++ .../libmediaplayerservice/nuplayer/GenericSource.h | 2 + media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 65 +++++++++++++++------- .../nuplayer/NuPlayerDecoder.cpp | 10 +++- .../nuplayer/NuPlayerDriver.cpp | 19 ++++++- .../nuplayer/NuPlayerRenderer.cpp | 4 +- 6 files changed, 103 insertions(+), 28 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index f84decd..baf211b 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -73,6 +73,7 @@ void NuPlayer::GenericSource::resetDataSource() { mDecryptHandle = NULL; mDrmManagerClient = NULL; mStarted = false; + mStopRead = true; } status_t NuPlayer::GenericSource::setDataSource( @@ -439,6 +440,7 @@ status_t NuPlayer::GenericSource::prefillCacheIfNecessary() { void NuPlayer::GenericSource::start() { ALOGI("start"); + mStopRead = false; if (mAudioTrack.mSource != NULL) { CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); @@ -459,6 +461,12 @@ void NuPlayer::GenericSource::stop() { // nothing to do, just account for DRM playback status setDrmPlaybackStatusIfNeeded(Playback::STOP, 0); mStarted = false; + if (mIsWidevine) { + // For a widevine source we need to prevent any further reads. + sp msg = new AMessage(kWhatStopWidevine, id()); + sp response; + (void) msg->postAndAwaitResponse(&response); + } } void NuPlayer::GenericSource::pause() { @@ -675,6 +683,20 @@ void NuPlayer::GenericSource::onMessageReceived(const sp &msg) { break; } + case kWhatStopWidevine: + { + // mStopRead is only used for Widevine to prevent the video source + // from being read while the associated video decoder is shutting down. + mStopRead = true; + if (mVideoTrack.mSource != NULL) { + mVideoTrack.mPackets->clear(); + } + sp response = new AMessage; + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + response->postReply(replyID); + break; + } default: Source::onMessageReceived(msg); break; @@ -1082,6 +1104,11 @@ void NuPlayer::GenericSource::onSeek(sp msg) { } status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) { + // If the Widevine source is stopped, do not attempt to read any + // more buffers. + if (mStopRead) { + return INVALID_OPERATION; + } if (mVideoTrack.mSource != NULL) { int64_t actualTimeUs; readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs); @@ -1193,6 +1220,10 @@ void NuPlayer::GenericSource::onReadBuffer(sp msg) { void NuPlayer::GenericSource::readBuffer( media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) { + // Do not read data if Widevine source is stopped + if (mStopRead) { + return; + } Track *track; size_t maxBuffers = 1; switch (trackType) { diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 24bb6af..1741f27 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -93,6 +93,7 @@ private: kWhatSelectTrack, kWhatSeek, kWhatReadBuffer, + kWhatStopWidevine, }; Vector > mSources; @@ -131,6 +132,7 @@ private: DrmManagerClient *mDrmManagerClient; sp mDecryptHandle; bool mStarted; + bool mStopRead; String8 mContentType; AString mSniffedMIME; off64_t mMetaDataSize; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index ca596fd..d225851 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -791,6 +791,11 @@ void NuPlayer::onMessageReceived(const sp &msg) { 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) { @@ -833,30 +838,50 @@ void NuPlayer::onMessageReceived(const sp &msg) { finishFlushIfPossible(); } else if (what == Decoder::kWhatError) { status_t err; - if (!msg->findInt32("err", &err)) { + if (!msg->findInt32("err", &err) || err == OK) { err = UNKNOWN_ERROR; } - ALOGE("received error from %s decoder %#x", audio ? "audio" : "video", err); - ALOGI("shutting down %s", audio ? "audio" : "video"); - if (audio && mFlushingAudio != NONE) { - mRenderer->queueEOS(audio, err); - mAudioDecoder.clear(); - ++mAudioDecoderGeneration; - mFlushingAudio = SHUT_DOWN; - finishFlushIfPossible(); - } else if (!audio && mFlushingVideo != NONE) { - mRenderer->queueEOS(audio, err); - mVideoDecoder.clear(); - ++mVideoDecoderGeneration; - mFlushingVideo = SHUT_DOWN; - finishFlushIfPossible(); - } else { - mDeferredActions.push_back( - new ShutdownDecoderAction(audio, !audio /* video */)); - processDeferredActions(); - notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); + // Decoder errors can be due to Source (e.g. from streaming), + // or from decoding corrupted bitstreams, or from other decoder + // MediaCodec operations (e.g. from an ongoing reset or seek). + // + // We try to gracefully shut down the affected decoder if possible, + // rather than trying to force the shutdown with something + // similar to performReset(). This method can lead to a hang + // if MediaCodec functions block after an error, but they should + // typically return INVALID_OPERATION instead of blocking. + + FlushStatus *flushing = audio ? &mFlushingAudio : &mFlushingVideo; + ALOGE("received error(%#x) from %s decoder, flushing(%d), now shutting down", + err, audio ? "audio" : "video", *flushing); + + switch (*flushing) { + case NONE: + mDeferredActions.push_back( + new ShutdownDecoderAction(audio, !audio /* video */)); + processDeferredActions(); + break; + case FLUSHING_DECODER: + *flushing = FLUSHING_DECODER_SHUTDOWN; // initiate shutdown after flush. + break; // Wait for flush to complete. + case FLUSHING_DECODER_SHUTDOWN: + break; // Wait for flush to complete. + case SHUTTING_DOWN_DECODER: + break; // Wait for shutdown to complete. + case FLUSHED: + // Widevine source reads must stop before releasing the video decoder. + if (!audio && mSource != NULL && mSourceFlags & Source::FLAG_SECURE) { + mSource->stop(); + } + getDecoder(audio)->initiateShutdown(); // In the middle of a seek. + *flushing = SHUTTING_DOWN_DECODER; // Shut down. + break; + case SHUT_DOWN: + finishFlushIfPossible(); // Should not occur. + break; // Finish anyways. } + notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); } else if (what == Decoder::kWhatDrainThisBuffer) { renderBuffer(audio, msg); } else { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 1a066b7..7814bf1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -140,6 +140,8 @@ void NuPlayer::Decoder::onConfigure(const sp &format) { format, surface, NULL /* crypto */, 0 /* flags */); if (err != OK) { ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err); + mCodec->release(); + mCodec.clear(); handleError(err); return; } @@ -152,6 +154,8 @@ void NuPlayer::Decoder::onConfigure(const sp &format) { err = mCodec->start(); if (err != OK) { ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err); + mCodec->release(); + mCodec.clear(); handleError(err); return; } @@ -511,9 +515,9 @@ void NuPlayer::Decoder::onFlush() { if (err != OK) { ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err); handleError(err); - return; + // finish with posting kWhatFlushCompleted. + // we attempt to release the buffers even if flush fails. } - releaseAndResetMediaBuffers(); sp notify = mNotify->dup(); @@ -551,7 +555,7 @@ void NuPlayer::Decoder::onShutdown() { if (err != OK) { ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err); handleError(err); - return; + // finish with posting kWhatShutdownCompleted. } sp notify = mNotify->dup(); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index a9bca49..1a01d52 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace android { @@ -47,6 +48,7 @@ NuPlayerDriver::NuPlayerDriver() mLooping(false), mAutoLoop(false), mStartupSeekTimeUs(-1) { + ALOGV("NuPlayerDriver(%p)", this); mLooper->setName("NuPlayerDriver Looper"); mLooper->start( @@ -61,6 +63,7 @@ NuPlayerDriver::NuPlayerDriver() } NuPlayerDriver::~NuPlayerDriver() { + ALOGV("~NuPlayerDriver(%p)", this); mLooper->stop(); } @@ -78,9 +81,9 @@ status_t NuPlayerDriver::setDataSource( const sp &httpService, const char *url, const KeyedVector *headers) { + ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str()); Mutex::Autolock autoLock(mLock); - ALOGV("setDataSource: url=%s", url); if (mState != STATE_IDLE) { return INVALID_OPERATION; } @@ -97,9 +100,9 @@ status_t NuPlayerDriver::setDataSource( } status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) { + ALOGV("setDataSource(%p) file(%d)", this, fd); Mutex::Autolock autoLock(mLock); - ALOGV("setDataSource: fd=%d", fd); if (mState != STATE_IDLE) { return INVALID_OPERATION; } @@ -116,9 +119,9 @@ status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) { } status_t NuPlayerDriver::setDataSource(const sp &source) { + ALOGV("setDataSource(%p) stream source", this); Mutex::Autolock autoLock(mLock); - ALOGV("setDataSource: stream source"); if (mState != STATE_IDLE) { return INVALID_OPERATION; } @@ -136,6 +139,7 @@ status_t NuPlayerDriver::setDataSource(const sp &source) { status_t NuPlayerDriver::setVideoSurfaceTexture( const sp &bufferProducer) { + ALOGV("setVideoSurfaceTexture(%p)", this); Mutex::Autolock autoLock(mLock); if (mSetSurfaceInProgress) { @@ -163,6 +167,7 @@ status_t NuPlayerDriver::setVideoSurfaceTexture( } status_t NuPlayerDriver::prepare() { + ALOGV("prepare(%p)", this); Mutex::Autolock autoLock(mLock); return prepare_l(); } @@ -197,6 +202,7 @@ status_t NuPlayerDriver::prepare_l() { } status_t NuPlayerDriver::prepareAsync() { + ALOGV("prepareAsync(%p)", this); Mutex::Autolock autoLock(mLock); switch (mState) { @@ -218,6 +224,7 @@ status_t NuPlayerDriver::prepareAsync() { } status_t NuPlayerDriver::start() { + ALOGD("start(%p)", this); Mutex::Autolock autoLock(mLock); switch (mState) { @@ -292,6 +299,7 @@ status_t NuPlayerDriver::start() { } status_t NuPlayerDriver::stop() { + ALOGD("stop(%p)", this); Mutex::Autolock autoLock(mLock); switch (mState) { @@ -346,6 +354,7 @@ bool NuPlayerDriver::isPlaying() { } status_t NuPlayerDriver::seekTo(int msec) { + ALOGD("seekTo(%p) %d ms", this, msec); Mutex::Autolock autoLock(mLock); int64_t seekTimeUs = msec * 1000ll; @@ -430,6 +439,7 @@ status_t NuPlayerDriver::getDuration(int *msec) { } status_t NuPlayerDriver::reset() { + ALOGD("reset(%p)", this); Mutex::Autolock autoLock(mLock); switch (mState) { @@ -572,6 +582,7 @@ status_t NuPlayerDriver::getMetadata( } void NuPlayerDriver::notifyResetComplete() { + ALOGI("notifyResetComplete(%p)", this); Mutex::Autolock autoLock(mLock); CHECK_EQ(mState, STATE_RESET_IN_PROGRESS); @@ -580,6 +591,7 @@ void NuPlayerDriver::notifyResetComplete() { } void NuPlayerDriver::notifySetSurfaceComplete() { + ALOGV("notifySetSurfaceComplete(%p)", this); Mutex::Autolock autoLock(mLock); CHECK(mSetSurfaceInProgress); @@ -602,6 +614,7 @@ void NuPlayerDriver::notifyPosition(int64_t positionUs) { } void NuPlayerDriver::notifySeekComplete() { + ALOGV("notifySeekComplete(%p)", this); Mutex::Autolock autoLock(mLock); notifySeekComplete_l(); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 73ac057..8313da6 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -1031,7 +1031,7 @@ int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) { // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms, // the max latency should be about 25ms with an average around 12ms (to be verified). // For safety we use 100ms. - ALOGW("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)", + ALOGV("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)", (long long)nowUs, (long long)numFramesPlayedAt); numFramesPlayedAt = nowUs - kStaleTimestamp100ms; } @@ -1061,7 +1061,7 @@ int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) { // numFramesPlayedAt, by a time amount greater than numFramesPlayed. // // Both of these are transitory conditions. - ALOGW("getPlayedOutAudioDurationUs: negative timestamp %lld set to zero", (long long)durationUs); + ALOGV("getPlayedOutAudioDurationUs: negative duration %lld set to zero", (long long)durationUs); durationUs = 0; } ALOGV("getPlayedOutAudioDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)", -- cgit v1.1 From c416becd966945fca5fa7fb45ac51f84d1d8cd20 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 1 Oct 2014 21:30:20 -0700 Subject: stagefright: move math templates into AUtils.h add unit test for math templates Bug: 17676461 Change-Id: Ie964c5fcfcca1ec53b4538f8e577392e8fbb4319 --- .../libmediaplayerservice/VideoFrameScheduler.cpp | 31 +------ media/libstagefright/tests/Android.mk | 45 ++++++++- media/libstagefright/tests/Utils_test.cpp | 101 +++++++++++++++++++++ 3 files changed, 142 insertions(+), 35 deletions(-) create mode 100644 media/libstagefright/tests/Utils_test.cpp (limited to 'media') diff --git a/media/libmediaplayerservice/VideoFrameScheduler.cpp b/media/libmediaplayerservice/VideoFrameScheduler.cpp index 1a5f3e0..ce5f5fe 100644 --- a/media/libmediaplayerservice/VideoFrameScheduler.cpp +++ b/media/libmediaplayerservice/VideoFrameScheduler.cpp @@ -27,6 +27,7 @@ #include #include +#include #include "VideoFrameScheduler.h" @@ -35,36 +36,6 @@ namespace android { static const nsecs_t kNanosIn1s = 1000000000; template -inline static const T divRound(const T &nom, const T &den) { - if ((nom >= 0) ^ (den >= 0)) { - return (nom - den / 2) / den; - } else { - return (nom + den / 2) / den; - } -} - -template -inline static T abs(const T &a) { - return a < 0 ? -a : a; -} - -template -inline static const T &min(const T &a, const T &b) { - return a < b ? a : b; -} - -template -inline static const T &max(const T &a, const T &b) { - return a > b ? a : b; -} - -template -inline static T periodicError(const T &val, const T &period) { - T err = abs(val) % period; - return (err < (period / 2)) ? err : (period - err); -} - -template static int compare(const T *lhs, const T *rhs) { if (*lhs < *rhs) { return -1; diff --git a/media/libstagefright/tests/Android.mk b/media/libstagefright/tests/Android.mk index 903af49..99b480ad 100644 --- a/media/libstagefright/tests/Android.mk +++ b/media/libstagefright/tests/Android.mk @@ -9,7 +9,7 @@ LOCAL_MODULE := SurfaceMediaSource_test LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := \ - SurfaceMediaSource_test.cpp \ + SurfaceMediaSource_test.cpp \ DummyRecorder.cpp \ LOCAL_SHARED_LIBRARIES := \ @@ -33,10 +33,10 @@ LOCAL_STATIC_LIBRARIES := \ libgtest_main \ LOCAL_C_INCLUDES := \ - bionic \ - bionic/libstdc++/include \ - external/gtest/include \ - external/stlport/stlport \ + bionic \ + bionic/libstdc++/include \ + external/gtest/include \ + external/stlport/stlport \ frameworks/av/media/libstagefright \ frameworks/av/media/libstagefright/include \ $(TOP)/frameworks/native/include/media/openmax \ @@ -47,6 +47,41 @@ include $(BUILD_EXECUTABLE) endif + +include $(CLEAR_VARS) + +LOCAL_MODULE := Utils_test + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := \ + Utils_test.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + liblog \ + libmedia \ + libstagefright \ + libstagefright_foundation \ + libstagefright_omx \ + libstlport \ + +LOCAL_STATIC_LIBRARIES := \ + libgtest \ + libgtest_main \ + +LOCAL_C_INCLUDES := \ + bionic \ + bionic/libstdc++/include \ + external/gtest/include \ + external/stlport/stlport \ + frameworks/av/include \ + frameworks/av/media/libstagefright \ + frameworks/av/media/libstagefright/include \ + $(TOP)/frameworks/native/include/media/openmax \ + +include $(BUILD_EXECUTABLE) + # Include subdirectory makefiles # ============================================================ diff --git a/media/libstagefright/tests/Utils_test.cpp b/media/libstagefright/tests/Utils_test.cpp new file mode 100644 index 0000000..f2825dd --- /dev/null +++ b/media/libstagefright/tests/Utils_test.cpp @@ -0,0 +1,101 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "Utils_test" + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace android { + +class UtilsTest : public ::testing::Test { +}; + +TEST_F(UtilsTest, TestFourCC) { + ASSERT_EQ(FOURCC('s', 't', 'm' , 'u'), 'stmu'); +} + +TEST_F(UtilsTest, TestMathTemplates) { + ASSERT_EQ(divRound(-10, -4), 3); + ASSERT_EQ(divRound(-11, -4), 3); + ASSERT_EQ(divRound(-12, -4), 3); + ASSERT_EQ(divRound(-13, -4), 3); + ASSERT_EQ(divRound(-14, -4), 4); + + ASSERT_EQ(divRound(10, -4), -3); + ASSERT_EQ(divRound(11, -4), -3); + ASSERT_EQ(divRound(12, -4), -3); + ASSERT_EQ(divRound(13, -4), -3); + ASSERT_EQ(divRound(14, -4), -4); + + ASSERT_EQ(divRound(-10, 4), -3); + ASSERT_EQ(divRound(-11, 4), -3); + ASSERT_EQ(divRound(-12, 4), -3); + ASSERT_EQ(divRound(-13, 4), -3); + ASSERT_EQ(divRound(-14, 4), -4); + + ASSERT_EQ(divRound(10, 4), 3); + ASSERT_EQ(divRound(11, 4), 3); + ASSERT_EQ(divRound(12, 4), 3); + ASSERT_EQ(divRound(13, 4), 3); + ASSERT_EQ(divRound(14, 4), 4); + + ASSERT_EQ(divUp(-11, -4), 3); + ASSERT_EQ(divUp(-12, -4), 3); + ASSERT_EQ(divUp(-13, -4), 4); + + ASSERT_EQ(divUp(11, -4), -2); + ASSERT_EQ(divUp(12, -4), -3); + ASSERT_EQ(divUp(13, -4), -3); + + ASSERT_EQ(divUp(-11, 4), -2); + ASSERT_EQ(divUp(-12, 4), -3); + ASSERT_EQ(divUp(-13, 4), -3); + + ASSERT_EQ(divUp(11, 4), 3); + ASSERT_EQ(divUp(12, 4), 3); + ASSERT_EQ(divUp(13, 4), 4); + + ASSERT_EQ(abs(5L), 5L); + ASSERT_EQ(abs(-25), 25); + + ASSERT_EQ(min(5.6f, 6.0f), 5.6f); + ASSERT_EQ(min(6.0f, 5.6f), 5.6f); + ASSERT_EQ(min(-4.3, 8.6), -4.3); + ASSERT_EQ(min(8.6, -4.3), -4.3); + + ASSERT_EQ(max(5.6f, 6.0f), 6.0f); + ASSERT_EQ(max(6.0f, 5.6f), 6.0f); + ASSERT_EQ(max(-4.3, 8.6), 8.6); + ASSERT_EQ(max(8.6, -4.3), 8.6); + + ASSERT_EQ(periodicError(124, 100), 24); + ASSERT_EQ(periodicError(288, 100), 12); + ASSERT_EQ(periodicError(-345, 100), 45); + ASSERT_EQ(periodicError(-493, 100), 7); + ASSERT_EQ(periodicError(-550, 100), 50); + ASSERT_EQ(periodicError(-600, 100), 0); +} + +} // namespace android -- cgit v1.1 From a147b4f91143d9f2fb608e22f9fca14bbd029573 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 1 Oct 2014 21:36:51 -0700 Subject: mediarecorder: set level if setting default profile Bug: 17676461 Change-Id: If01ccd09935945d330de0842be95c3544951b6b9 --- .../libmediaplayerservice/StagefrightRecorder.cpp | 5 ++ media/libstagefright/ACodec.cpp | 53 ++++++++++++++++++++++ 2 files changed, 58 insertions(+) (limited to 'media') diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index b904aa8..17190fb 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -1243,6 +1244,10 @@ void StagefrightRecorder::setDefaultProfileIfNecessary() { if (videoCodec == VIDEO_ENCODER_H264) { ALOGI("Force to use AVC baseline profile"); setParamVideoEncoderProfile(OMX_VIDEO_AVCProfileBaseline); + // set 0 for invalid levels - this will be rejected by the + // codec if it cannot handle it during configure + setParamVideoEncoderLevel(ACodec::getAVCLevelFor( + videoFrameWidth, videoFrameHeight, videoFrameRate, videoBitRate)); } } } diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index d6fba98..b6ac2a0 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -2490,6 +2491,58 @@ status_t ACodec::setupH263EncoderParameters(const sp &msg) { return setupErrorCorrectionParameters(); } +// static +int /* OMX_VIDEO_AVCLEVELTYPE */ ACodec::getAVCLevelFor( + int width, int height, int rate, int bitrate, + OMX_VIDEO_AVCPROFILETYPE profile) { + // convert bitrate to main/baseline profile kbps equivalent + switch (profile) { + case OMX_VIDEO_AVCProfileHigh10: + bitrate = divUp(bitrate, 3000); break; + case OMX_VIDEO_AVCProfileHigh: + bitrate = divUp(bitrate, 1250); break; + default: + bitrate = divUp(bitrate, 1000); break; + } + + // convert size and rate to MBs + width = divUp(width, 16); + height = divUp(height, 16); + int mbs = width * height; + rate *= mbs; + int maxDimension = max(width, height); + + static const int limits[][5] = { + /* MBps MB dim bitrate level */ + { 1485, 99, 28, 64, OMX_VIDEO_AVCLevel1 }, + { 1485, 99, 28, 128, OMX_VIDEO_AVCLevel1b }, + { 3000, 396, 56, 192, OMX_VIDEO_AVCLevel11 }, + { 6000, 396, 56, 384, OMX_VIDEO_AVCLevel12 }, + { 11880, 396, 56, 768, OMX_VIDEO_AVCLevel13 }, + { 11880, 396, 56, 2000, OMX_VIDEO_AVCLevel2 }, + { 19800, 792, 79, 4000, OMX_VIDEO_AVCLevel21 }, + { 20250, 1620, 113, 4000, OMX_VIDEO_AVCLevel22 }, + { 40500, 1620, 113, 10000, OMX_VIDEO_AVCLevel3 }, + { 108000, 3600, 169, 14000, OMX_VIDEO_AVCLevel31 }, + { 216000, 5120, 202, 20000, OMX_VIDEO_AVCLevel32 }, + { 245760, 8192, 256, 20000, OMX_VIDEO_AVCLevel4 }, + { 245760, 8192, 256, 50000, OMX_VIDEO_AVCLevel41 }, + { 522240, 8704, 263, 50000, OMX_VIDEO_AVCLevel42 }, + { 589824, 22080, 420, 135000, OMX_VIDEO_AVCLevel5 }, + { 983040, 36864, 543, 240000, OMX_VIDEO_AVCLevel51 }, + { 2073600, 36864, 543, 240000, OMX_VIDEO_AVCLevel52 }, + }; + + for (size_t i = 0; i < ARRAY_SIZE(limits); i++) { + const int (&limit)[5] = limits[i]; + if (rate <= limit[0] && mbs <= limit[1] && maxDimension <= limit[2] + && bitrate <= limit[3]) { + return limit[4]; + } + } + return 0; +} + status_t ACodec::setupAVCEncoderParameters(const sp &msg) { int32_t bitrate, iFrameInterval; if (!msg->findInt32("bitrate", &bitrate) -- cgit v1.1 From 2245fc625910e47d1ba3c339e205c21ab58a47ad Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Thu, 2 Oct 2014 15:12:25 -0700 Subject: NuPlayerDecoder: postpone input message processing when it's not dequeued. Bug: 17622642 Change-Id: I67608121bf70d6acb152e4aa64892b11bf167e8c --- .../nuplayer/NuPlayerDecoder.cpp | 35 +++++++++++++++++----- .../nuplayer/NuPlayerDecoder.h | 4 ++- 2 files changed, 31 insertions(+), 8 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 1a066b7..037b5d2 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -185,6 +185,8 @@ void NuPlayer::Decoder::releaseAndResetMediaBuffers() { for (size_t i = 0; i < mInputBufferIsDequeued.size(); i++) { mInputBufferIsDequeued.editItemAt(i) = false; } + + mPendingInputMessages.clear(); } void NuPlayer::Decoder::requestCodecNotification() { @@ -270,7 +272,19 @@ bool NuPlayer::Decoder::handleAnInputBuffer() { ALOGI("[%s] resubmitting CSD", mComponentName.c_str()); reply->setBuffer("buffer", buffer); mCSDsToSubmit.removeAt(0); - reply->post(); + CHECK(onInputBufferFilled(reply)); + return true; + } + + while (!mPendingInputMessages.empty()) { + sp msg = *mPendingInputMessages.begin(); + if (!onInputBufferFilled(msg)) { + break; + } + mPendingInputMessages.erase(mPendingInputMessages.begin()); + } + + if (!mInputBufferIsDequeued.editItemAt(bufferIx)) { return true; } @@ -282,7 +296,7 @@ bool NuPlayer::Decoder::handleAnInputBuffer() { return true; } -void android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { +bool android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { size_t bufferIx; CHECK(msg->findSize("buffer-ix", &bufferIx)); CHECK_LT(bufferIx, mInputBuffers.size()); @@ -302,9 +316,12 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { const sp &buf = mInputBuffers[ix]; if (buf->data() == mediaBuffer->data()) { // all input buffers are dequeued on start, hence the check - CHECK(mInputBufferIsDequeued[ix]); - ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu", - mComponentName.c_str(), ix, bufferIx); + if (!mInputBufferIsDequeued[ix]) { + ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu", + mComponentName.c_str(), ix, bufferIx); + mediaBuffer->release(); + return false; + } // TRICKY: need buffer for the metadata, so instead, set // codecBuffer to the same (though incorrect) buffer to @@ -329,7 +346,7 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { if (streamErr == OK) { /* buffers are returned to hold on to */ - return; + return true; } // attempt to queue EOS @@ -394,6 +411,7 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { } } } + return true; } bool NuPlayer::Decoder::handleAnOutputBuffer() { @@ -616,7 +634,10 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { case kWhatInputBufferFilled: { if (!isStaleReply(msg)) { - onInputBufferFilled(msg); + if (!mPendingInputMessages.empty() + || !onInputBufferFilled(msg)) { + mPendingInputMessages.push_back(msg); + } } break; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index cc1bdff..dba3eee 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -80,6 +80,8 @@ private: sp mCodecLooper; sp mDecoderLooper; + List > mPendingInputMessages; + Vector > mInputBuffers; Vector > mOutputBuffers; Vector > mCSDsForCurrentFormat; @@ -98,7 +100,7 @@ private: void onConfigure(const sp &format); void onFlush(); void onResume(); - void onInputBufferFilled(const sp &msg); + bool onInputBufferFilled(const sp &msg); void onRenderBuffer(const sp &msg); void onShutdown(); -- cgit v1.1 From e47d44486f0a9f9b828b01d0fbaf84f5573f0aa2 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 30 Sep 2014 13:12:22 -0700 Subject: send available codec buffer count with codec notification Bug: 14679336 Change-Id: Id927c96a9a14dd6ecd72540f0037d5841aa32154 --- .../libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 16 ++++++++++++---- media/libstagefright/MediaCodec.cpp | 17 +++++++++++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 7814bf1..601f6b5 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -604,13 +604,21 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { case kWhatCodecNotify: { if (!isStaleReply(msg)) { - if (!mPaused) { - while (handleAnInputBuffer()) { - } + int32_t numInput, numOutput; + + if (!msg->findInt32("input-buffers", &numInput)) { + numInput = INT32_MAX; } - while (handleAnOutputBuffer()) { + if (!msg->findInt32("output-buffers", &numOutput)) { + numOutput = INT32_MAX; } + + if (!mPaused) { + while (numInput-- > 0 && handleAnInputBuffer()) {} + } + + while (numOutput-- > 0 && handleAnOutputBuffer()) {} } requestCodecNotification(); diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index b56819c..b568063 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -2141,11 +2141,24 @@ void MediaCodec::postActivityNotificationIfPossible() { return; } - if ((mFlags & (kFlagStickyError + bool isErrorOrOutputChanged = + (mFlags & (kFlagStickyError | kFlagOutputBuffersChanged - | kFlagOutputFormatChanged)) + | kFlagOutputFormatChanged)); + + if (isErrorOrOutputChanged || !mAvailPortBuffers[kPortIndexInput].empty() || !mAvailPortBuffers[kPortIndexOutput].empty()) { + mActivityNotify->setInt32("input-buffers", + mAvailPortBuffers[kPortIndexInput].size()); + + if (isErrorOrOutputChanged) { + // we want consumer to dequeue as many times as it can + mActivityNotify->setInt32("output-buffers", INT32_MAX); + } else { + mActivityNotify->setInt32("output-buffers", + mAvailPortBuffers[kPortIndexOutput].size()); + } mActivityNotify->post(); mActivityNotify.clear(); } -- cgit v1.1 From 0f694a12f92a01f95807242320bd65e88c699708 Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Thu, 2 Oct 2014 11:21:08 -0700 Subject: stagefright: fix fake-stride handling for H263 SW decoder - Use outputBufferWidth/Height to init H263 decoder. - Handle stride change when using fake stride. Bug: 17773094 Bug: 17326758 Change-Id: I66ce7b9c650383456923d75417c590e3a8a814e7 --- media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp | 5 +++-- media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp | 9 ++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp index d98fa80..1f4b6fd 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp @@ -156,7 +156,8 @@ void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) { (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE; Bool success = PVInitVideoDecoder( - mHandle, vol_data, &vol_size, 1, mWidth, mHeight, mode); + mHandle, vol_data, &vol_size, 1, + outputBufferWidth(), outputBufferHeight(), mode); if (!success) { ALOGW("PVInitVideoDecoder failed. Unsupported content?"); @@ -321,7 +322,7 @@ bool SoftMPEG4::handlePortSettingsChange() { vol_data[0] = NULL; if (!PVInitVideoDecoder( - mHandle, vol_data, &vol_size, 1, mWidth, mHeight, + mHandle, vol_data, &vol_size, 1, outputBufferWidth(), outputBufferHeight(), H263_MODE)) { notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp index 3d20a79..2f83610 100644 --- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp +++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp @@ -166,8 +166,15 @@ void SoftVideoDecoderOMXComponent::handlePortSettingsChange( bool sizeChanged = (width != mWidth || height != mHeight); bool updateCrop = (cropSettingsMode == kCropUnSet); bool cropChanged = (cropSettingsMode == kCropChanged); + bool strideChanged = false; + if (fakeStride) { + OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef; + if (def->format.video.nStride != width || def->format.video.nSliceHeight != height) { + strideChanged = true; + } + } - if (sizeChanged || cropChanged) { + if (sizeChanged || cropChanged || strideChanged) { mWidth = width; mHeight = height; -- cgit v1.1 From 0852917279f79a94907e9906d0533ae409a30f6a Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Thu, 2 Oct 2014 16:55:52 -0700 Subject: NuPlayer: don't restart AudioSink when torn down due to pause timeout. Bug: 17752358 Change-Id: I232d105480139bfc0b991bcd8e001930e577cf30 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 11 ++++++++++- media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp | 8 +++++--- media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h | 7 ++++++- 3 files changed, 21 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index ca596fd..ea60c06 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -941,6 +941,8 @@ void NuPlayer::onMessageReceived(const sp &msg) { ALOGV("Tear down audio offload, fall back to s/w path"); int64_t positionUs; CHECK(msg->findInt64("positionUs", &positionUs)); + int32_t reason; + CHECK(msg->findInt32("reason", &reason)); closeAudioSink(); mAudioDecoder.clear(); ++mAudioDecoderGeneration; @@ -952,7 +954,9 @@ void NuPlayer::onMessageReceived(const sp &msg) { mOffloadAudio = false; performSeek(positionUs, false /* needNotify */); - instantiateDecoder(true /* audio */, &mAudioDecoder); + if (reason == Renderer::kDueToError) { + instantiateDecoder(true /* audio */, &mAudioDecoder); + } } break; } @@ -1019,6 +1023,11 @@ void NuPlayer::onMessageReceived(const sp &msg) { } else { ALOGW("resume called when source is gone or not set"); } + // |mAudioDecoder| may have been released due to the pause timeout, so try to re-create + // it if needed. + if (mFlushingAudio != SHUT_DOWN) { + instantiateDecoder(true /* audio */, &mAudioDecoder); + } if (mRenderer != NULL) { mRenderer->resume(); } else { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 6d10651..958ab5b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -274,7 +274,7 @@ void NuPlayer::Renderer::onMessageReceived(const sp &msg) { case kWhatAudioOffloadTearDown: { - onAudioOffloadTearDown(); + onAudioOffloadTearDown(kDueToError); break; } @@ -285,7 +285,8 @@ void NuPlayer::Renderer::onMessageReceived(const sp &msg) { if (generation != mAudioOffloadPauseTimeoutGeneration) { break; } - onAudioOffloadTearDown(); + ALOGV("Audio Offload tear down due to pause timeout."); + onAudioOffloadTearDown(kDueToTimeout); break; } @@ -1089,7 +1090,7 @@ int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) { return durationUs; } -void NuPlayer::Renderer::onAudioOffloadTearDown() { +void NuPlayer::Renderer::onAudioOffloadTearDown(AudioOffloadTearDownReason reason) { if (mAudioOffloadTornDown) { return; } @@ -1110,6 +1111,7 @@ void NuPlayer::Renderer::onAudioOffloadTearDown() { sp notify = mNotify->dup(); notify->setInt32("what", kWhatAudioOffloadTearDown); notify->setInt64("positionUs", currentPositionUs); + notify->setInt32("reason", reason); notify->post(); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 8e6112b..4237902 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -69,6 +69,11 @@ struct NuPlayer::Renderer : public AHandler { kWhatAudioOffloadPauseTimeout = 'aOPT', }; + enum AudioOffloadTearDownReason { + kDueToError = 0, + kDueToTimeout, + }; + protected: virtual ~Renderer(); @@ -157,7 +162,7 @@ private: void onPause(); void onResume(); void onSetVideoFrameRate(float fps); - void onAudioOffloadTearDown(); + void onAudioOffloadTearDown(AudioOffloadTearDownReason reason); void notifyEOS(bool audio, status_t finalResult, int64_t delayUs = 0); void notifyFlushComplete(bool audio); -- cgit v1.1 From f2a64852a4a48c5a3d8a08ffcda20d6884586672 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Fri, 3 Oct 2014 16:12:37 -0700 Subject: MediaRecorder: only dequeue available buffers from MediaCodec Bug: 17514968 Change-Id: If232f92d163deb2440b927315c69e0c4d51ca290 --- media/libstagefright/MediaCodecSource.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index 27cd231..0fecda8 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -615,11 +615,11 @@ status_t MediaCodecSource::feedEncoderInputBuffers() { return OK; } -status_t MediaCodecSource::doMoreWork() { - status_t err; +status_t MediaCodecSource::doMoreWork(int32_t numInput, int32_t numOutput) { + status_t err = OK; if (!(mFlags & FLAG_USE_SURFACE_INPUT)) { - for (;;) { + while (numInput-- > 0) { size_t bufferIndex; err = mEncoder->dequeueInputBuffer(&bufferIndex); @@ -633,7 +633,7 @@ status_t MediaCodecSource::doMoreWork() { feedEncoderInputBuffers(); } - for (;;) { + while (numOutput-- > 0) { size_t bufferIndex; size_t offset; size_t size; @@ -805,7 +805,16 @@ void MediaCodecSource::onMessageReceived(const sp &msg) { break; } - status_t err = doMoreWork(); + int32_t numInput, numOutput; + + if (!msg->findInt32("input-buffers", &numInput)) { + numInput = INT32_MAX; + } + if (!msg->findInt32("output-buffers", &numOutput)) { + numOutput = INT32_MAX; + } + + status_t err = doMoreWork(numInput, numOutput); if (err == OK) { scheduleDoMoreWork(); -- cgit v1.1 From d7988b1a7b32e39e671f7d4e2b2d8027a1f99639 Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Fri, 3 Oct 2014 15:19:10 -0700 Subject: NuPlayer: add audioDecoderStillNeeded. Bug: 17752358 Change-Id: Ia3b3ee4df65e5564afd0723943d2d747f3a604af --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 11 ++++++++--- media/libmediaplayerservice/nuplayer/NuPlayer.h | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 5270efc..53eec91 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1048,9 +1048,9 @@ void NuPlayer::onMessageReceived(const sp &msg) { } else { ALOGW("resume called when source is gone or not set"); } - // |mAudioDecoder| may have been released due to the pause timeout, so try to re-create - // it if needed. - if (mFlushingAudio != SHUT_DOWN) { + // |mAudioDecoder| may have been released due to the pause timeout, so re-create it if + // needed. + if (audioDecoderStillNeeded() && mAudioDecoder == NULL) { instantiateDecoder(true /* audio */, &mAudioDecoder); } if (mRenderer != NULL) { @@ -1079,6 +1079,11 @@ void NuPlayer::onMessageReceived(const sp &msg) { } } +bool NuPlayer::audioDecoderStillNeeded() { + // Audio decoder is no longer needed if it's in shut/shutting down status. + return ((mFlushingAudio != SHUT_DOWN) && (mFlushingAudio != SHUTTING_DOWN_DECODER)); +} + void NuPlayer::finishFlushIfPossible() { if (mFlushingAudio != NONE && mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 8fa7269..8157733 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -203,6 +203,8 @@ private: void finishFlushIfPossible(); + bool audioDecoderStillNeeded(); + void flushDecoder( bool audio, bool needShutdown, const sp &newFormat = NULL); void updateDecoderFormatWithoutFlush(bool audio, const sp &format); -- cgit v1.1 From 8d121d41f5355b78b687f44e8d4aae4de2aa0359 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Fri, 3 Oct 2014 09:53:53 -0700 Subject: NuPlayer: wait for renderer flush before decoder shutdown Bug: 17679341 Change-Id: Ie3883686891e7ee6fb45ceb01af1eb60b559d3a0 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 101 +++++++++++---------- media/libmediaplayerservice/nuplayer/NuPlayer.h | 13 ++- .../nuplayer/NuPlayerDriver.cpp | 2 +- 3 files changed, 64 insertions(+), 52 deletions(-) (limited to 'media') 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 format) const { @@ -773,38 +755,9 @@ void NuPlayer::onMessageReceived(const sp &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 format; @@ -957,6 +910,8 @@ void NuPlayer::onMessageReceived(const sp &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 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 &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 &newFormat = NULL); void updateDecoderFormatWithoutFlush(bool audio, const sp &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 1a01d52..c57955d 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); -- cgit v1.1 From bc78bd02f0b823b18e3a4f8b8f862780b51994c0 Mon Sep 17 00:00:00 2001 From: Praveen Chavan Date: Mon, 6 Oct 2014 00:37:28 -0700 Subject: StageFrightRecorder: Enable meta-data mode for VP8 hardware encoder. Meta-data mode for input is preferred (rather required) for recording with camera v1. This capability is queried and enabled per codec; enable it for VP8 hardware encoder. Bug: 17664960 Change-Id: I4735c61670ebe0a555002cc25ef3ed823ab02f1f --- media/libmediaplayerservice/StagefrightRecorder.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'media') 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; -- cgit v1.1 From c68cc33cd94cfc97c2a7b57955ce18b0ff931f19 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Sun, 5 Oct 2014 13:15:16 -0700 Subject: Recover from errors When the AAC decoder encounters an error, the lists of submitted and consumed sizes need to be resynchronized, to prevent timestamp drift. Bug: 17638652 Change-Id: Ia6d5f48dc36be355803589e4a5796b01559942b8 --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'media') 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 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 } -- cgit v1.1 From 7985dcb06e0c29d5cc12d0c0e17e03d5d863cf53 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 7 Oct 2014 15:45:14 -0700 Subject: AudioTrack: fix AudioTrackThread crash upon exit In case of error during createTrack_l(), there is a possibility that a newly created AudioTrackThread is resumed by requestExit() just after entering the Thread class _threadLoop() but before entering the class threadLoop(). In this case, processAudioBuffer() is executed once with mCblk == 0 and we assert. Bug: 17894033. Change-Id: I93d0d0d4dbf14bcb88dad23e6ad49d2ecd47badd --- media/libmedia/AudioTrack.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'media') 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: -- cgit v1.1 From 91a3cc00db31a713a25848f345bd624ac2ad8dc5 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Tue, 7 Oct 2014 18:42:45 -0700 Subject: ACodec: only check crop rect on output port Bug: 17789956 Change-Id: I0e17660d95ac0b3b051e7f555820188d9286571a --- media/libstagefright/ACodec.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index b693625..229e688 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -3200,12 +3200,20 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { sizeof(describeParams.sMediaImage))); } + if (portIndex != kPortIndexOutput) { + // TODO: also get input crop + break; + } + OMX_CONFIG_RECTTYPE rect; InitOMXParams(&rect); - rect.nPortIndex = kPortIndexOutput; + rect.nPortIndex = portIndex; if (mOMX->getConfig( - mNode, OMX_IndexConfigCommonOutputCrop, + mNode, + (portIndex == kPortIndexOutput ? + OMX_IndexConfigCommonOutputCrop : + OMX_IndexConfigCommonInputCrop), &rect, sizeof(rect)) != OK) { rect.nLeft = 0; rect.nTop = 0; -- cgit v1.1 From 49966fff32b27f8821ebe280f25688b3c4f5f73f Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 8 Oct 2014 18:44:45 -0700 Subject: NuPlayerRenderer: adjust anchor time correctly for video only case. Bug: 17922171 Change-Id: I4c7e9e7f5ab96d3675d012ae30f78ef945394103 --- .../nuplayer/NuPlayerRenderer.cpp | 19 ++++++++++++++++++- .../libmediaplayerservice/nuplayer/NuPlayerRenderer.h | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'media') 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 &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; -- cgit v1.1 From 6e029f0ba9a3b421eb7273a095305f7998e9aa5a Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Thu, 9 Oct 2014 16:32:33 -0700 Subject: MediaCodec: fix onError and onInputBufferAvailable - don't call onInputBufferAvailable if we created an input surface - keep component name alive if an error occurs Bug: 17934966 Change-Id: I396c6e6cfd9fa589a1a95c6169492089255e6993 --- media/libstagefright/MediaCodec.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'media') 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 &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 &msg) { } if (mFlags & kFlagIsAsync) { - onInputBufferAvailable(); + if (!mHaveInputSurface) { + onInputBufferAvailable(); + } } else if (mFlags & kFlagDequeueInputPending) { CHECK(handleDequeueInputBuffer(mDequeueInputReplyID)); @@ -1130,6 +1134,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { } else { CHECK_EQ(mState, RELEASING); setState(UNINITIALIZED); + mComponentName.clear(); } (new AMessage)->postReply(mReplyID); @@ -1339,12 +1344,12 @@ void MediaCodec::onMessageReceived(const sp &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 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 &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. -- cgit v1.1 From 9c78328f4dfd2c8a1dd5d31010f10ffcd762f04b Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 9 Oct 2014 21:33:53 -0700 Subject: handle case OMX_AUDIO_CodingG711 in ACodec::getPortFormat Bug: 17935293 Change-Id: I8eab0acf55df6934e05947b0dbdd1fd456130088 --- media/libstagefright/ACodec.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index b693625..a6c9dcc 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -3458,6 +3458,27 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { break; } + case OMX_AUDIO_CodingG711: + { + OMX_AUDIO_PARAM_PCMMODETYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + CHECK_EQ((status_t)OK, mOMX->getParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioPcm, + ¶ms, + sizeof(params))); + + // mime type: + // MEDIA_MIMETYPE_AUDIO_G711_ALAW or + // MEDIA_MIMETYPE_AUDIO_G711_MLAW + notify->setString("mime", audioDef->cMIMEType); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSamplingRate); + break; + } + default: ALOGE("UNKNOWN AUDIO CODING: %d\n", audioDef->eEncoding); TRESPASS(); -- cgit v1.1 From f393c33e65ae51a7cf168b4e15771b152f996b32 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Fri, 10 Oct 2014 18:13:00 -0700 Subject: ACodec: process deferred messages when entering Loaded state. Bug: 17792260 Change-Id: Ie8154cf41be5672fc8a9f3a2a82b7ede0a8b828f --- media/libstagefright/ACodec.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index b6ac2a0..b14efd7 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -4551,6 +4551,8 @@ void ACodec::LoadedState::stateEntered() { onShutdown(keepComponentAllocated); } mCodec->mExplicitShutdown = false; + + mCodec->processDeferredMessages(); } void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) { -- cgit v1.1 From 667623ac75700fc1bb4829b8275c4fc29c631fe9 Mon Sep 17 00:00:00 2001 From: Guang Zhu Date: Mon, 13 Oct 2014 00:02:20 +0000 Subject: Revert "handle case OMX_AUDIO_CodingG711 in ACodec::getPortFormat" Bug: 17935293 fix 64-bit builds This reverts commit 9c78328f4dfd2c8a1dd5d31010f10ffcd762f04b. Change-Id: Ifbc499342fb47fd67cae02a79cb900e701caed68 --- media/libstagefright/ACodec.cpp | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index a6c9dcc..b693625 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -3458,27 +3458,6 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { break; } - case OMX_AUDIO_CodingG711: - { - OMX_AUDIO_PARAM_PCMMODETYPE params; - InitOMXParams(¶ms); - params.nPortIndex = portIndex; - - CHECK_EQ((status_t)OK, mOMX->getParameter( - mNode, - (OMX_INDEXTYPE)OMX_IndexParamAudioPcm, - ¶ms, - sizeof(params))); - - // mime type: - // MEDIA_MIMETYPE_AUDIO_G711_ALAW or - // MEDIA_MIMETYPE_AUDIO_G711_MLAW - notify->setString("mime", audioDef->cMIMEType); - notify->setInt32("channel-count", params.nChannels); - notify->setInt32("sample-rate", params.nSamplingRate); - break; - } - default: ALOGE("UNKNOWN AUDIO CODING: %d\n", audioDef->eEncoding); TRESPASS(); -- cgit v1.1 From 10d023beb0544591d0f5ff556f7f67356f0d9189 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Sun, 12 Oct 2014 22:28:11 -0700 Subject: handle case OMX_AUDIO_CodingG711 in ACodec::getPortFormat Bug: 17935293 Change-Id: Id09190ae813aa9e00a3c1ef6fb8a1bd3021deb6e --- media/libstagefright/ACodec.cpp | 26 +++++++++++++++++++++++ media/libstagefright/codecs/g711/dec/SoftG711.cpp | 9 +++++++- 2 files changed, 34 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index b693625..bf4ecdf 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -3458,6 +3458,32 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { break; } + case OMX_AUDIO_CodingG711: + { + OMX_AUDIO_PARAM_PCMMODETYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + CHECK_EQ((status_t)OK, mOMX->getParameter( + mNode, + (OMX_INDEXTYPE)OMX_IndexParamAudioPcm, + ¶ms, + 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(); 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; -- cgit v1.1 From dab70a065a8e972d272ed948e77cf2cd0f1525e1 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Sat, 11 Oct 2014 15:33:00 -0700 Subject: NuPlayerDriver: request seek notification when prepare*() is called in STOPPED state. Bug: 17596535 Change-Id: Ib43f91f9b0d0a52112aa1fa8352adac15aaf80f8 --- media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 1a01d52..776fd92 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -191,7 +191,7 @@ status_t NuPlayerDriver::prepare_l() { mAtEOS = false; mState = STATE_STOPPED_AND_PREPARING; mIsAsyncPrepare = false; - mPlayer->seekToAsync(0); + mPlayer->seekToAsync(0, true /* needNotify */); while (mState == STATE_STOPPED_AND_PREPARING) { mCondition.wait(mLock); } @@ -216,7 +216,7 @@ status_t NuPlayerDriver::prepareAsync() { mAtEOS = false; mState = STATE_STOPPED_AND_PREPARING; mIsAsyncPrepare = true; - mPlayer->seekToAsync(0); + mPlayer->seekToAsync(0, true /* needNotify */); return OK; default: return INVALID_OPERATION; -- cgit v1.1 From a73d9e0b3d171d2bfcd9eb07df9d6d36ae74df57 Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Wed, 8 Oct 2014 15:13:29 -0700 Subject: NuPlayer: query current position from NuPlayerRenderer. Bug: 17653702 Change-Id: Ie0b1f92420b071a0cfcd389f5e7917a54d332541 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 48 ++--- media/libmediaplayerservice/nuplayer/NuPlayer.h | 4 +- .../nuplayer/NuPlayerDriver.cpp | 94 ++------- .../nuplayer/NuPlayerDriver.h | 8 +- .../nuplayer/NuPlayerRenderer.cpp | 232 +++++++++++---------- .../nuplayer/NuPlayerRenderer.h | 33 ++- 6 files changed, 194 insertions(+), 225 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 1c73995..eb5821b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -151,7 +151,6 @@ private: NuPlayer::NuPlayer() : mUIDValid(false), mSourceFlags(0), - mCurrentPositionUs(0), mVideoIsAVC(false), mOffloadAudio(false), mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER), @@ -169,7 +168,6 @@ NuPlayer::NuPlayer() mFlushingVideo(NONE), mSkipRenderingAudioUntilMediaTimeUs(-1ll), mSkipRenderingVideoUntilMediaTimeUs(-1ll), - mVideoLateByUs(0ll), mNumFramesTotal(0ll), mNumFramesDropped(0ll), mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW), @@ -546,8 +544,11 @@ void NuPlayer::onMessageReceived(const sp &msg) { // the extractor may not yet be started and will assert. // If the video decoder is not set (perhaps audio only in this case) // do not perform a seek as it is not needed. - mDeferredActions.push_back( - new SeekAction(mCurrentPositionUs, false /* needNotify */)); + int64_t currentPositionUs = 0; + if (getCurrentPosition(¤tPositionUs) == OK) { + mDeferredActions.push_back( + new SeekAction(currentPositionUs, false /* needNotify */)); + } } // If there is a new surface texture, instantiate decoders @@ -581,7 +582,6 @@ void NuPlayer::onMessageReceived(const sp &msg) { mVideoEOS = false; mSkipRenderingAudioUntilMediaTimeUs = -1; mSkipRenderingVideoUntilMediaTimeUs = -1; - mVideoLateByUs = 0; mNumFramesTotal = 0; mNumFramesDropped = 0; mStarted = true; @@ -889,22 +889,6 @@ void NuPlayer::onMessageReceived(const sp &msg) { && (mVideoEOS || mVideoDecoder == NULL)) { notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); } - } else if (what == Renderer::kWhatPosition) { - int64_t positionUs; - CHECK(msg->findInt64("positionUs", &positionUs)); - mCurrentPositionUs = positionUs; - - CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs)); - - if (mDriver != NULL) { - sp driver = mDriver.promote(); - if (driver != NULL) { - driver->notifyPosition(positionUs); - - driver->notifyFrameStats( - mNumFramesTotal, mNumFramesDropped); - } - } } else if (what == Renderer::kWhatFlushComplete) { int32_t audio; CHECK(msg->findInt32("audio", &audio)); @@ -1053,10 +1037,6 @@ void NuPlayer::handleFlushComplete(bool audio, bool isDecoder) { case FLUSHING_DECODER: { *state = FLUSHED; - - if (!audio) { - mVideoLateByUs = 0; - } break; } @@ -1066,7 +1046,6 @@ void NuPlayer::handleFlushComplete(bool audio, bool isDecoder) { 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(); @@ -1487,7 +1466,7 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { dropAccessUnit = false; if (!audio && !(mSourceFlags & Source::FLAG_SECURE) - && mVideoLateByUs > 100000ll + && mRenderer->getVideoLateByUs() > 100000ll && mVideoIsAVC && !IsAVCReferenceFrame(accessUnit)) { dropAccessUnit = true; @@ -1822,6 +1801,20 @@ status_t NuPlayer::selectTrack(size_t trackIndex, bool select) { return err; } +status_t NuPlayer::getCurrentPosition(int64_t *mediaUs) { + sp renderer = mRenderer; + if (renderer == NULL) { + return NO_INIT; + } + + return renderer->getCurrentPosition(mediaUs); +} + +void NuPlayer::getStats(int64_t *numFramesTotal, int64_t *numFramesDropped) { + *numFramesTotal = mNumFramesTotal; + *numFramesDropped = mNumFramesDropped; +} + sp NuPlayer::getFileMeta() { return mSource->getFileFormatMeta(); } @@ -1879,7 +1872,6 @@ void NuPlayer::performSeek(int64_t seekTimeUs, bool needNotify) { if (mDriver != NULL) { sp driver = mDriver.promote(); if (driver != NULL) { - driver->notifyPosition(seekTimeUs); if (needNotify) { driver->notifySeekComplete(); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 1b9a756..c61510c 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -67,6 +67,8 @@ struct NuPlayer : public AHandler { status_t getTrackInfo(Parcel* reply) const; status_t getSelectedTrack(int32_t type, Parcel* reply) const; status_t selectTrack(size_t trackIndex, bool select); + status_t getCurrentPosition(int64_t *mediaUs); + void getStats(int64_t *mNumFramesTotal, int64_t *mNumFramesDropped); sp getFileMeta(); @@ -126,7 +128,6 @@ private: sp mSource; uint32_t mSourceFlags; sp mNativeWindow; - int64_t mCurrentPositionUs; sp mAudioSink; sp mVideoDecoder; bool mVideoIsAVC; @@ -179,7 +180,6 @@ private: int64_t mSkipRenderingAudioUntilMediaTimeUs; int64_t mSkipRenderingVideoUntilMediaTimeUs; - int64_t mVideoLateByUs; int64_t mNumFramesTotal, mNumFramesDropped; int32_t mVideoScalingMode; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index c57955d..6a80313 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -38,10 +39,7 @@ NuPlayerDriver::NuPlayerDriver() mSetSurfaceInProgress(false), mDurationUs(-1), mPositionUs(-1), - mNotifyTimeRealUs(-1), - mPauseStartedTimeUs(-1), - mNumFramesTotal(0), - mNumFramesDropped(0), + mSeekInProgress(false), mLooper(new ALooper), mPlayerFlags(0), mAtEOS(false), @@ -276,14 +274,6 @@ status_t NuPlayerDriver::start() { mPositionUs = -1; } else { mPlayer->resume(); - if (mNotifyTimeRealUs != -1) { - // Pause time must be set if here by setPauseStartedTimeIfNeeded(). - //CHECK(mPauseStartedTimeUs != -1); - - // if no seek occurs, adjust our notify time so that getCurrentPosition() - // is continuous if read immediately after calling start(). - mNotifyTimeRealUs += ALooper::GetNowUs() - mPauseStartedTimeUs; - } } break; } @@ -293,7 +283,6 @@ status_t NuPlayerDriver::start() { } mState = STATE_RUNNING; - mPauseStartedTimeUs = -1; return OK; } @@ -322,7 +311,6 @@ status_t NuPlayerDriver::stop() { default: return INVALID_OPERATION; } - setPauseStartedTimeIfNeeded(); return OK; } @@ -336,7 +324,6 @@ status_t NuPlayerDriver::pause() { return OK; case STATE_RUNNING: - setPauseStartedTimeIfNeeded(); mState = STATE_PAUSED; notifyListener_l(MEDIA_PAUSED); mPlayer->pause(); @@ -374,6 +361,7 @@ status_t NuPlayerDriver::seekTo(int msec) { case STATE_PAUSED: { mAtEOS = false; + mSeekInProgress = true; // seeks can take a while, so we essentially paused notifyListener_l(MEDIA_PAUSED); mPlayer->seekToAsync(seekTimeUs, true /* needNotify */); @@ -385,44 +373,23 @@ status_t NuPlayerDriver::seekTo(int msec) { } mPositionUs = seekTimeUs; - mNotifyTimeRealUs = -1; return OK; } status_t NuPlayerDriver::getCurrentPosition(int *msec) { - Mutex::Autolock autoLock(mLock); + int64_t tempUs = 0; + status_t ret = mPlayer->getCurrentPosition(&tempUs); - if (mPositionUs < 0) { - // mPositionUs is the media time. - // It is negative under these cases - // (1) == -1 after reset, or very first playback, no stream notification yet. - // (2) == -1 start after end of stream, no stream notification yet. - // (3) == large negative # after ~292,471 years of continuous playback. - - //CHECK_EQ(mPositionUs, -1); - *msec = 0; - } else if (mNotifyTimeRealUs == -1) { - // A seek has occurred just occurred, no stream notification yet. - // mPositionUs (>= 0) is the new media position. - *msec = mPositionUs / 1000; + Mutex::Autolock autoLock(mLock); + // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which + // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a + // position value that's different the seek to position. + if (ret != OK || mSeekInProgress) { + tempUs = (mPositionUs <= 0) ? 0 : mPositionUs; } else { - // mPosition must be valid (i.e. >= 0) by the first check above. - // We're either playing or have pause time set: mPauseStartedTimeUs is >= 0 - //LOG_ALWAYS_FATAL_IF( - // !isPlaying() && mPauseStartedTimeUs < 0, - // "Player in non-playing mState(%d) and mPauseStartedTimeUs(%lld) < 0", - // mState, (long long)mPauseStartedTimeUs); - ALOG_ASSERT(mNotifyTimeRealUs >= 0); - int64_t nowUs = - (isPlaying() ? ALooper::GetNowUs() : mPauseStartedTimeUs); - *msec = (mPositionUs + nowUs - mNotifyTimeRealUs + 500ll) / 1000; - // It is possible for *msec to be negative if the media position is > 596 hours. - // but we turn on this checking in NDEBUG == 0 mode. - ALOG_ASSERT(*msec >= 0); - ALOGV("getCurrentPosition nowUs(%lld)", (long long)nowUs); + mPositionUs = tempUs; } - ALOGV("getCurrentPosition returning(%d) mPositionUs(%lld) mNotifyRealTimeUs(%lld)", - *msec, (long long)mPositionUs, (long long)mNotifyTimeRealUs); + *msec = (int)divRound(tempUs, (int64_t)(1000)); return OK; } @@ -605,17 +572,10 @@ void NuPlayerDriver::notifyDuration(int64_t durationUs) { mDurationUs = durationUs; } -void NuPlayerDriver::notifyPosition(int64_t positionUs) { - Mutex::Autolock autoLock(mLock); - if (isPlaying()) { - mPositionUs = positionUs; - mNotifyTimeRealUs = ALooper::GetNowUs(); - } -} - void NuPlayerDriver::notifySeekComplete() { ALOGV("notifySeekComplete(%p)", this); Mutex::Autolock autoLock(mLock); + mSeekInProgress = false; notifySeekComplete_l(); } @@ -636,26 +596,21 @@ void NuPlayerDriver::notifySeekComplete_l() { notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED); } -void NuPlayerDriver::notifyFrameStats( - int64_t numFramesTotal, int64_t numFramesDropped) { - Mutex::Autolock autoLock(mLock); - mNumFramesTotal = numFramesTotal; - mNumFramesDropped = numFramesDropped; -} - status_t NuPlayerDriver::dump( int fd, const Vector & /* args */) const { - Mutex::Autolock autoLock(mLock); + int64_t numFramesTotal; + int64_t numFramesDropped; + mPlayer->getStats(&numFramesTotal, &numFramesDropped); FILE *out = fdopen(dup(fd), "w"); fprintf(out, " NuPlayer\n"); fprintf(out, " numFramesTotal(%" PRId64 "), numFramesDropped(%" PRId64 "), " "percentageDropped(%.2f)\n", - mNumFramesTotal, - mNumFramesDropped, - mNumFramesTotal == 0 - ? 0.0 : (double)mNumFramesDropped / mNumFramesTotal); + numFramesTotal, + numFramesDropped, + numFramesTotal == 0 + ? 0.0 : (double)numFramesDropped / numFramesTotal); fclose(out); out = NULL; @@ -690,7 +645,6 @@ void NuPlayerDriver::notifyListener_l( case MEDIA_ERROR: { mAtEOS = true; - setPauseStartedTimeIfNeeded(); break; } @@ -758,10 +712,4 @@ void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) { mPlayerFlags = flags; } -void NuPlayerDriver::setPauseStartedTimeIfNeeded() { - if (mPauseStartedTimeUs == -1) { - mPauseStartedTimeUs = ALooper::GetNowUs(); - } -} - } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index f2bd431..5cba7d9 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -68,10 +68,8 @@ struct NuPlayerDriver : public MediaPlayerInterface { void notifyResetComplete(); void notifySetSurfaceComplete(); void notifyDuration(int64_t durationUs); - void notifyPosition(int64_t positionUs); void notifySeekComplete(); void notifySeekComplete_l(); - void notifyFrameStats(int64_t numFramesTotal, int64_t numFramesDropped); void notifyListener(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL); void notifyFlagsChanged(uint32_t flags); @@ -106,10 +104,7 @@ private: bool mSetSurfaceInProgress; int64_t mDurationUs; int64_t mPositionUs; - int64_t mNotifyTimeRealUs; - int64_t mPauseStartedTimeUs; - int64_t mNumFramesTotal; - int64_t mNumFramesDropped; + bool mSeekInProgress; // <<< sp mLooper; @@ -125,7 +120,6 @@ private: status_t prepare_l(); void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL); - void setPauseStartedTimeIfNeeded(); DISALLOW_EVIL_CONSTRUCTORS(NuPlayerDriver); }; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index e5c64f6..7b9dbb7 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -63,22 +64,21 @@ NuPlayer::Renderer::Renderer( mDrainVideoQueuePending(false), mAudioQueueGeneration(0), mVideoQueueGeneration(0), - mFirstAnchorTimeMediaUs(-1), - mAnchorTimeMediaUs(-1), - mAnchorTimeRealUs(-1), - mFlushingAudio(false), - mFlushingVideo(false), + mAudioFirstAnchorTimeMediaUs(-1), + mVideoAnchorTimeMediaUs(-1), + mVideoAnchorTimeRealUs(-1), + mVideoLateByUs(0ll), mHasAudio(false), mHasVideo(false), + mPauseStartedTimeRealUs(-1), + mFlushingAudio(false), + mFlushingVideo(false), mSyncQueues(false), mPaused(false), - mPauseStartedTimeRealUs(-1), mVideoSampleReceived(false), mVideoRenderingStarted(false), mVideoRenderingStartGeneration(0), mAudioRenderingStartGeneration(0), - mLastPositionUpdateUs(-1ll), - mVideoLateByUs(0ll), mAudioOffloadPauseTimeoutGeneration(0), mAudioOffloadTornDown(false) { readProperties(); @@ -137,9 +137,9 @@ void NuPlayer::Renderer::signalTimeDiscontinuity() { Mutex::Autolock autoLock(mLock); // CHECK(mAudioQueue.empty()); // CHECK(mVideoQueue.empty()); - mFirstAnchorTimeMediaUs = -1; - mAnchorTimeMediaUs = -1; - mAnchorTimeRealUs = -1; + setAudioFirstAnchorTime(-1); + setVideoAnchorTime(-1, -1); + setVideoLateByUs(0); mSyncQueues = false; } @@ -165,6 +165,78 @@ void NuPlayer::Renderer::setVideoFrameRate(float fps) { msg->post(); } +status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) { + return getCurrentPosition(mediaUs, ALooper::GetNowUs()); +} + +status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs, int64_t nowUs) { + Mutex::Autolock autoLock(mTimeLock); + if (!mHasAudio && !mHasVideo) { + return NO_INIT; + } + + int64_t positionUs = 0; + if (!mHasAudio) { + if (mVideoAnchorTimeMediaUs < 0) { + return NO_INIT; + } + positionUs = (nowUs - mVideoAnchorTimeRealUs) + mVideoAnchorTimeMediaUs; + + if (mPauseStartedTimeRealUs != -1) { + positionUs -= (nowUs - mPauseStartedTimeRealUs); + } + } else { + if (mAudioFirstAnchorTimeMediaUs < 0) { + return NO_INIT; + } + positionUs = mAudioFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs); + } + *mediaUs = (positionUs <= 0) ? 0 : positionUs; + return OK; +} + +void NuPlayer::Renderer::setHasMedia(bool audio) { + Mutex::Autolock autoLock(mTimeLock); + if (audio) { + mHasAudio = true; + } else { + mHasVideo = true; + } +} + +void NuPlayer::Renderer::setAudioFirstAnchorTime(int64_t mediaUs) { + Mutex::Autolock autoLock(mTimeLock); + mAudioFirstAnchorTimeMediaUs = mediaUs; +} + +void NuPlayer::Renderer::setAudioFirstAnchorTimeIfNeeded(int64_t mediaUs) { + Mutex::Autolock autoLock(mTimeLock); + if (mAudioFirstAnchorTimeMediaUs == -1) { + mAudioFirstAnchorTimeMediaUs = mediaUs; + } +} + +void NuPlayer::Renderer::setVideoAnchorTime(int64_t mediaUs, int64_t realUs) { + Mutex::Autolock autoLock(mTimeLock); + mVideoAnchorTimeMediaUs = mediaUs; + mVideoAnchorTimeRealUs = realUs; +} + +void NuPlayer::Renderer::setVideoLateByUs(int64_t lateUs) { + Mutex::Autolock autoLock(mTimeLock); + mVideoLateByUs = lateUs; +} + +int64_t NuPlayer::Renderer::getVideoLateByUs() { + Mutex::Autolock autoLock(mTimeLock); + return mVideoLateByUs; +} + +void NuPlayer::Renderer::setPauseStartedTimeRealUs(int64_t realUs) { + Mutex::Autolock autoLock(mTimeLock); + mPauseStartedTimeRealUs = realUs; +} + void NuPlayer::Renderer::onMessageReceived(const sp &msg) { switch (msg->what()) { case kWhatStopAudioSink: @@ -388,16 +460,7 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { int64_t mediaTimeUs; CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); - if (mFirstAnchorTimeMediaUs == -1) { - mFirstAnchorTimeMediaUs = mediaTimeUs; - } - - int64_t nowUs = ALooper::GetNowUs(); - mAnchorTimeMediaUs = - mFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs); - mAnchorTimeRealUs = nowUs; - - notifyPosition(); + setAudioFirstAnchorTimeIfNeeded(mediaTimeUs); } size_t copy = entry->mBuffer->size() - entry->mOffset; @@ -468,15 +531,8 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { int64_t mediaTimeUs; CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); - if (mFirstAnchorTimeMediaUs == -1) { - mFirstAnchorTimeMediaUs = mediaTimeUs; - } - mAnchorTimeMediaUs = mediaTimeUs; - - int64_t nowUs = ALooper::GetNowUs(); - mAnchorTimeRealUs = nowUs + getPendingAudioPlayoutDurationUs(nowUs); - notifyPosition(); + setAudioFirstAnchorTimeIfNeeded(mediaTimeUs); } size_t copy = entry->mBuffer->size() - entry->mOffset; @@ -534,6 +590,14 @@ int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) { return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs); } +int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) { + int64_t currentPositionUs; + if (getCurrentPosition(¤tPositionUs, nowUs) != OK) { + currentPositionUs = 0; + } + return (mediaTimeUs - currentPositionUs) + nowUs; +} + void NuPlayer::Renderer::postDrainVideoQueue() { if (mDrainVideoQueuePending || mSyncQueues @@ -568,21 +632,11 @@ void NuPlayer::Renderer::postDrainVideoQueue() { int64_t mediaTimeUs; CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); - if (mFirstAnchorTimeMediaUs == -1 && !mHasAudio) { - mFirstAnchorTimeMediaUs = mediaTimeUs; - } - if (mAnchorTimeMediaUs < 0) { - if (!mHasAudio) { - mAnchorTimeMediaUs = mediaTimeUs; - mAnchorTimeRealUs = nowUs; - if (!mPaused || mVideoSampleReceived) { - notifyPosition(); - } - } + if (mVideoAnchorTimeMediaUs < 0) { + setVideoAnchorTime(mediaTimeUs, nowUs); realTimeUs = nowUs; } else { - realTimeUs = - (mediaTimeUs - mAnchorTimeMediaUs) + mAnchorTimeRealUs; + realTimeUs = getRealTimeUs(mediaTimeUs, nowUs); } } @@ -618,10 +672,11 @@ void NuPlayer::Renderer::onDrainVideoQueue() { mVideoQueue.erase(mVideoQueue.begin()); entry = NULL; - mVideoLateByUs = 0ll; + setVideoLateByUs(0); return; } + int64_t nowUs = -1; int64_t realTimeUs; if (mFlags & FLAG_REAL_TIME) { CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs)); @@ -629,13 +684,17 @@ void NuPlayer::Renderer::onDrainVideoQueue() { int64_t mediaTimeUs; CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); - realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs; + nowUs = ALooper::GetNowUs(); + realTimeUs = getRealTimeUs(mediaTimeUs, nowUs); } bool tooLate = false; if (!mPaused) { - mVideoLateByUs = ALooper::GetNowUs() - realTimeUs; + if (nowUs == -1) { + nowUs = ALooper::GetNowUs(); + } + setVideoLateByUs(nowUs - realTimeUs); tooLate = (mVideoLateByUs > 40000); if (tooLate) { @@ -644,13 +703,14 @@ void NuPlayer::Renderer::onDrainVideoQueue() { } else { ALOGV("rendering video at media time %.2f secs", (mFlags & FLAG_REAL_TIME ? realTimeUs : - (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6); + (realTimeUs + mVideoAnchorTimeMediaUs - mVideoAnchorTimeRealUs)) / 1E6); } } else { - mVideoLateByUs = 0ll; - if (!mHasAudio && !mVideoSampleReceived) { - mAnchorTimeMediaUs = -1; - mAnchorTimeRealUs = -1; + setVideoLateByUs(0); + if (!mVideoSampleReceived) { + // This will ensure that the first frame after a flush won't be used as anchor + // when renderer is in paused state, because resume can happen any time after seek. + setVideoAnchorTime(-1, -1); } } @@ -693,10 +753,9 @@ void NuPlayer::Renderer::onQueueBuffer(const sp &msg) { int32_t audio; CHECK(msg->findInt32("audio", &audio)); - if (audio) { - mHasAudio = true; - } else { - mHasVideo = true; + setHasMedia(audio); + + if (mHasVideo) { if (mVideoScheduler == NULL) { mVideoScheduler = new VideoFrameScheduler(); mVideoScheduler->init(); @@ -837,9 +896,7 @@ void NuPlayer::Renderer::onFlush(const sp &msg) { { Mutex::Autolock autoLock(mLock); syncQueuesDone_l(); - if (!mHasAudio) { - mPauseStartedTimeRealUs = -1; - } + setPauseStartedTimeRealUs(-1); } ALOGV("flushing %s", audio ? "audio" : "video"); @@ -852,7 +909,7 @@ void NuPlayer::Renderer::onFlush(const sp &msg) { prepareForMediaRenderingStart(); if (offloadingAudio()) { - mFirstAnchorTimeMediaUs = -1; + setAudioFirstAnchorTime(-1); } } @@ -943,42 +1000,6 @@ void NuPlayer::Renderer::onDisableOffloadAudio() { ++mAudioQueueGeneration; } -void NuPlayer::Renderer::notifyPosition() { - // notifyPosition() must be called only after setting mAnchorTimeRealUs - // and mAnchorTimeMediaUs, and must not be paused as it extrapolates position. - //CHECK_GE(mAnchorTimeRealUs, 0); - //CHECK_GE(mAnchorTimeMediaUs, 0); - //CHECK(!mPaused || !mHasAudio); // video-only does display in paused mode. - - int64_t nowUs = ALooper::GetNowUs(); - - if (mLastPositionUpdateUs >= 0 - && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) { - return; - } - mLastPositionUpdateUs = nowUs; - - int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs; - - //ALOGD("notifyPosition: positionUs(%lld) nowUs(%lld) mAnchorTimeRealUs(%lld)" - // " mAnchorTimeMediaUs(%lld) mFirstAnchorTimeMediaUs(%lld)", - // (long long)positionUs, (long long)nowUs, (long long)mAnchorTimeRealUs, - // (long long)mAnchorTimeMediaUs, (long long)mFirstAnchorTimeMediaUs); - - // Due to adding the latency to mAnchorTimeRealUs in onDrainAudioQueue(), - // positionUs may be less than the first media time. This is avoided - // here to prevent potential retrograde motion of the position bar - // when starting up after a seek. - if (positionUs < mFirstAnchorTimeMediaUs) { - positionUs = mFirstAnchorTimeMediaUs; - } - sp notify = mNotify->dup(); - notify->setInt32("what", kWhatPosition); - notify->setInt64("positionUs", positionUs); - notify->setInt64("videoLateByUs", mVideoLateByUs); - notify->post(); -} - void NuPlayer::Renderer::onPause() { if (mPaused) { ALOGW("Renderer::onPause() called while already paused!"); @@ -990,9 +1011,7 @@ void NuPlayer::Renderer::onPause() { ++mVideoQueueGeneration; prepareForMediaRenderingStart(); mPaused = true; - if (!mHasAudio) { - mPauseStartedTimeRealUs = ALooper::GetNowUs(); - } + setPauseStartedTimeRealUs(ALooper::GetNowUs()); } mDrainAudioQueuePending = false; @@ -1021,9 +1040,11 @@ void NuPlayer::Renderer::onResume() { Mutex::Autolock autoLock(mLock); mPaused = false; - if (!mHasAudio && mPauseStartedTimeRealUs != -1) { - mAnchorTimeRealUs += ALooper::GetNowUs() - mPauseStartedTimeRealUs; - mPauseStartedTimeRealUs = -1; + if (mPauseStartedTimeRealUs != -1) { + int64_t newAnchorRealUs = + mVideoAnchorTimeRealUs + ALooper::GetNowUs() - mPauseStartedTimeRealUs; + setVideoAnchorTime(mVideoAnchorTimeMediaUs, newAnchorRealUs); + setPauseStartedTimeRealUs(-1); } if (!mAudioQueue.empty()) { @@ -1045,7 +1066,6 @@ void NuPlayer::Renderer::onSetVideoFrameRate(float fps) { // TODO: Remove unnecessary calls to getPlayedOutAudioDurationUs() // as it acquires locks and may query the audio driver. // -// Some calls are not needed since notifyPosition() doesn't always deliver a message. // Some calls could conceivably retrieve extrapolated data instead of // accessing getTimestamp() or getPosition() every time a data buffer with // a media time is received. @@ -1113,15 +1133,11 @@ void NuPlayer::Renderer::onAudioOffloadTearDown(AudioOffloadTearDownReason reaso } mAudioOffloadTornDown = true; - int64_t firstAudioTimeUs; - { - Mutex::Autolock autoLock(mLock); - firstAudioTimeUs = mFirstAnchorTimeMediaUs; + int64_t currentPositionUs; + if (getCurrentPosition(¤tPositionUs) != OK) { + currentPositionUs = 0; } - int64_t currentPositionUs = - firstAudioTimeUs + getPlayedOutAudioDurationUs(ALooper::GetNowUs()); - mAudioSink->stop(); mAudioSink->flush(); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index d27c238..db1dab6 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -59,6 +59,17 @@ struct NuPlayer::Renderer : public AHandler { void setVideoFrameRate(float fps); + // Following setters and getters are protected by mTimeLock. + status_t getCurrentPosition(int64_t *mediaUs); + status_t getCurrentPosition(int64_t *mediaUs, int64_t nowUs); + void setHasMedia(bool audio); + void setAudioFirstAnchorTime(int64_t mediaUs); + void setAudioFirstAnchorTimeIfNeeded(int64_t mediaUs); + void setVideoAnchorTime(int64_t mediaUs, int64_t realUs); + void setVideoLateByUs(int64_t lateUs); + int64_t getVideoLateByUs(); + void setPauseStartedTimeRealUs(int64_t realUs); + enum { kWhatEOS = 'eos ', kWhatFlushComplete = 'fluC', @@ -117,27 +128,33 @@ private: int32_t mAudioQueueGeneration; int32_t mVideoQueueGeneration; - int64_t mFirstAnchorTimeMediaUs; - int64_t mAnchorTimeMediaUs; - int64_t mAnchorTimeRealUs; + Mutex mTimeLock; + // |mTimeLock| protects the following 7 member vars that are related to time. + // Note: those members are only written on Renderer thread, so reading on Renderer thread + // doesn't need to be protected. Otherwise accessing those members must be protected by + // |mTimeLock|. + // TODO: move those members to a seperated media clock class. + int64_t mAudioFirstAnchorTimeMediaUs; + int64_t mVideoAnchorTimeMediaUs; + int64_t mVideoAnchorTimeRealUs; + int64_t mVideoLateByUs; + bool mHasAudio; + bool mHasVideo; + int64_t mPauseStartedTimeRealUs; Mutex mFlushLock; // protects the following 2 member vars. bool mFlushingAudio; bool mFlushingVideo; - bool mHasAudio; - bool mHasVideo; bool mSyncQueues; bool mPaused; - int64_t mPauseStartedTimeRealUs; bool mVideoSampleReceived; bool mVideoRenderingStarted; int32_t mVideoRenderingStartGeneration; int32_t mAudioRenderingStartGeneration; int64_t mLastPositionUpdateUs; - int64_t mVideoLateByUs; int32_t mAudioOffloadPauseTimeoutGeneration; bool mAudioOffloadTornDown; @@ -149,6 +166,8 @@ private: int64_t getPlayedOutAudioDurationUs(int64_t nowUs); void postDrainAudioQueue_l(int64_t delayUs = 0); + int64_t getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs); + void onDrainVideoQueue(); void postDrainVideoQueue(); -- cgit v1.1 From 512e979284de984427e5b2f73b9054ae1b5e2b0a Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 10 Oct 2014 17:14:17 -0700 Subject: stagefright: support passing GraphicBuffer in metadata buffer Bug: 17935149 Change-Id: I6bb5dd654e498a7153410afc052c2c8f7f35e44d --- media/libstagefright/include/OMXNodeInstance.h | 4 +- media/libstagefright/omx/GraphicBufferSource.cpp | 52 ++++++++++++++++++------ media/libstagefright/omx/GraphicBufferSource.h | 5 ++- media/libstagefright/omx/OMXNodeInstance.cpp | 35 +++++++++++++--- 4 files changed, 75 insertions(+), 21 deletions(-) (limited to 'media') diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h index dc6d410..24d431c 100644 --- a/media/libstagefright/include/OMXNodeInstance.h +++ b/media/libstagefright/include/OMXNodeInstance.h @@ -182,7 +182,9 @@ private: OMX_IN OMX_PTR pAppData, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer); - status_t storeMetaDataInBuffers_l(OMX_U32 portIndex, OMX_BOOL enable); + status_t storeMetaDataInBuffers_l( + OMX_U32 portIndex, OMX_BOOL enable, + OMX_BOOL useGraphicBuffer, OMX_BOOL *usingGraphicBufferInMeta); sp getGraphicBufferSource(); void setGraphicBufferSource(const sp& bufferSource); diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index fad6c33..3e70956 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -37,7 +37,8 @@ static const bool EXTRA_CHECK = true; GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, - uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount) : + uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount, + bool useGraphicBufferInMeta) : mInitCheck(UNKNOWN_ERROR), mNodeInstance(nodeInstance), mExecuting(false), @@ -59,7 +60,8 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, mTimePerCaptureUs(-1ll), mTimePerFrameUs(-1ll), mPrevCaptureUs(-1ll), - mPrevFrameUs(-1ll) { + mPrevFrameUs(-1ll), + mUseGraphicBufferInMeta(useGraphicBufferInMeta) { ALOGV("GraphicBufferSource w=%u h=%u c=%u", bufferWidth, bufferHeight, bufferCount); @@ -254,13 +256,25 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { // Pull the graphic buffer handle back out of the buffer, and confirm // that it matches expectations. OMX_U8* data = header->pBuffer; - buffer_handle_t bufferHandle; - memcpy(&bufferHandle, data + 4, sizeof(buffer_handle_t)); - if (bufferHandle != codecBuffer.mGraphicBuffer->handle) { - // should never happen - ALOGE("codecBufferEmptied: buffer's handle is %p, expected %p", - bufferHandle, codecBuffer.mGraphicBuffer->handle); - CHECK(!"codecBufferEmptied: mismatched buffer"); + MetadataBufferType type = *(MetadataBufferType *)data; + if (type == kMetadataBufferTypeGrallocSource) { + buffer_handle_t bufferHandle; + memcpy(&bufferHandle, data + 4, sizeof(buffer_handle_t)); + if (bufferHandle != codecBuffer.mGraphicBuffer->handle) { + // should never happen + ALOGE("codecBufferEmptied: buffer's handle is %p, expected %p", + bufferHandle, codecBuffer.mGraphicBuffer->handle); + CHECK(!"codecBufferEmptied: mismatched buffer"); + } + } else if (type == kMetadataBufferTypeGraphicBuffer) { + GraphicBuffer *buffer; + memcpy(&buffer, data + 4, sizeof(buffer)); + if (buffer != codecBuffer.mGraphicBuffer.get()) { + // should never happen + ALOGE("codecBufferEmptied: buffer is %p, expected %p", + buffer, codecBuffer.mGraphicBuffer.get()); + CHECK(!"codecBufferEmptied: mismatched buffer"); + } } } @@ -642,10 +656,22 @@ status_t GraphicBufferSource::submitBuffer_l( OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader; CHECK(header->nAllocLen >= 4 + sizeof(buffer_handle_t)); OMX_U8* data = header->pBuffer; - const OMX_U32 type = kMetadataBufferTypeGrallocSource; - buffer_handle_t handle = codecBuffer.mGraphicBuffer->handle; - memcpy(data, &type, 4); - memcpy(data + 4, &handle, sizeof(buffer_handle_t)); + buffer_handle_t handle; + if (!mUseGraphicBufferInMeta) { + const OMX_U32 type = kMetadataBufferTypeGrallocSource; + handle = codecBuffer.mGraphicBuffer->handle; + memcpy(data, &type, 4); + memcpy(data + 4, &handle, sizeof(buffer_handle_t)); + } else { + // codecBuffer holds a reference to the GraphicBuffer, so + // it is valid while it is with the OMX component + const OMX_U32 type = kMetadataBufferTypeGraphicBuffer; + memcpy(data, &type, 4); + // passing a non-reference-counted graphicBuffer + GraphicBuffer *buffer = codecBuffer.mGraphicBuffer.get(); + handle = buffer->handle; + memcpy(data + 4, &buffer, sizeof(buffer)); + } status_t err = mNodeInstance->emptyDirectBuffer(header, 0, 4 + sizeof(buffer_handle_t), OMX_BUFFERFLAG_ENDOFFRAME, diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index a70cc1a..c0860ab 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -49,7 +49,8 @@ namespace android { class GraphicBufferSource : public BufferQueue::ConsumerListener { public: GraphicBufferSource(OMXNodeInstance* nodeInstance, - uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount); + uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount, + bool useGraphicBufferInMeta = false); virtual ~GraphicBufferSource(); // We can't throw an exception if the constructor fails, so we just set @@ -271,6 +272,8 @@ private: int64_t mPrevCaptureUs; int64_t mPrevFrameUs; + bool mUseGraphicBufferInMeta; + void onMessageReceived(const sp &msg); DISALLOW_EVIL_CONSTRUCTORS(GraphicBufferSource); diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index efb27f5..d07ec14 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -393,20 +393,39 @@ status_t OMXNodeInstance::storeMetaDataInBuffers( OMX_U32 portIndex, OMX_BOOL enable) { Mutex::Autolock autolock(mLock); - return storeMetaDataInBuffers_l(portIndex, enable); + return storeMetaDataInBuffers_l( + portIndex, enable, + OMX_FALSE /* useGraphicBuffer */, NULL /* usingGraphicBufferInMetadata */); } status_t OMXNodeInstance::storeMetaDataInBuffers_l( OMX_U32 portIndex, - OMX_BOOL enable) { + OMX_BOOL enable, + OMX_BOOL useGraphicBuffer, + OMX_BOOL *usingGraphicBufferInMetadata) { OMX_INDEXTYPE index; OMX_STRING name = const_cast( "OMX.google.android.index.storeMetaDataInBuffers"); - OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index); + OMX_STRING graphicBufferName = const_cast( + "OMX.google.android.index.storeGraphicBufferInMetaData"); + if (usingGraphicBufferInMetadata == NULL) { + usingGraphicBufferInMetadata = &useGraphicBuffer; + } + + OMX_ERRORTYPE err = + (useGraphicBuffer && portIndex == kPortIndexInput) + ? OMX_GetExtensionIndex(mHandle, graphicBufferName, &index) + : OMX_ErrorBadParameter; + if (err == OMX_ErrorNone) { + *usingGraphicBufferInMetadata = OMX_TRUE; + } else { + *usingGraphicBufferInMetadata = OMX_FALSE; + err = OMX_GetExtensionIndex(mHandle, name, &index); + } + if (err != OMX_ErrorNone) { ALOGE("OMX_GetExtensionIndex %s failed", name); - return StatusFromOMXError(err); } @@ -421,6 +440,7 @@ status_t OMXNodeInstance::storeMetaDataInBuffers_l( params.bStoreMetaData = enable; if ((err = OMX_SetParameter(mHandle, index, ¶ms)) != OMX_ErrorNone) { ALOGE("OMX_SetParameter() failed for StoreMetaDataInBuffers: 0x%08x", err); + *usingGraphicBufferInMetadata = OMX_FALSE; return UNKNOWN_ERROR; } return err; @@ -683,7 +703,10 @@ status_t OMXNodeInstance::createInputSurface( } // Input buffers will hold meta-data (gralloc references). - err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE); + OMX_BOOL usingGraphicBuffer = OMX_FALSE; + err = storeMetaDataInBuffers_l( + portIndex, OMX_TRUE, + OMX_TRUE /* useGraphicBuffer */, &usingGraphicBuffer); if (err != OK) { return err; } @@ -709,7 +732,7 @@ status_t OMXNodeInstance::createInputSurface( GraphicBufferSource* bufferSource = new GraphicBufferSource( this, def.format.video.nFrameWidth, def.format.video.nFrameHeight, - def.nBufferCountActual); + def.nBufferCountActual, usingGraphicBuffer); if ((err = bufferSource->initCheck()) != OK) { delete bufferSource; return err; -- cgit v1.1 From 2edda09a2ad1d112c52acd37d323f63f0a492d67 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 10 Oct 2014 17:15:17 -0700 Subject: stagefright: fix surface input handling of software encoders - added SoftVideoEncoder for common color conversion and extension handling logic - fix YUV420 SemiPlanar handling that should be NV12 not NV21 Bug: 17935149 Change-Id: I9b8d05678b1862dd37bf349ea83d67bdf1bb5560 --- .../codecs/avc/enc/SoftAVCEncoder.cpp | 116 ++------ .../libstagefright/codecs/avc/enc/SoftAVCEncoder.h | 12 +- .../codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp | 122 ++------ .../codecs/m4v_h263/enc/SoftMPEG4Encoder.h | 12 +- media/libstagefright/codecs/on2/enc/Android.mk | 4 - .../codecs/on2/enc/SoftVPXEncoder.cpp | 147 ++-------- .../libstagefright/codecs/on2/enc/SoftVPXEncoder.h | 8 +- .../include/SoftVideoEncoderOMXComponent.h | 67 +++++ media/libstagefright/omx/Android.mk | 6 + .../omx/SoftVideoEncoderOMXComponent.cpp | 311 +++++++++++++++++++++ 10 files changed, 456 insertions(+), 349 deletions(-) create mode 100644 media/libstagefright/include/SoftVideoEncoderOMXComponent.h create mode 100644 media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp (limited to 'media') diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp index 0f4a00d..ed3dca0 100644 --- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp +++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp @@ -111,36 +111,6 @@ static status_t ConvertAvcSpecLevelToOmxAvcLevel( return BAD_VALUE; } -inline static void ConvertYUV420SemiPlanarToYUV420Planar( - uint8_t *inyuv, uint8_t* outyuv, - int32_t width, int32_t height) { - - int32_t outYsize = width * height; - uint32_t *outy = (uint32_t *) outyuv; - uint16_t *outcb = (uint16_t *) (outyuv + outYsize); - uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2)); - - /* Y copying */ - memcpy(outy, inyuv, outYsize); - - /* U & V copying */ - uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize); - for (int32_t i = height >> 1; i > 0; --i) { - for (int32_t j = width >> 2; j > 0; --j) { - uint32_t temp = *inyuv_4++; - uint32_t tempU = temp & 0xFF; - tempU = tempU | ((temp >> 8) & 0xFF00); - - uint32_t tempV = (temp >> 8) & 0xFF; - tempV = tempV | ((temp >> 16) & 0xFF00); - - // Flip U and V - *outcb++ = tempV; - *outcr++ = tempU; - } - } -} - static void* MallocWrapper( void * /* userData */, int32_t size, int32_t /* attrs */) { void *ptr = malloc(size); @@ -178,7 +148,7 @@ SoftAVCEncoder::SoftAVCEncoder( const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component) - : SimpleSoftOMXComponent(name, callbacks, appData, component), + : SoftVideoEncoderOMXComponent(name, callbacks, appData, component), mVideoWidth(176), mVideoHeight(144), mVideoFrameRate(30), @@ -260,9 +230,10 @@ OMX_ERRORTYPE SoftAVCEncoder::initEncParams() { mEncParams->use_overrun_buffer = AVC_OFF; - if (mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { + if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar + || mStoreMetaDataInBuffers) { // Color conversion is needed. - CHECK(mInputFrameData == NULL); + free(mInputFrameData); mInputFrameData = (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1); CHECK(mInputFrameData != NULL); @@ -348,10 +319,10 @@ OMX_ERRORTYPE SoftAVCEncoder::releaseEncoder() { PVAVCCleanUpEncoder(mHandle); releaseOutputBuffers(); - delete mInputFrameData; + free(mInputFrameData); mInputFrameData = NULL; - delete mSliceGroup; + free(mSliceGroup); mSliceGroup = NULL; delete mEncParams; @@ -713,11 +684,7 @@ OMX_ERRORTYPE SoftAVCEncoder::internalSetParameter( mStoreMetaDataInBuffers ? " true" : "false"); if (mStoreMetaDataInBuffers) { - mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar; - if (mInputFrameData == NULL) { - mInputFrameData = - (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1); - } + mVideoColorFormat = OMX_COLOR_FormatAndroidOpaque; } return OMX_ErrorNone; @@ -801,8 +768,6 @@ void SoftAVCEncoder::onQueueFilled(OMX_U32 /* portIndex */) { } } - buffer_handle_t srcBuffer = NULL; // for MetaDataMode only - // Get next input video frame if (mReadyForNextFrame) { // Save the input buffer info so that it can be @@ -823,7 +788,7 @@ void SoftAVCEncoder::onQueueFilled(OMX_U32 /* portIndex */) { videoInput.height = ((mVideoHeight + 15) >> 4) << 4; videoInput.pitch = ((mVideoWidth + 15) >> 4) << 4; videoInput.coding_timestamp = (inHeader->nTimeStamp + 500) / 1000; // in ms - uint8_t *inputData = NULL; + const uint8_t *inputData = NULL; if (mStoreMetaDataInBuffers) { if (inHeader->nFilledLen != 8) { ALOGE("MetaData buffer is wrong size! " @@ -833,8 +798,10 @@ void SoftAVCEncoder::onQueueFilled(OMX_U32 /* portIndex */) { return; } inputData = - extractGrallocData(inHeader->pBuffer + inHeader->nOffset, - &srcBuffer); + extractGraphicBuffer( + mInputFrameData, (mVideoWidth * mVideoHeight * 3) >> 1, + inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen, + mVideoWidth, mVideoHeight); if (inputData == NULL) { ALOGE("Unable to extract gralloc buffer in metadata mode"); mSignalledError = true; @@ -843,16 +810,16 @@ void SoftAVCEncoder::onQueueFilled(OMX_U32 /* portIndex */) { } // TODO: Verify/convert pixel format enum } else { - inputData = (uint8_t *)inHeader->pBuffer + inHeader->nOffset; + inputData = (const uint8_t *)inHeader->pBuffer + inHeader->nOffset; + if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) { + ConvertYUV420SemiPlanarToYUV420Planar( + inputData, mInputFrameData, mVideoWidth, mVideoHeight); + inputData = mInputFrameData; + } } - if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) { - ConvertYUV420SemiPlanarToYUV420Planar( - inputData, mInputFrameData, mVideoWidth, mVideoHeight); - inputData = mInputFrameData; - } CHECK(inputData != NULL); - videoInput.YCbCr[0] = inputData; + videoInput.YCbCr[0] = (uint8_t *)inputData; videoInput.YCbCr[1] = videoInput.YCbCr[0] + videoInput.height * videoInput.pitch; videoInput.YCbCr[2] = videoInput.YCbCr[1] + ((videoInput.height * videoInput.pitch) >> 2); @@ -869,14 +836,12 @@ void SoftAVCEncoder::onQueueFilled(OMX_U32 /* portIndex */) { if (encoderStatus < AVCENC_SUCCESS) { ALOGE("encoderStatus = %d at line %d", encoderStatus, __LINE__); mSignalledError = true; - releaseGrallocData(srcBuffer); notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); return; } else { ALOGV("encoderStatus = %d at line %d", encoderStatus, __LINE__); inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; - releaseGrallocData(srcBuffer); notifyEmptyBufferDone(inHeader); return; } @@ -916,7 +881,6 @@ void SoftAVCEncoder::onQueueFilled(OMX_U32 /* portIndex */) { if (encoderStatus < AVCENC_SUCCESS) { ALOGE("encoderStatus = %d at line %d", encoderStatus, __LINE__); mSignalledError = true; - releaseGrallocData(srcBuffer); notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); return; } @@ -926,7 +890,6 @@ void SoftAVCEncoder::onQueueFilled(OMX_U32 /* portIndex */) { inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; - releaseGrallocData(srcBuffer); notifyEmptyBufferDone(inHeader); outQueue.erase(outQueue.begin()); @@ -974,47 +937,6 @@ void SoftAVCEncoder::signalBufferReturned(MediaBuffer *buffer) { ALOGV("signalBufferReturned: %p", buffer); } -OMX_ERRORTYPE SoftAVCEncoder::getExtensionIndex( - const char *name, OMX_INDEXTYPE *index) { - if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) { - *(int32_t*)index = kStoreMetaDataExtensionIndex; - return OMX_ErrorNone; - } - return OMX_ErrorUndefined; -} - -uint8_t *SoftAVCEncoder::extractGrallocData(void *data, buffer_handle_t *buffer) { - OMX_U32 type = *(OMX_U32*)data; - status_t res; - if (type != kMetadataBufferTypeGrallocSource) { - ALOGE("Data passed in with metadata mode does not have type " - "kMetadataBufferTypeGrallocSource (%d), has type %d instead", - kMetadataBufferTypeGrallocSource, type); - return NULL; - } - buffer_handle_t imgBuffer = *(buffer_handle_t*)((uint8_t*)data + 4); - - const Rect rect(mVideoWidth, mVideoHeight); - uint8_t *img; - res = GraphicBufferMapper::get().lock(imgBuffer, - GRALLOC_USAGE_HW_VIDEO_ENCODER, - rect, (void**)&img); - if (res != OK) { - ALOGE("%s: Unable to lock image buffer %p for access", __FUNCTION__, - imgBuffer); - return NULL; - } - - *buffer = imgBuffer; - return img; -} - -void SoftAVCEncoder::releaseGrallocData(buffer_handle_t buffer) { - if (mStoreMetaDataInBuffers) { - GraphicBufferMapper::get().unlock(buffer); - } -} - } // namespace android android::SoftOMXComponent *createSoftOMXComponent( diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h index cfa9ca5..130593f 100644 --- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h +++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h @@ -22,14 +22,14 @@ #include #include "avcenc_api.h" -#include "SimpleSoftOMXComponent.h" +#include "SoftVideoEncoderOMXComponent.h" namespace android { struct MediaBuffer; struct SoftAVCEncoder : public MediaBufferObserver, - public SimpleSoftOMXComponent { + public SoftVideoEncoderOMXComponent { SoftAVCEncoder( const char *name, const OMX_CALLBACKTYPE *callbacks, @@ -45,11 +45,6 @@ struct SoftAVCEncoder : public MediaBufferObserver, virtual void onQueueFilled(OMX_U32 portIndex); - // Override SoftOMXComponent methods - - virtual OMX_ERRORTYPE getExtensionIndex( - const char *name, OMX_INDEXTYPE *index); - // Implement MediaBufferObserver virtual void signalBufferReturned(MediaBuffer *buffer); @@ -105,9 +100,6 @@ private: OMX_ERRORTYPE releaseEncoder(); void releaseOutputBuffers(); - uint8_t* extractGrallocData(void *data, buffer_handle_t *buffer); - void releaseGrallocData(buffer_handle_t buffer); - DISALLOW_EVIL_CONSTRUCTORS(SoftAVCEncoder); }; diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp index 42c9956..c87d19c 100644 --- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp +++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp @@ -46,42 +46,12 @@ static void InitOMXParams(T *params) { params->nVersion.s.nStep = 0; } -inline static void ConvertYUV420SemiPlanarToYUV420Planar( - uint8_t *inyuv, uint8_t* outyuv, - int32_t width, int32_t height) { - - int32_t outYsize = width * height; - uint32_t *outy = (uint32_t *) outyuv; - uint16_t *outcb = (uint16_t *) (outyuv + outYsize); - uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2)); - - /* Y copying */ - memcpy(outy, inyuv, outYsize); - - /* U & V copying */ - uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize); - for (int32_t i = height >> 1; i > 0; --i) { - for (int32_t j = width >> 2; j > 0; --j) { - uint32_t temp = *inyuv_4++; - uint32_t tempU = temp & 0xFF; - tempU = tempU | ((temp >> 8) & 0xFF00); - - uint32_t tempV = (temp >> 8) & 0xFF; - tempV = tempV | ((temp >> 16) & 0xFF00); - - // Flip U and V - *outcb++ = tempV; - *outcr++ = tempU; - } - } -} - SoftMPEG4Encoder::SoftMPEG4Encoder( const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component) - : SimpleSoftOMXComponent(name, callbacks, appData, component), + : SoftVideoEncoderOMXComponent(name, callbacks, appData, component), mEncodeMode(COMBINE_MODE_WITH_ERR_RES), mVideoWidth(176), mVideoHeight(144), @@ -149,9 +119,10 @@ OMX_ERRORTYPE SoftMPEG4Encoder::initEncParams() { mEncParams->quantType[0] = 0; mEncParams->noFrameSkipped = PV_OFF; - if (mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { + if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar + || mStoreMetaDataInBuffers) { // Color conversion is needed. - CHECK(mInputFrameData == NULL); + free(mInputFrameData); mInputFrameData = (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1); CHECK(mInputFrameData != NULL); @@ -216,7 +187,7 @@ OMX_ERRORTYPE SoftMPEG4Encoder::releaseEncoder() { PVCleanUpVideoEncoder(mHandle); - delete mInputFrameData; + free(mInputFrameData); mInputFrameData = NULL; delete mEncParams; @@ -486,6 +457,17 @@ OMX_ERRORTYPE SoftMPEG4Encoder::internalSetParameter( mVideoHeight = def->format.video.nFrameHeight; mVideoFrameRate = def->format.video.xFramerate >> 16; mVideoColorFormat = def->format.video.eColorFormat; + + OMX_PARAM_PORTDEFINITIONTYPE *portDef = + &editPortInfo(0)->mDef; + portDef->format.video.nFrameWidth = mVideoWidth; + portDef->format.video.nFrameHeight = mVideoHeight; + portDef->format.video.xFramerate = def->format.video.xFramerate; + portDef->format.video.eColorFormat = + (OMX_COLOR_FORMATTYPE) mVideoColorFormat; + portDef = &editPortInfo(1)->mDef; + portDef->format.video.nFrameWidth = mVideoWidth; + portDef->format.video.nFrameHeight = mVideoHeight; } else { mVideoBitRate = def->format.video.nBitrate; } @@ -607,11 +589,7 @@ OMX_ERRORTYPE SoftMPEG4Encoder::internalSetParameter( mStoreMetaDataInBuffers ? " true" : "false"); if (mStoreMetaDataInBuffers) { - mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar; - if (mInputFrameData == NULL) { - mInputFrameData = - (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1); - } + mVideoColorFormat = OMX_COLOR_FormatAndroidOpaque; } return OMX_ErrorNone; @@ -679,9 +657,8 @@ void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { mSawInputEOS = true; } - buffer_handle_t srcBuffer = NULL; // for MetaDataMode only if (inHeader->nFilledLen > 0) { - uint8_t *inputData = NULL; + const uint8_t *inputData = NULL; if (mStoreMetaDataInBuffers) { if (inHeader->nFilledLen != 8) { ALOGE("MetaData buffer is wrong size! " @@ -691,24 +668,25 @@ void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { return; } inputData = - extractGrallocData(inHeader->pBuffer + inHeader->nOffset, - &srcBuffer); + extractGraphicBuffer( + mInputFrameData, (mVideoWidth * mVideoHeight * 3) >> 1, + inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen, + mVideoWidth, mVideoHeight); if (inputData == NULL) { ALOGE("Unable to extract gralloc buffer in metadata mode"); mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); return; } - // TODO: Verify/convert pixel format enum } else { - inputData = (uint8_t *)inHeader->pBuffer + inHeader->nOffset; + inputData = (const uint8_t *)inHeader->pBuffer + inHeader->nOffset; + if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) { + ConvertYUV420SemiPlanarToYUV420Planar( + inputData, mInputFrameData, mVideoWidth, mVideoHeight); + inputData = mInputFrameData; + } } - if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) { - ConvertYUV420SemiPlanarToYUV420Planar( - inputData, mInputFrameData, mVideoWidth, mVideoHeight); - inputData = mInputFrameData; - } CHECK(inputData != NULL); VideoEncFrameIO vin, vout; @@ -717,7 +695,7 @@ void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { vin.height = ((mVideoHeight + 15) >> 4) << 4; vin.pitch = ((mVideoWidth + 15) >> 4) << 4; vin.timestamp = (inHeader->nTimeStamp + 500) / 1000; // in ms - vin.yChan = inputData; + vin.yChan = (uint8_t *)inputData; vin.uChan = vin.yChan + vin.height * vin.pitch; vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2); @@ -744,7 +722,6 @@ void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; - releaseGrallocData(srcBuffer); notifyEmptyBufferDone(inHeader); outQueue.erase(outQueue.begin()); @@ -759,47 +736,6 @@ void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { } } -OMX_ERRORTYPE SoftMPEG4Encoder::getExtensionIndex( - const char *name, OMX_INDEXTYPE *index) { - if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) { - *(int32_t*)index = kStoreMetaDataExtensionIndex; - return OMX_ErrorNone; - } - return OMX_ErrorUndefined; -} - -uint8_t *SoftMPEG4Encoder::extractGrallocData(void *data, buffer_handle_t *buffer) { - OMX_U32 type = *(OMX_U32*)data; - status_t res; - if (type != kMetadataBufferTypeGrallocSource) { - ALOGE("Data passed in with metadata mode does not have type " - "kMetadataBufferTypeGrallocSource (%d), has type %d instead", - kMetadataBufferTypeGrallocSource, type); - return NULL; - } - buffer_handle_t imgBuffer = *(buffer_handle_t*)((uint8_t*)data + 4); - - const Rect rect(mVideoWidth, mVideoHeight); - uint8_t *img; - res = GraphicBufferMapper::get().lock(imgBuffer, - GRALLOC_USAGE_HW_VIDEO_ENCODER, - rect, (void**)&img); - if (res != OK) { - ALOGE("%s: Unable to lock image buffer %p for access", __FUNCTION__, - imgBuffer); - return NULL; - } - - *buffer = imgBuffer; - return img; -} - -void SoftMPEG4Encoder::releaseGrallocData(buffer_handle_t buffer) { - if (mStoreMetaDataInBuffers) { - GraphicBufferMapper::get().unlock(buffer); - } -} - } // namespace android android::SoftOMXComponent *createSoftOMXComponent( diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h index c59a1b9..b0605b4 100644 --- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h +++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h @@ -19,7 +19,7 @@ #include #include -#include "SimpleSoftOMXComponent.h" +#include "SoftVideoEncoderOMXComponent.h" #include "mp4enc_api.h" @@ -27,7 +27,7 @@ namespace android { struct MediaBuffer; -struct SoftMPEG4Encoder : public SimpleSoftOMXComponent { +struct SoftMPEG4Encoder : public SoftVideoEncoderOMXComponent { SoftMPEG4Encoder( const char *name, const OMX_CALLBACKTYPE *callbacks, @@ -43,11 +43,6 @@ struct SoftMPEG4Encoder : public SimpleSoftOMXComponent { virtual void onQueueFilled(OMX_U32 portIndex); - // Override SoftOMXComponent methods - - virtual OMX_ERRORTYPE getExtensionIndex( - const char *name, OMX_INDEXTYPE *index); - protected: virtual ~SoftMPEG4Encoder(); @@ -86,9 +81,6 @@ private: OMX_ERRORTYPE initEncoder(); OMX_ERRORTYPE releaseEncoder(); - uint8_t* extractGrallocData(void *data, buffer_handle_t *buffer); - void releaseGrallocData(buffer_handle_t buffer); - DISALLOW_EVIL_CONSTRUCTORS(SoftMPEG4Encoder); }; diff --git a/media/libstagefright/codecs/on2/enc/Android.mk b/media/libstagefright/codecs/on2/enc/Android.mk index 4060a0a..e265104 100644 --- a/media/libstagefright/codecs/on2/enc/Android.mk +++ b/media/libstagefright/codecs/on2/enc/Android.mk @@ -12,10 +12,6 @@ LOCAL_C_INCLUDES := \ frameworks/av/media/libstagefright/include \ frameworks/native/include/media/openmax \ -ifeq ($(TARGET_DEVICE), manta) - LOCAL_CFLAGS += -DSURFACE_IS_BGR32 -endif - LOCAL_STATIC_LIBRARIES := \ libvpx diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp index cabd6bd..eb621d5 100644 --- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp +++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp @@ -50,90 +50,11 @@ static int GetCPUCoreCount() { return cpuCoreCount; } - -// This color conversion utility is copied from SoftMPEG4Encoder.cpp -inline static void ConvertSemiPlanarToPlanar(uint8_t *inyuv, - uint8_t* outyuv, - int32_t width, - int32_t height) { - int32_t outYsize = width * height; - uint32_t *outy = (uint32_t *) outyuv; - uint16_t *outcb = (uint16_t *) (outyuv + outYsize); - uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2)); - - /* Y copying */ - memcpy(outy, inyuv, outYsize); - - /* U & V copying */ - uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize); - for (int32_t i = height >> 1; i > 0; --i) { - for (int32_t j = width >> 2; j > 0; --j) { - uint32_t temp = *inyuv_4++; - uint32_t tempU = temp & 0xFF; - tempU = tempU | ((temp >> 8) & 0xFF00); - - uint32_t tempV = (temp >> 8) & 0xFF; - tempV = tempV | ((temp >> 16) & 0xFF00); - - // Flip U and V - *outcb++ = tempV; - *outcr++ = tempU; - } - } -} - -static void ConvertRGB32ToPlanar( - const uint8_t *src, uint8_t *dstY, int32_t width, int32_t height) { - CHECK((width & 1) == 0); - CHECK((height & 1) == 0); - - uint8_t *dstU = dstY + width * height; - uint8_t *dstV = dstU + (width / 2) * (height / 2); - - for (int32_t y = 0; y < height; ++y) { - for (int32_t x = 0; x < width; ++x) { -#ifdef SURFACE_IS_BGR32 - unsigned blue = src[4 * x]; - unsigned green = src[4 * x + 1]; - unsigned red= src[4 * x + 2]; -#else - unsigned red= src[4 * x]; - unsigned green = src[4 * x + 1]; - unsigned blue = src[4 * x + 2]; -#endif - - unsigned luma = - ((red * 66 + green * 129 + blue * 25) >> 8) + 16; - - dstY[x] = luma; - - if ((x & 1) == 0 && (y & 1) == 0) { - unsigned U = - ((-red * 38 - green * 74 + blue * 112) >> 8) + 128; - - unsigned V = - ((red * 112 - green * 94 - blue * 18) >> 8) + 128; - - dstU[x / 2] = U; - dstV[x / 2] = V; - } - } - - if ((y & 1) == 0) { - dstU += width / 2; - dstV += width / 2; - } - - src += 4 * width; - dstY += width; - } -} - SoftVPXEncoder::SoftVPXEncoder(const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component) - : SimpleSoftOMXComponent(name, callbacks, appData, component), + : SoftVideoEncoderOMXComponent(name, callbacks, appData, component), mCodecContext(NULL), mCodecConfiguration(NULL), mCodecInterface(NULL), @@ -157,7 +78,6 @@ SoftVPXEncoder::SoftVPXEncoder(const char *name, mLastTimestamp(0x7FFFFFFFFFFFFFFFLL), mConversionBuffer(NULL), mInputDataIsMeta(false), - mGrallocModule(NULL), mKeyFrameRequested(false) { memset(mTemporalLayerBitrateRatio, 0, sizeof(mTemporalLayerBitrateRatio)); mTemporalLayerBitrateRatio[0] = 100; @@ -447,13 +367,12 @@ status_t SoftVPXEncoder::initEncoder() { } } - if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || mInputDataIsMeta) { + if (mColorFormat != OMX_COLOR_FormatYUV420Planar || mInputDataIsMeta) { + free(mConversionBuffer); + mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2); if (mConversionBuffer == NULL) { - mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2); - if (mConversionBuffer == NULL) { - ALOGE("Allocating conversion buffer failed."); - return UNKNOWN_ERROR; - } + ALOGE("Allocating conversion buffer failed."); + return UNKNOWN_ERROR; } } return OK; @@ -473,7 +392,7 @@ status_t SoftVPXEncoder::releaseEncoder() { } if (mConversionBuffer != NULL) { - delete mConversionBuffer; + free(mConversionBuffer); mConversionBuffer = NULL; } @@ -1035,49 +954,28 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { return; } - uint8_t *source = + const uint8_t *source = inputBufferHeader->pBuffer + inputBufferHeader->nOffset; if (mInputDataIsMeta) { - CHECK_GE(inputBufferHeader->nFilledLen, - 4 + sizeof(buffer_handle_t)); - - uint32_t bufferType = *(uint32_t *)source; - CHECK_EQ(bufferType, kMetadataBufferTypeGrallocSource); - - if (mGrallocModule == NULL) { - CHECK_EQ(0, hw_get_module( - GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule)); + source = extractGraphicBuffer( + mConversionBuffer, mWidth * mHeight * 3 / 2, + source, inputBufferHeader->nFilledLen, + mWidth, mHeight); + if (source == NULL) { + ALOGE("Unable to extract gralloc buffer in metadata mode"); + notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); + return; } - - const gralloc_module_t *grmodule = - (const gralloc_module_t *)mGrallocModule; - - buffer_handle_t handle = *(buffer_handle_t *)(source + 4); - - void *bits; - CHECK_EQ(0, - grmodule->lock( - grmodule, handle, - GRALLOC_USAGE_SW_READ_OFTEN - | GRALLOC_USAGE_SW_WRITE_NEVER, - 0, 0, mWidth, mHeight, &bits)); - - ConvertRGB32ToPlanar( - (const uint8_t *)bits, mConversionBuffer, mWidth, mHeight); - - source = mConversionBuffer; - - CHECK_EQ(0, grmodule->unlock(grmodule, handle)); } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { - ConvertSemiPlanarToPlanar( + ConvertYUV420SemiPlanarToYUV420Planar( source, mConversionBuffer, mWidth, mHeight); source = mConversionBuffer; } vpx_image_t raw_frame; vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight, - kInputBufferAlignment, source); + kInputBufferAlignment, (uint8_t *)source); vpx_enc_frame_flags_t flags = 0; if (mTemporalPatternLength > 0) { @@ -1153,15 +1051,6 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { } } -OMX_ERRORTYPE SoftVPXEncoder::getExtensionIndex( - const char *name, OMX_INDEXTYPE *index) { - if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) { - *(int32_t*)index = kStoreMetaDataExtensionIndex; - return OMX_ErrorNone; - } - return SimpleSoftOMXComponent::getExtensionIndex(name, index); -} - } // namespace android diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h index 5b4c954..f4c1564 100644 --- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h +++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h @@ -18,7 +18,7 @@ #define SOFT_VPX_ENCODER_H_ -#include "SimpleSoftOMXComponent.h" +#include "SoftVideoEncoderOMXComponent.h" #include #include @@ -59,7 +59,7 @@ namespace android { // - OMX timestamps are in microseconds, therefore // encoder timebase is fixed to 1/1000000 -struct SoftVPXEncoder : public SimpleSoftOMXComponent { +struct SoftVPXEncoder : public SoftVideoEncoderOMXComponent { SoftVPXEncoder(const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, @@ -87,9 +87,6 @@ protected: // encoding of the frame virtual void onQueueFilled(OMX_U32 portIndex); - virtual OMX_ERRORTYPE getExtensionIndex( - const char *name, OMX_INDEXTYPE *index); - private: enum TemporalReferences { // For 1 layer case: reference all (last, golden, and alt ref), but only @@ -233,7 +230,6 @@ private: uint8_t* mConversionBuffer; bool mInputDataIsMeta; - const hw_module_t *mGrallocModule; bool mKeyFrameRequested; diff --git a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h new file mode 100644 index 0000000..b3b810d --- /dev/null +++ b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h @@ -0,0 +1,67 @@ +/* + * Copyright 2014 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 SOFT_VIDEO_ENCODER_OMX_COMPONENT_H_ + +#define SOFT_VIDEO_ENCODER_OMX_COMPONENT_H_ + +#include "SimpleSoftOMXComponent.h" +#include + +struct hw_module_t; + +namespace android { + +struct SoftVideoEncoderOMXComponent : public SimpleSoftOMXComponent { + SoftVideoEncoderOMXComponent( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component); + +protected: + static void ConvertFlexYUVToPlanar( + uint8_t *dst, size_t dstStride, size_t dstVStride, + struct android_ycbcr *ycbcr, int32_t width, int32_t height); + + static void ConvertYUV420SemiPlanarToYUV420Planar( + const uint8_t *inYVU, uint8_t* outYUV, int32_t width, int32_t height); + + static void ConvertRGB32ToPlanar( + uint8_t *dstY, size_t dstStride, size_t dstVStride, + const uint8_t *src, size_t width, size_t height, size_t srcStride, + bool bgr); + + const uint8_t *extractGraphicBuffer( + uint8_t *dst, size_t dstSize, const uint8_t *src, size_t srcSize, + size_t width, size_t height) const; + + virtual OMX_ERRORTYPE getExtensionIndex(const char *name, OMX_INDEXTYPE *index); + + enum { + kInputPortIndex = 0, + kOutputPortIndex = 1, + }; + +private: + mutable const hw_module_t *mGrallocModule; + + DISALLOW_EVIL_CONSTRUCTORS(SoftVideoEncoderOMXComponent); +}; + +} // namespace android + +#endif // SOFT_VIDEO_ENCODER_OMX_COMPONENT_H_ diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk index cd912e7..aaa8334 100644 --- a/media/libstagefright/omx/Android.mk +++ b/media/libstagefright/omx/Android.mk @@ -1,6 +1,10 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +ifeq ($(TARGET_DEVICE), manta) + LOCAL_CFLAGS += -DSURFACE_IS_BGR32 +endif + LOCAL_SRC_FILES:= \ GraphicBufferSource.cpp \ OMX.cpp \ @@ -10,6 +14,7 @@ LOCAL_SRC_FILES:= \ SoftOMXComponent.cpp \ SoftOMXPlugin.cpp \ SoftVideoDecoderOMXComponent.cpp \ + SoftVideoEncoderOMXComponent.cpp \ LOCAL_C_INCLUDES += \ $(TOP)/frameworks/av/media/libstagefright \ @@ -18,6 +23,7 @@ LOCAL_C_INCLUDES += \ LOCAL_SHARED_LIBRARIES := \ libbinder \ + libhardware \ libmedia \ libutils \ liblog \ diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp new file mode 100644 index 0000000..8bff142 --- /dev/null +++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp @@ -0,0 +1,311 @@ +/* + * Copyright 2014 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 + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoftVideoEncoderOMXComponent" +#include + +#include "include/SoftVideoEncoderOMXComponent.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace android { + +SoftVideoEncoderOMXComponent::SoftVideoEncoderOMXComponent( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component) + : SimpleSoftOMXComponent(name, callbacks, appData, component), + mGrallocModule(NULL) { +} + +// static +void SoftVideoEncoderOMXComponent::ConvertFlexYUVToPlanar( + uint8_t *dst, size_t dstStride, size_t dstVStride, + struct android_ycbcr *ycbcr, int32_t width, int32_t height) { + const uint8_t *src = (const uint8_t *)ycbcr->y; + const uint8_t *srcU = (const uint8_t *)ycbcr->cb; + const uint8_t *srcV = (const uint8_t *)ycbcr->cr; + uint8_t *dstU = dst + dstVStride * dstStride; + uint8_t *dstV = dstU + (dstVStride >> 1) * (dstStride >> 1); + + for (size_t y = height; y > 0; --y) { + memcpy(dst, src, width); + dst += dstStride; + src += ycbcr->ystride; + } + if (ycbcr->cstride == ycbcr->ystride >> 1 && ycbcr->chroma_step == 1) { + // planar + for (size_t y = height >> 1; y > 0; --y) { + memcpy(dstU, srcU, width >> 1); + dstU += dstStride >> 1; + srcU += ycbcr->cstride; + memcpy(dstV, srcV, width >> 1); + dstV += dstStride >> 1; + srcV += ycbcr->cstride; + } + } else { + // arbitrary + for (size_t y = height >> 1; y > 0; --y) { + for (size_t x = width >> 1; x > 0; --x) { + *dstU++ = *srcU; + *dstV++ = *srcV; + srcU += ycbcr->chroma_step; + srcV += ycbcr->chroma_step; + } + dstU += (dstStride >> 1) - (width >> 1); + dstV += (dstStride >> 1) - (width >> 1); + srcU += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step; + srcV += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step; + } + } +} + +// static +void SoftVideoEncoderOMXComponent::ConvertYUV420SemiPlanarToYUV420Planar( + const uint8_t *inYVU, uint8_t* outYUV, int32_t width, int32_t height) { + // TODO: add support for stride + int32_t outYsize = width * height; + uint32_t *outY = (uint32_t *) outYUV; + uint16_t *outCb = (uint16_t *) (outYUV + outYsize); + uint16_t *outCr = (uint16_t *) (outYUV + outYsize + (outYsize >> 2)); + + /* Y copying */ + memcpy(outY, inYVU, outYsize); + + /* U & V copying */ + // FIXME this only works if width is multiple of 4 + uint32_t *inYVU_4 = (uint32_t *) (inYVU + outYsize); + for (int32_t i = height >> 1; i > 0; --i) { + for (int32_t j = width >> 2; j > 0; --j) { + uint32_t temp = *inYVU_4++; + uint32_t tempU = temp & 0xFF; + tempU = tempU | ((temp >> 8) & 0xFF00); + + uint32_t tempV = (temp >> 8) & 0xFF; + tempV = tempV | ((temp >> 16) & 0xFF00); + + *outCb++ = tempU; + *outCr++ = tempV; + } + } +} + +// static +void SoftVideoEncoderOMXComponent::ConvertRGB32ToPlanar( + uint8_t *dstY, size_t dstStride, size_t dstVStride, + const uint8_t *src, size_t width, size_t height, size_t srcStride, + bool bgr) { + CHECK((width & 1) == 0); + CHECK((height & 1) == 0); + + uint8_t *dstU = dstY + dstStride * dstVStride; + uint8_t *dstV = dstU + (dstStride >> 1) * (dstVStride >> 1); + +#ifdef SURFACE_IS_BGR32 + bgr = !bgr; +#endif + + const size_t redOffset = bgr ? 2 : 0; + const size_t greenOffset = 1; + const size_t blueOffset = bgr ? 0 : 2; + + for (size_t y = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x) { + unsigned red = src[redOffset]; + unsigned green = src[greenOffset]; + unsigned blue = src[blueOffset]; + + // using ITU-R BT.601 conversion matrix + unsigned luma = + ((red * 66 + green * 129 + blue * 25) >> 8) + 16; + + dstY[x] = luma; + + if ((x & 1) == 0 && (y & 1) == 0) { + unsigned U = + ((-red * 38 - green * 74 + blue * 112) >> 8) + 128; + + unsigned V = + ((red * 112 - green * 94 - blue * 18) >> 8) + 128; + + dstU[x >> 1] = U; + dstV[x >> 1] = V; + } + src += 4; + } + + if ((y & 1) == 0) { + dstU += dstStride >> 1; + dstV += dstStride >> 1; + } + + src += srcStride - 4 * width; + dstY += dstStride; + } +} + +const uint8_t *SoftVideoEncoderOMXComponent::extractGraphicBuffer( + uint8_t *dst, size_t dstSize, + const uint8_t *src, size_t srcSize, + size_t width, size_t height) const { + size_t dstStride = width; + size_t dstVStride = height; + + MetadataBufferType bufferType = *(MetadataBufferType *)src; + bool usingGraphicBuffer = bufferType == kMetadataBufferTypeGraphicBuffer; + if (!usingGraphicBuffer && bufferType != kMetadataBufferTypeGrallocSource) { + ALOGE("Unsupported metadata type (%d)", bufferType); + return NULL; + } + + if (mGrallocModule == NULL) { + CHECK_EQ(0, hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule)); + } + + const gralloc_module_t *grmodule = + (const gralloc_module_t *)mGrallocModule; + + buffer_handle_t handle; + int format; + size_t srcStride; + size_t srcVStride; + if (usingGraphicBuffer) { + if (srcSize < 4 + sizeof(GraphicBuffer *)) { + ALOGE("Metadata is too small (%zu vs %zu)", srcSize, 4 + sizeof(GraphicBuffer *)); + return NULL; + } + + GraphicBuffer *buffer = *(GraphicBuffer **)(src + 4); + handle = buffer->handle; + format = buffer->format; + srcStride = buffer->stride; + srcVStride = buffer->height; + // convert stride from pixels to bytes + if (format != HAL_PIXEL_FORMAT_YV12 && + format != HAL_PIXEL_FORMAT_YCbCr_420_888) { + // TODO do we need to support other formats? + srcStride *= 4; + } + } else { + // TODO: remove this part. Check if anyone uses this. + + if (srcSize < 4 + sizeof(buffer_handle_t)) { + ALOGE("Metadata is too small (%zu vs %zu)", srcSize, 4 + sizeof(buffer_handle_t)); + return NULL; + } + + handle = *(buffer_handle_t *)(src + 4); + // assume HAL_PIXEL_FORMAT_RGBA_8888 + // there is no way to get the src stride without the graphic buffer + format = HAL_PIXEL_FORMAT_RGBA_8888; + srcStride = width * 4; + srcVStride = height; + } + + size_t neededSize = + dstStride * dstVStride + (width >> 1) + + (dstStride >> 1) * ((dstVStride >> 1) + (height >> 1) - 1); + if (dstSize < neededSize) { + ALOGE("destination buffer is too small (%zu vs %zu)", dstSize, neededSize); + return NULL; + } + + void *bits = NULL; + struct android_ycbcr ycbcr; + status_t res; + if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { + res = grmodule->lock_ycbcr( + grmodule, handle, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, + 0, 0, width, height, &ycbcr); + } else { + res = grmodule->lock( + grmodule, handle, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, + 0, 0, width, height, &bits); + } + if (res != OK) { + ALOGE("Unable to lock image buffer %p for access", handle); + return NULL; + } + + switch (format) { + case HAL_PIXEL_FORMAT_YV12: // YCrCb / YVU planar + // convert to flex YUV + ycbcr.y = bits; + ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride; + ycbcr.cb = (uint8_t *)ycbcr.cr + (srcStride >> 1) * (srcVStride >> 1); + ycbcr.chroma_step = 1; + ycbcr.cstride = srcVStride >> 1; + ycbcr.ystride = srcVStride; + ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height); + break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: // YCrCb / YVU semiplanar, NV21 + // convert to flex YUV + ycbcr.y = bits; + ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride; + ycbcr.cb = (uint8_t *)ycbcr.cr + 1; + ycbcr.chroma_step = 2; + ycbcr.cstride = srcVStride; + ycbcr.ystride = srcVStride; + ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_888: + ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height); + break; + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + ConvertRGB32ToPlanar( + dst, dstStride, dstVStride, + (const uint8_t *)bits, width, height, srcStride, + format == HAL_PIXEL_FORMAT_BGRA_8888); + break; + default: + ALOGE("Unsupported pixel format %#x", format); + dst = NULL; + break; + } + + if (grmodule->unlock(grmodule, handle) != OK) { + ALOGE("Unable to unlock image buffer %p for access", handle); + } + + return dst; +} + +OMX_ERRORTYPE SoftVideoEncoderOMXComponent::getExtensionIndex( + const char *name, OMX_INDEXTYPE *index) { + if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers") || + !strcmp(name, "OMX.google.android.index.storeGraphicBufferInMetaData")) { + *(int32_t*)index = kStoreMetaDataExtensionIndex; + return OMX_ErrorNone; + } + return SimpleSoftOMXComponent::getExtensionIndex(name, index); +} + +} // namespace android -- cgit v1.1 From 942481eee58cb1e81853bc79e25359a7ee8a59e1 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 16 Oct 2014 10:51:23 -0700 Subject: Fix freed memory references MPEG4Source references memory owned by MPEG4Extractor, and therefore an MPEG4Extractor needs to be kept around as long as the MPEG4Sources obtained from it exist. Bug: 17890354 Change-Id: I399e18ec78517559ccc0914ffc7e099687c0ba51 --- media/libstagefright/MPEG4Extractor.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'media') diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 1729f93..d922dc0 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -48,7 +48,8 @@ namespace android { class MPEG4Source : public MediaSource { public: // Caller retains ownership of both "dataSource" and "sampleTable". - MPEG4Source(const sp &format, + MPEG4Source(const sp &owner, + const sp &format, const sp &dataSource, int32_t timeScale, const sp &sampleTable, @@ -70,6 +71,8 @@ protected: private: Mutex mLock; + // keep the MPEG4Extractor around, since we're referencing its data + sp mOwner; sp mFormat; sp mDataSource; int32_t mTimescale; @@ -2593,7 +2596,7 @@ sp MPEG4Extractor::getTrack(size_t index) { ALOGV("getTrack called, pssh: %zu", mPssh.size()); - return new MPEG4Source( + return new MPEG4Source(this, track->meta, mDataSource, track->timescale, track->sampleTable, mSidxEntries, trex, mMoofOffset); } @@ -2940,6 +2943,7 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio( //////////////////////////////////////////////////////////////////////////////// MPEG4Source::MPEG4Source( + const sp &owner, const sp &format, const sp &dataSource, int32_t timeScale, @@ -2947,7 +2951,8 @@ MPEG4Source::MPEG4Source( Vector &sidx, const Trex *trex, off64_t firstMoofOffset) - : mFormat(format), + : mOwner(owner), + mFormat(format), mDataSource(dataSource), mTimescale(timeScale), mSampleTable(sampleTable), -- cgit v1.1 From 3b9eb1f8629c6264d924ab7043f80d824cdd39e2 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 15 Oct 2014 17:05:08 -0700 Subject: move audio sink open/close to NuPlayerRenderer Bug: 17675112 Change-Id: I7eb3d02380658f848baedafe2aea287586ccf016 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 130 +------------- media/libmediaplayerservice/nuplayer/NuPlayer.h | 1 - .../nuplayer/NuPlayerRenderer.cpp | 199 ++++++++++++++++++++- .../nuplayer/NuPlayerRenderer.h | 16 ++ 4 files changed, 223 insertions(+), 123 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index eb5821b..a63a940 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -153,7 +153,6 @@ NuPlayer::NuPlayer() mSourceFlags(0), mVideoIsAVC(false), mOffloadAudio(false), - mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER), mAudioDecoderGeneration(0), mVideoDecoderGeneration(0), mRendererGeneration(0), @@ -1112,30 +1111,15 @@ void NuPlayer::postScanSources() { } void NuPlayer::openAudioSink(const sp &format, bool offloadOnly) { - ALOGV("openAudioSink: offloadOnly(%d) mOffloadAudio(%d)", - offloadOnly, mOffloadAudio); - bool audioSinkChanged = false; - - int32_t numChannels; - CHECK(format->findInt32("channel-count", &numChannels)); - - int32_t channelMask; - if (!format->findInt32("channel-mask", &channelMask)) { - // signal to the AudioSink to derive the mask from count. - channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; - } - - int32_t sampleRate; - CHECK(format->findInt32("sample-rate", &sampleRate)); - uint32_t flags; int64_t durationUs; + bool hasVideo = (mVideoDecoder != NULL); // FIXME: we should handle the case where the video decoder // is created after we receive the format change indication. // Current code will just make that we select deep buffer // with video which should not be a problem as it should // not prevent from keeping A/V sync. - if (mVideoDecoder == NULL && + if (hasVideo && mSource->getDuration(&durationUs) == OK && durationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) { @@ -1144,114 +1128,18 @@ void NuPlayer::openAudioSink(const sp &format, bool offloadOnly) { flags = AUDIO_OUTPUT_FLAG_NONE; } - if (mOffloadAudio) { - audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT; - AString mime; - CHECK(format->findString("mime", &mime)); - status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str()); + mOffloadAudio = mRenderer->openAudioSink( + format, offloadOnly, hasVideo, flags); - if (err != OK) { - ALOGE("Couldn't map mime \"%s\" to a valid " - "audio_format", mime.c_str()); - mOffloadAudio = false; - } else { - ALOGV("Mime \"%s\" mapped to audio_format 0x%x", - mime.c_str(), audioFormat); - - int avgBitRate = -1; - format->findInt32("bit-rate", &avgBitRate); - - int32_t aacProfile = -1; - if (audioFormat == AUDIO_FORMAT_AAC - && format->findInt32("aac-profile", &aacProfile)) { - // Redefine AAC format as per aac profile - mapAACProfileToAudioFormat( - audioFormat, - aacProfile); - } - - audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER; - offloadInfo.duration_us = -1; - format->findInt64( - "durationUs", &offloadInfo.duration_us); - offloadInfo.sample_rate = sampleRate; - offloadInfo.channel_mask = channelMask; - offloadInfo.format = audioFormat; - offloadInfo.stream_type = AUDIO_STREAM_MUSIC; - offloadInfo.bit_rate = avgBitRate; - offloadInfo.has_video = (mVideoDecoder != NULL); - offloadInfo.is_streaming = true; - - if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) { - ALOGV("openAudioSink: no change in offload mode"); - return; // no change from previous configuration, everything ok. - } - ALOGV("openAudioSink: try to open AudioSink in offload mode"); - flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; - flags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER; - audioSinkChanged = true; - mAudioSink->close(); - err = mAudioSink->open( - sampleRate, - numChannels, - (audio_channel_mask_t)channelMask, - audioFormat, - 8 /* bufferCount */, - &NuPlayer::Renderer::AudioSinkCallback, - mRenderer.get(), - (audio_output_flags_t)flags, - &offloadInfo); - - if (err == OK) { - // If the playback is offloaded to h/w, we pass - // the HAL some metadata information. - // We don't want to do this for PCM because it - // will be going through the AudioFlinger mixer - // before reaching the hardware. - sp audioMeta = - mSource->getFormatMeta(true /* audio */); - sendMetaDataToHal(mAudioSink, audioMeta); - mCurrentOffloadInfo = offloadInfo; - err = mAudioSink->start(); - ALOGV_IF(err == OK, "openAudioSink: offload succeeded"); - } - if (err != OK) { - // Clean up, fall back to non offload mode. - mAudioSink->close(); - mRenderer->signalDisableOffloadAudio(); - mOffloadAudio = false; - mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; - ALOGV("openAudioSink: offload failed"); - } - } - } - if (!offloadOnly && !mOffloadAudio) { - flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; - ALOGV("openAudioSink: open AudioSink in NON-offload mode"); - - audioSinkChanged = true; - mAudioSink->close(); - mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; - CHECK_EQ(mAudioSink->open( - sampleRate, - numChannels, - (audio_channel_mask_t)channelMask, - AUDIO_FORMAT_PCM_16_BIT, - 8 /* bufferCount */, - NULL, - NULL, - (audio_output_flags_t)flags), - (status_t)OK); - mAudioSink->start(); - } - if (audioSinkChanged) { - mRenderer->signalAudioSinkChanged(); + if (mOffloadAudio) { + sp audioMeta = + mSource->getFormatMeta(true /* audio */); + sendMetaDataToHal(mAudioSink, audioMeta); } } void NuPlayer::closeAudioSink() { - mAudioSink->close(); - mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; + mRenderer->closeAudioSink(); } status_t NuPlayer::instantiateDecoder(bool audio, sp *decoder) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index c61510c..d6120d2 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -132,7 +132,6 @@ private: sp mVideoDecoder; bool mVideoIsAVC; bool mOffloadAudio; - audio_offload_info_t mCurrentOffloadInfo; sp mAudioDecoder; sp mCCDecoder; sp mRenderer; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 7b9dbb7..e5c83dd 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -80,7 +81,8 @@ NuPlayer::Renderer::Renderer( mVideoRenderingStartGeneration(0), mAudioRenderingStartGeneration(0), mAudioOffloadPauseTimeoutGeneration(0), - mAudioOffloadTornDown(false) { + mAudioOffloadTornDown(false), + mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER) { readProperties(); } @@ -237,8 +239,72 @@ void NuPlayer::Renderer::setPauseStartedTimeRealUs(int64_t realUs) { mPauseStartedTimeRealUs = realUs; } +bool NuPlayer::Renderer::openAudioSink( + const sp &format, + bool offloadOnly, + bool hasVideo, + uint32_t flags) { + sp msg = new AMessage(kWhatOpenAudioSink, id()); + msg->setMessage("format", format); + msg->setInt32("offload-only", offloadOnly); + msg->setInt32("has-video", hasVideo); + msg->setInt32("flags", flags); + + sp response; + msg->postAndAwaitResponse(&response); + + int32_t offload; + CHECK(response->findInt32("offload", &offload)); + return (offload != 0); +} + +void NuPlayer::Renderer::closeAudioSink() { + sp msg = new AMessage(kWhatCloseAudioSink, id()); + + sp response; + msg->postAndAwaitResponse(&response); +} + void NuPlayer::Renderer::onMessageReceived(const sp &msg) { switch (msg->what()) { + case kWhatOpenAudioSink: + { + sp format; + CHECK(msg->findMessage("format", &format)); + + int32_t offloadOnly; + CHECK(msg->findInt32("offload-only", &offloadOnly)); + + int32_t hasVideo; + CHECK(msg->findInt32("has-video", &hasVideo)); + + uint32_t flags; + CHECK(msg->findInt32("flags", (int32_t *)&flags)); + + bool offload = onOpenAudioSink(format, offloadOnly, hasVideo, flags); + + sp response = new AMessage; + response->setInt32("offload", offload); + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + response->postReply(replyID); + + break; + } + + case kWhatCloseAudioSink: + { + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + onCloseAudioSink(); + + sp response = new AMessage; + response->postReply(replyID); + break; + } + case kWhatStopAudioSink: { mAudioSink->stop(); @@ -1162,5 +1228,136 @@ void NuPlayer::Renderer::cancelAudioOffloadPauseTimeout() { } } +bool NuPlayer::Renderer::onOpenAudioSink( + const sp &format, + bool offloadOnly, + bool hasVideo, + uint32_t flags) { + ALOGV("openAudioSink: offloadOnly(%d) offloadingAudio(%d)", + offloadOnly, offloadingAudio()); + bool audioSinkChanged = false; + + int32_t numChannels; + CHECK(format->findInt32("channel-count", &numChannels)); + + int32_t channelMask; + if (!format->findInt32("channel-mask", &channelMask)) { + // signal to the AudioSink to derive the mask from count. + channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; + } + + int32_t sampleRate; + CHECK(format->findInt32("sample-rate", &sampleRate)); + + if (offloadingAudio()) { + audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT; + AString mime; + CHECK(format->findString("mime", &mime)); + status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str()); + + if (err != OK) { + ALOGE("Couldn't map mime \"%s\" to a valid " + "audio_format", mime.c_str()); + onDisableOffloadAudio(); + } else { + ALOGV("Mime \"%s\" mapped to audio_format 0x%x", + mime.c_str(), audioFormat); + + int avgBitRate = -1; + format->findInt32("bit-rate", &avgBitRate); + + int32_t aacProfile = -1; + if (audioFormat == AUDIO_FORMAT_AAC + && format->findInt32("aac-profile", &aacProfile)) { + // Redefine AAC format as per aac profile + mapAACProfileToAudioFormat( + audioFormat, + aacProfile); + } + + audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER; + offloadInfo.duration_us = -1; + format->findInt64( + "durationUs", &offloadInfo.duration_us); + offloadInfo.sample_rate = sampleRate; + offloadInfo.channel_mask = channelMask; + offloadInfo.format = audioFormat; + offloadInfo.stream_type = AUDIO_STREAM_MUSIC; + offloadInfo.bit_rate = avgBitRate; + offloadInfo.has_video = hasVideo; + offloadInfo.is_streaming = true; + + if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) { + ALOGV("openAudioSink: no change in offload mode"); + // no change from previous configuration, everything ok. + return offloadingAudio(); + } + ALOGV("openAudioSink: try to open AudioSink in offload mode"); + flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; + flags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER; + audioSinkChanged = true; + mAudioSink->close(); + err = mAudioSink->open( + sampleRate, + numChannels, + (audio_channel_mask_t)channelMask, + audioFormat, + 8 /* bufferCount */, + &NuPlayer::Renderer::AudioSinkCallback, + this, + (audio_output_flags_t)flags, + &offloadInfo); + + if (err == OK) { + // If the playback is offloaded to h/w, we pass + // the HAL some metadata information. + // We don't want to do this for PCM because it + // will be going through the AudioFlinger mixer + // before reaching the hardware. + // TODO + mCurrentOffloadInfo = offloadInfo; + err = mAudioSink->start(); + ALOGV_IF(err == OK, "openAudioSink: offload succeeded"); + } + if (err != OK) { + // Clean up, fall back to non offload mode. + mAudioSink->close(); + onDisableOffloadAudio(); + mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; + ALOGV("openAudioSink: offload failed"); + } + } + } + if (!offloadOnly && !offloadingAudio()) { + flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; + ALOGV("openAudioSink: open AudioSink in NON-offload mode"); + + audioSinkChanged = true; + mAudioSink->close(); + mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; + CHECK_EQ(mAudioSink->open( + sampleRate, + numChannels, + (audio_channel_mask_t)channelMask, + AUDIO_FORMAT_PCM_16_BIT, + 8 /* bufferCount */, + NULL, + NULL, + (audio_output_flags_t)flags), + (status_t)OK); + mAudioSink->start(); + } + if (audioSinkChanged) { + onAudioSinkChanged(); + } + + return offloadingAudio(); +} + +void NuPlayer::Renderer::onCloseAudioSink() { + mAudioSink->close(); + mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; +} + } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index db1dab6..3e30226 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -70,6 +70,13 @@ struct NuPlayer::Renderer : public AHandler { int64_t getVideoLateByUs(); void setPauseStartedTimeRealUs(int64_t realUs); + bool openAudioSink( + const sp &format, + bool offloadOnly, + bool hasVideo, + uint32_t flags); + void closeAudioSink(); + enum { kWhatEOS = 'eos ', kWhatFlushComplete = 'fluC', @@ -100,6 +107,8 @@ private: kWhatAudioSinkChanged = 'auSC', kWhatPause = 'paus', kWhatResume = 'resm', + kWhatOpenAudioSink = 'opnA', + kWhatCloseAudioSink = 'clsA', kWhatStopAudioSink = 'stpA', kWhatDisableOffloadAudio = 'noOA', kWhatSetVideoFrameRate = 'sVFR', @@ -158,6 +167,7 @@ private: int32_t mAudioOffloadPauseTimeoutGeneration; bool mAudioOffloadTornDown; + audio_offload_info_t mCurrentOffloadInfo; size_t fillAudioBuffer(void *buffer, size_t size); @@ -183,6 +193,12 @@ private: void onResume(); void onSetVideoFrameRate(float fps); void onAudioOffloadTearDown(AudioOffloadTearDownReason reason); + bool onOpenAudioSink( + const sp &format, + bool offloadOnly, + bool hasVideo, + uint32_t flags); + void onCloseAudioSink(); void notifyEOS(bool audio, status_t finalResult, int64_t delayUs = 0); void notifyFlushComplete(bool audio); -- cgit v1.1 From c2813e568aa476e03d159529c0af28c99536db8d Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Thu, 16 Oct 2014 17:54:34 -0700 Subject: Fix AudioTrack retrograde getPosition when restoring tracks mReleased represents the number of frames written to the track, but was cleared on start() causing a mismatch if the client wrote to the track before starting. Moved the clearing to entering the STATE_STOPPED or STATE_FLUSHED state. Bug: 18017947 Bug: 18022276 Change-Id: I3788c98c4c3c4d9cc004378432797b3f3138e22e --- media/libmedia/AudioTrack.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 8e0704f..0a89fbb 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -464,7 +464,6 @@ status_t AudioTrack::start() if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) { // reset current position as seen by client to 0 mPosition = 0; - mReleased = 0; // For offloaded tracks, we don't know if the hardware counters are really zero here, // since the flush is asynchronous and stop may not fully drain. // We save the time when the track is started to later verify whether @@ -529,6 +528,7 @@ void AudioTrack::stop() mState = STATE_STOPPING; } else { mState = STATE_STOPPED; + mReleased = 0; } mProxy->interrupt(); @@ -585,6 +585,7 @@ void AudioTrack::flush_l() mRefreshRemaining = true; mState = STATE_FLUSHED; + mReleased = 0; if (isOffloaded_l()) { mProxy->interrupt(); } @@ -1625,6 +1626,7 @@ nsecs_t AudioTrack::processAudioBuffer() waitStreamEnd = mState == STATE_STOPPING; if (waitStreamEnd) { mState = STATE_STOPPED; + mReleased = 0; } } if (waitStreamEnd && status != DEAD_OBJECT) { @@ -1873,6 +1875,7 @@ status_t AudioTrack::restoreTrack_l(const char *from) if (result != NO_ERROR) { ALOGW("restoreTrack_l() failed status %d", result); mState = STATE_STOPPED; + mReleased = 0; } return result; -- cgit v1.1 From eecb7805bbbb712925d4372c505f8c7f5c4fb5ed Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Sun, 19 Oct 2014 23:12:50 -0700 Subject: NuPlayer: set anchor time for each audio buffer. And use anchor time to compute current position Bug: 17999949 Bug: 18008307 Bug: 18032127 Change-Id: Ie493c9a1d45d7b788aef65d863f710da6326fcc1 --- .../nuplayer/NuPlayerRenderer.cpp | 77 ++++++++++++---------- .../nuplayer/NuPlayerRenderer.h | 7 +- 2 files changed, 48 insertions(+), 36 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index e5c83dd..46a2590 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -66,8 +66,8 @@ NuPlayer::Renderer::Renderer( mAudioQueueGeneration(0), mVideoQueueGeneration(0), mAudioFirstAnchorTimeMediaUs(-1), - mVideoAnchorTimeMediaUs(-1), - mVideoAnchorTimeRealUs(-1), + mAnchorTimeMediaUs(-1), + mAnchorTimeRealUs(-1), mVideoLateByUs(0ll), mHasAudio(false), mHasVideo(false), @@ -140,7 +140,7 @@ void NuPlayer::Renderer::signalTimeDiscontinuity() { // CHECK(mAudioQueue.empty()); // CHECK(mVideoQueue.empty()); setAudioFirstAnchorTime(-1); - setVideoAnchorTime(-1, -1); + setAnchorTime(-1, -1); setVideoLateByUs(0); mSyncQueues = false; } @@ -177,22 +177,19 @@ status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs, int64_t nowUs) return NO_INIT; } - int64_t positionUs = 0; - if (!mHasAudio) { - if (mVideoAnchorTimeMediaUs < 0) { - return NO_INIT; - } - positionUs = (nowUs - mVideoAnchorTimeRealUs) + mVideoAnchorTimeMediaUs; + if (mAnchorTimeMediaUs < 0) { + return NO_INIT; + } + int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs; - if (mPauseStartedTimeRealUs != -1) { - positionUs -= (nowUs - mPauseStartedTimeRealUs); - } - } else { - if (mAudioFirstAnchorTimeMediaUs < 0) { - return NO_INIT; - } - positionUs = mAudioFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs); + if (mPauseStartedTimeRealUs != -1) { + positionUs -= (nowUs - mPauseStartedTimeRealUs); + } + + if (positionUs < mAudioFirstAnchorTimeMediaUs) { + positionUs = mAudioFirstAnchorTimeMediaUs; } + *mediaUs = (positionUs <= 0) ? 0 : positionUs; return OK; } @@ -218,10 +215,13 @@ void NuPlayer::Renderer::setAudioFirstAnchorTimeIfNeeded(int64_t mediaUs) { } } -void NuPlayer::Renderer::setVideoAnchorTime(int64_t mediaUs, int64_t realUs) { +void NuPlayer::Renderer::setAnchorTime(int64_t mediaUs, int64_t realUs, bool resume) { Mutex::Autolock autoLock(mTimeLock); - mVideoAnchorTimeMediaUs = mediaUs; - mVideoAnchorTimeRealUs = realUs; + mAnchorTimeMediaUs = mediaUs; + mAnchorTimeRealUs = realUs; + if (resume) { + mPauseStartedTimeRealUs = -1; + } } void NuPlayer::Renderer::setVideoLateByUs(int64_t lateUs) { @@ -526,7 +526,7 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { int64_t mediaTimeUs; CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); - setAudioFirstAnchorTimeIfNeeded(mediaTimeUs); + onNewAudioMediaTime(mediaTimeUs); } size_t copy = entry->mBuffer->size() - entry->mOffset; @@ -597,8 +597,7 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { int64_t mediaTimeUs; CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); - - setAudioFirstAnchorTimeIfNeeded(mediaTimeUs); + onNewAudioMediaTime(mediaTimeUs); } size_t copy = entry->mBuffer->size() - entry->mOffset; @@ -659,11 +658,24 @@ int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) { int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) { int64_t currentPositionUs; if (getCurrentPosition(¤tPositionUs, nowUs) != OK) { - currentPositionUs = 0; + // If failed to get current position, e.g. due to audio clock is not ready, then just + // play out video immediately without delay. + return nowUs; } return (mediaTimeUs - currentPositionUs) + nowUs; } +void NuPlayer::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) { + // TRICKY: vorbis decoder generates multiple frames with the same + // timestamp, so only update on the first frame with a given timestamp + if (mediaTimeUs == mAnchorTimeMediaUs) { + return; + } + setAudioFirstAnchorTimeIfNeeded(mediaTimeUs); + int64_t nowUs = ALooper::GetNowUs(); + setAnchorTime(mediaTimeUs, nowUs + getPendingAudioPlayoutDurationUs(nowUs)); +} + void NuPlayer::Renderer::postDrainVideoQueue() { if (mDrainVideoQueuePending || mSyncQueues @@ -698,8 +710,8 @@ void NuPlayer::Renderer::postDrainVideoQueue() { int64_t mediaTimeUs; CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); - if (mVideoAnchorTimeMediaUs < 0) { - setVideoAnchorTime(mediaTimeUs, nowUs); + if (mAnchorTimeMediaUs < 0) { + setAnchorTime(mediaTimeUs, nowUs); realTimeUs = nowUs; } else { realTimeUs = getRealTimeUs(mediaTimeUs, nowUs); @@ -769,14 +781,14 @@ void NuPlayer::Renderer::onDrainVideoQueue() { } else { ALOGV("rendering video at media time %.2f secs", (mFlags & FLAG_REAL_TIME ? realTimeUs : - (realTimeUs + mVideoAnchorTimeMediaUs - mVideoAnchorTimeRealUs)) / 1E6); + (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6); } } else { setVideoLateByUs(0); - if (!mVideoSampleReceived) { + if (!mVideoSampleReceived && !mHasAudio) { // This will ensure that the first frame after a flush won't be used as anchor // when renderer is in paused state, because resume can happen any time after seek. - setVideoAnchorTime(-1, -1); + setAnchorTime(-1, -1); } } @@ -1108,9 +1120,8 @@ void NuPlayer::Renderer::onResume() { mPaused = false; if (mPauseStartedTimeRealUs != -1) { int64_t newAnchorRealUs = - mVideoAnchorTimeRealUs + ALooper::GetNowUs() - mPauseStartedTimeRealUs; - setVideoAnchorTime(mVideoAnchorTimeMediaUs, newAnchorRealUs); - setPauseStartedTimeRealUs(-1); + mAnchorTimeRealUs + ALooper::GetNowUs() - mPauseStartedTimeRealUs; + setAnchorTime(mAnchorTimeMediaUs, newAnchorRealUs, true /* resume */); } if (!mAudioQueue.empty()) { @@ -1175,7 +1186,7 @@ int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) { // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours. //CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test - int64_t durationUs = (int32_t)numFramesPlayed * 1000LL * mAudioSink->msecsPerFrame() + int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000LL * mAudioSink->msecsPerFrame()) + nowUs - numFramesPlayedAt; if (durationUs < 0) { // Occurs when numFramesPlayed position is very small and the following: diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 3e30226..7079f85 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -65,7 +65,7 @@ struct NuPlayer::Renderer : public AHandler { void setHasMedia(bool audio); void setAudioFirstAnchorTime(int64_t mediaUs); void setAudioFirstAnchorTimeIfNeeded(int64_t mediaUs); - void setVideoAnchorTime(int64_t mediaUs, int64_t realUs); + void setAnchorTime(int64_t mediaUs, int64_t realUs, bool resume = false); void setVideoLateByUs(int64_t lateUs); int64_t getVideoLateByUs(); void setPauseStartedTimeRealUs(int64_t realUs); @@ -144,8 +144,8 @@ private: // |mTimeLock|. // TODO: move those members to a seperated media clock class. int64_t mAudioFirstAnchorTimeMediaUs; - int64_t mVideoAnchorTimeMediaUs; - int64_t mVideoAnchorTimeRealUs; + int64_t mAnchorTimeMediaUs; + int64_t mAnchorTimeRealUs; int64_t mVideoLateByUs; bool mHasAudio; bool mHasVideo; @@ -176,6 +176,7 @@ private: int64_t getPlayedOutAudioDurationUs(int64_t nowUs); void postDrainAudioQueue_l(int64_t delayUs = 0); + void onNewAudioMediaTime(int64_t mediaTimeUs); int64_t getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs); void onDrainVideoQueue(); -- cgit v1.1 From d5923409bbcbb22954a92c2b497ef4492d7cb6a5 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 20 Oct 2014 17:47:54 -0700 Subject: mediaplayer: limit scheduling video frames into the future This addresses when video timestamps jumps before an audio timestamp, but still works on slideshow video clips (<=1fps). This, however, will not skip time-changes on video-only live video streams, as we cannot distinguish live slideshow video clips from non-slideshow ones. Bug: 18032127 Change-Id: I959a714edfe1c8cf3b84704c693dcd1b3e5b7855 --- .../nuplayer/NuPlayerRenderer.cpp | 39 +++++++++++++++++++++- .../nuplayer/NuPlayerRenderer.h | 5 +++ 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'media') diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 46a2590..638d9bc 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -82,7 +82,9 @@ NuPlayer::Renderer::Renderer( mAudioRenderingStartGeneration(0), mAudioOffloadPauseTimeoutGeneration(0), mAudioOffloadTornDown(false), - mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER) { + mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER), + mTotalBuffersQueued(0), + mLastAudioBufferDrained(0) { readProperties(); } @@ -361,6 +363,19 @@ void NuPlayer::Renderer::onMessageReceived(const sp &msg) { break; } + case kWhatPostDrainVideoQueue: + { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + if (generation != mVideoQueueGeneration) { + break; + } + + mDrainVideoQueuePending = false; + postDrainVideoQueue(); + break; + } + case kWhatQueueBuffer: { onQueueBuffer(msg); @@ -580,6 +595,8 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) { QueueEntry *entry = &*mAudioQueue.begin(); + mLastAudioBufferDrained = entry->mBufferOrdinal; + if (entry->mBuffer == NULL) { // EOS int64_t postEOSDelayUs = 0; @@ -716,6 +733,25 @@ void NuPlayer::Renderer::postDrainVideoQueue() { } else { realTimeUs = getRealTimeUs(mediaTimeUs, nowUs); } + + // Heuristics to handle situation when media time changed without a + // discontinuity. If we have not drained an audio buffer that was + // received after this buffer, repost in 10 msec. Otherwise repost + // in 500 msec. + delayUs = realTimeUs - nowUs; + if (delayUs > 500000) { + int64_t postDelayUs = 500000; + if (mHasAudio && (mLastAudioBufferDrained - entry.mBufferOrdinal) <= 0) { + postDelayUs = 10000; + } + msg->setWhat(kWhatPostDrainVideoQueue); + msg->post(postDelayUs); + mVideoScheduler->restart(); + ALOGI("possible video time jump of %dms, retrying in %dms", + (int)(delayUs / 1000), (int)(postDelayUs / 1000)); + mDrainVideoQueuePending = true; + return; + } } realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000; @@ -855,6 +891,7 @@ void NuPlayer::Renderer::onQueueBuffer(const sp &msg) { entry.mNotifyConsumed = notifyConsumed; entry.mOffset = 0; entry.mFinalResult = OK; + entry.mBufferOrdinal = ++mTotalBuffersQueued; if (audio) { Mutex::Autolock autoLock(mLock); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 7079f85..b15a266 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -101,6 +101,7 @@ private: enum { kWhatDrainAudioQueue = 'draA', kWhatDrainVideoQueue = 'draV', + kWhatPostDrainVideoQueue = 'pDVQ', kWhatQueueBuffer = 'queB', kWhatQueueEOS = 'qEOS', kWhatFlush = 'flus', @@ -119,6 +120,7 @@ private: sp mNotifyConsumed; size_t mOffset; status_t mFinalResult; + int32_t mBufferOrdinal; }; static const int64_t kMinPositionUpdateDelayUs; @@ -169,6 +171,9 @@ private: bool mAudioOffloadTornDown; audio_offload_info_t mCurrentOffloadInfo; + int32_t mTotalBuffersQueued; + int32_t mLastAudioBufferDrained; + size_t fillAudioBuffer(void *buffer, size_t size); bool onDrainAudioQueue(); -- cgit v1.1