diff options
52 files changed, 895 insertions, 246 deletions
diff --git a/cmds/screenrecord/FrameOutput.h b/cmds/screenrecord/FrameOutput.h index b8e9e68..bb66e05 100644 --- a/cmds/screenrecord/FrameOutput.h +++ b/cmds/screenrecord/FrameOutput.h @@ -34,9 +34,6 @@ public: mExtTextureName(0), mPixelBuf(NULL) {} - virtual ~FrameOutput() { - delete[] mPixelBuf; - } // Create an "input surface", similar in purpose to a MediaCodec input // surface, that the virtual display can send buffers to. Also configures @@ -59,6 +56,11 @@ private: FrameOutput(const FrameOutput&); FrameOutput& operator=(const FrameOutput&); + // Destruction via RefBase. + virtual ~FrameOutput() { + delete[] mPixelBuf; + } + // (overrides GLConsumer::FrameAvailableListener method) virtual void onFrameAvailable(); diff --git a/cmds/screenrecord/Overlay.h b/cmds/screenrecord/Overlay.h index b8473b4..48e48e0 100644 --- a/cmds/screenrecord/Overlay.h +++ b/cmds/screenrecord/Overlay.h @@ -47,7 +47,6 @@ public: mLastFrameNumber(-1), mTotalDroppedFrames(0) {} - virtual ~Overlay() { assert(mState == UNINITIALIZED || mState == STOPPED); } // Creates a thread that performs the overlay. Pass in the surface that // output will be sent to. @@ -71,6 +70,9 @@ private: Overlay(const Overlay&); Overlay& operator=(const Overlay&); + // Destruction via RefBase. + virtual ~Overlay() { assert(mState == UNINITIALIZED || mState == STOPPED); } + // Draw the initial info screen. static void doDrawInfoPage(const EglWindow& window, const Program& texRender, TextRenderer& textRenderer); diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index 7e9d557..7d23d02 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -746,6 +746,7 @@ protected: bool mInUnderrun; // whether track is currently in underrun state String8 mName; // server's name for this IAudioTrack + uint32_t mPausedPosition; private: class DeathNotifier : public IBinder::DeathRecipient { diff --git a/include/media/nbaio/AudioStreamInSource.h b/include/media/nbaio/AudioStreamInSource.h index 07d8c89..eaea63c 100644 --- a/include/media/nbaio/AudioStreamInSource.h +++ b/include/media/nbaio/AudioStreamInSource.h @@ -43,7 +43,7 @@ public: // This is an over-estimate, and could dupe the caller into making a blocking read() // FIXME Use an audio HAL API to query the buffer filling status when it's available. - virtual ssize_t availableToRead() { return mStreamBufferSizeBytes >> mBitShift; } + virtual ssize_t availableToRead() { return mStreamBufferSizeBytes / mFrameSize; } virtual ssize_t read(void *buffer, size_t count); diff --git a/include/media/nbaio/AudioStreamOutSink.h b/include/media/nbaio/AudioStreamOutSink.h index 7948d40..9949b88 100644 --- a/include/media/nbaio/AudioStreamOutSink.h +++ b/include/media/nbaio/AudioStreamOutSink.h @@ -43,7 +43,7 @@ public: // This is an over-estimate, and could dupe the caller into making a blocking write() // FIXME Use an audio HAL API to query the buffer emptying status when it's available. - virtual ssize_t availableToWrite() const { return mStreamBufferSizeBytes >> mBitShift; } + virtual ssize_t availableToWrite() const { return mStreamBufferSizeBytes / mFrameSize; } virtual ssize_t write(const void *buffer, size_t count); diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h index 56896b9..be0c15b 100644 --- a/include/media/nbaio/NBAIO.h +++ b/include/media/nbaio/NBAIO.h @@ -29,6 +29,7 @@ #include <utils/Errors.h> #include <utils/RefBase.h> #include <media/AudioTimestamp.h> +#include <system/audio.h> namespace android { @@ -53,8 +54,12 @@ enum { // too large, then this decision should be re-visited. // Sample rate and channel count are explicit, PCM interleaved 16-bit is assumed. struct NBAIO_Format { +// FIXME make this a class, and change Format_... global methods to class methods //private: - unsigned mPacked; + unsigned mSampleRate; + unsigned mChannelCount; + audio_format_t mFormat; + size_t mFrameSize; }; extern const NBAIO_Format Format_Invalid; @@ -62,13 +67,9 @@ extern const NBAIO_Format Format_Invalid; // Return the frame size of an NBAIO_Format in bytes size_t Format_frameSize(const NBAIO_Format& format); -// Return the frame size of an NBAIO_Format as a bit shift -// or -1 if frame size is not a power of 2 -int Format_frameBitShift(const NBAIO_Format& format); - // Convert a sample rate in Hz and channel count to an NBAIO_Format -// FIXME The sample format is hard-coded to AUDIO_FORMAT_PCM_16_BIT -NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount); +// FIXME rename +NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount, audio_format_t format); // Return the sample rate in Hz of an NBAIO_Format unsigned Format_sampleRate(const NBAIO_Format& format); @@ -126,14 +127,14 @@ public: protected: NBAIO_Port(const NBAIO_Format& format) : mNegotiated(false), mFormat(format), - mBitShift(Format_frameBitShift(format)) { } + mFrameSize(Format_frameSize(format)) { } virtual ~NBAIO_Port() { } // Implementations are free to ignore these if they don't need them bool mNegotiated; // mNegotiated implies (mFormat != Format_Invalid) NBAIO_Format mFormat; // (mFormat != Format_Invalid) does not imply mNegotiated - size_t mBitShift; // assign in parallel with any assignment to mFormat + size_t mFrameSize; // assign in parallel with any assignment to mFormat }; // Abstract class (interface) representing a non-blocking data sink, for use by a data provider. diff --git a/include/media/nbaio/SourceAudioBufferProvider.h b/include/media/nbaio/SourceAudioBufferProvider.h index cdfb6fe..daf6bc3 100644 --- a/include/media/nbaio/SourceAudioBufferProvider.h +++ b/include/media/nbaio/SourceAudioBufferProvider.h @@ -41,7 +41,7 @@ public: private: const sp<NBAIO_Source> mSource; // the wrapped source - /*const*/ size_t mFrameBitShift; // log2(frame size in bytes) + /*const*/ size_t mFrameSize; // frame size in bytes void* mAllocated; // pointer to base of allocated memory size_t mSize; // size of mAllocated in frames size_t mOffset; // frame offset within mAllocated of valid data diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h index cf5beda..678d642 100644 --- a/include/media/stagefright/MediaDefs.h +++ b/include/media/stagefright/MediaDefs.h @@ -38,6 +38,7 @@ extern const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II; extern const char *MEDIA_MIMETYPE_AUDIO_AAC; extern const char *MEDIA_MIMETYPE_AUDIO_QCELP; extern const char *MEDIA_MIMETYPE_AUDIO_VORBIS; +extern const char *MEDIA_MIMETYPE_AUDIO_OPUS; extern const char *MEDIA_MIMETYPE_AUDIO_G711_ALAW; extern const char *MEDIA_MIMETYPE_AUDIO_G711_MLAW; extern const char *MEDIA_MIMETYPE_AUDIO_RAW; diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index db8216b..e862ec3 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -56,6 +56,9 @@ enum { kKeyD263 = 'd263', // raw data kKeyVorbisInfo = 'vinf', // raw data kKeyVorbisBooks = 'vboo', // raw data + kKeyOpusHeader = 'ohdr', // raw data + kKeyOpusCodecDelay = 'ocod', // uint64_t (codec delay in ns) + kKeyOpusSeekPreRoll = 'ospr', // uint64_t (seek preroll in ns) kKeyWantsNALFragments = 'NALf', kKeyIsSyncFrame = 'sync', // int32_t (bool) kKeyIsCodecConfig = 'conf', // int32_t (bool) diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c index d25dc9b..a39d837 100644 --- a/media/libeffects/downmix/EffectDownmix.c +++ b/media/libeffects/downmix/EffectDownmix.c @@ -699,7 +699,7 @@ int Downmix_Reset(downmix_object_t *pDownmixer, bool init) { * *---------------------------------------------------------------------------- */ -int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, size_t size, void *pValue) { +int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue) { int16_t value16; ALOGV("Downmix_setParameter, context %p, param %d, value16 %d, value32 %d", @@ -709,7 +709,7 @@ int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, size_t siz case DOWNMIX_PARAM_TYPE: if (size != sizeof(downmix_type_t)) { - ALOGE("Downmix_setParameter(DOWNMIX_PARAM_TYPE) invalid size %zu, should be %zu", + ALOGE("Downmix_setParameter(DOWNMIX_PARAM_TYPE) invalid size %u, should be %zu", size, sizeof(downmix_type_t)); return -EINVAL; } @@ -755,7 +755,7 @@ int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, size_t siz * *---------------------------------------------------------------------------- */ -int Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, size_t *pSize, void *pValue) { +int Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue) { int16_t *pValue16; switch (param) { diff --git a/media/libeffects/downmix/EffectDownmix.h b/media/libeffects/downmix/EffectDownmix.h index cb6b957..fcb3c9e 100644 --- a/media/libeffects/downmix/EffectDownmix.h +++ b/media/libeffects/downmix/EffectDownmix.h @@ -93,8 +93,8 @@ static int Downmix_GetDescriptor(effect_handle_t self, int Downmix_Init(downmix_module_t *pDwmModule); int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bool init); int Downmix_Reset(downmix_object_t *pDownmixer, bool init); -int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, size_t size, void *pValue); -int Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, size_t *pSize, void *pValue); +int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue); +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); diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c index 32c4ce0..35e5bc8 100644 --- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c +++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c @@ -178,7 +178,7 @@ LVDBE_ReturnStatus_en LVDBE_Init(LVDBE_Handle_t *phInstance, { return(LVDBE_NULLADDRESS); } - if (((LVM_UINT32)pMemoryTable->Region[i].pBaseAddress % pMemoryTable->Region[i].Alignment)!=0){ + if (((uintptr_t)pMemoryTable->Region[i].pBaseAddress % pMemoryTable->Region[i].Alignment)!=0){ return(LVDBE_ALIGNMENTERROR); } } diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c index 794271b..f5a01f3 100644 --- a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c +++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c @@ -99,7 +99,7 @@ LVM_ReturnStatus_en LVM_Process(LVM_Handle_t hInstance, /* * Check the buffer alignment */ - if((((LVM_UINT32)pInData % 4) != 0) || (((LVM_UINT32)pOutData % 4) != 0)) + if((((uintptr_t)pInData % 4) != 0) || (((uintptr_t)pOutData % 4) != 0)) { return(LVM_ALIGNMENTERROR); } diff --git a/media/libeffects/lvm/lib/Common/lib/InstAlloc.h b/media/libeffects/lvm/lib/Common/lib/InstAlloc.h index c6954f2..7f725f4 100644 --- a/media/libeffects/lvm/lib/Common/lib/InstAlloc.h +++ b/media/libeffects/lvm/lib/Common/lib/InstAlloc.h @@ -29,7 +29,7 @@ extern "C" { typedef struct { LVM_UINT32 TotalSize; /* Accumulative total memory size */ - LVM_UINT32 pNextMember; /* Pointer to the next instance member to be allocated */ + uintptr_t pNextMember; /* Pointer to the next instance member to be allocated */ } INST_ALLOC; diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h index 81655dd..0c6fb25 100644 --- a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h +++ b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h @@ -29,6 +29,7 @@ extern "C" { #endif /* __cplusplus */ +#include <stdint.h> /****************************************************************************************/ /* */ @@ -85,14 +86,14 @@ extern "C" { typedef char LVM_CHAR; /* ASCII character */ -typedef char LVM_INT8; /* Signed 8-bit word */ -typedef unsigned char LVM_UINT8; /* Unsigned 8-bit word */ +typedef int8_t LVM_INT8; /* Signed 8-bit word */ +typedef uint8_t LVM_UINT8; /* Unsigned 8-bit word */ -typedef short LVM_INT16; /* Signed 16-bit word */ -typedef unsigned short LVM_UINT16; /* Unsigned 16-bit word */ +typedef int16_t LVM_INT16; /* Signed 16-bit word */ +typedef uint16_t LVM_UINT16; /* Unsigned 16-bit word */ -typedef long LVM_INT32; /* Signed 32-bit word */ -typedef unsigned long LVM_UINT32; /* Unsigned 32-bit word */ +typedef int32_t LVM_INT32; /* Signed 32-bit word */ +typedef uint32_t LVM_UINT32; /* Unsigned 32-bit word */ /****************************************************************************************/ diff --git a/media/libeffects/lvm/lib/Common/src/InstAlloc.c b/media/libeffects/lvm/lib/Common/src/InstAlloc.c index 481df84..a89a5c3 100644 --- a/media/libeffects/lvm/lib/Common/src/InstAlloc.c +++ b/media/libeffects/lvm/lib/Common/src/InstAlloc.c @@ -30,7 +30,7 @@ void InstAlloc_Init( INST_ALLOC *pms, void *StartAddr ) { pms->TotalSize = 3; - pms->pNextMember = (LVM_UINT32)(((LVM_UINT32)StartAddr + 3) & 0xFFFFFFFC);/* This code will fail if the platform address space is more than 32-bits*/ + pms->pNextMember = (((uintptr_t)StartAddr + 3) & (uintptr_t)~3); } @@ -51,7 +51,7 @@ void* InstAlloc_AddMember( INST_ALLOC *pms, void *NewMemberAddress; /* Variable to temporarily store the return value */ NewMemberAddress = (void*)pms->pNextMember; - Size = ((Size + 3) & 0xFFFFFFFC); /* Ceil the size to a multiple of four */ + Size = ((Size + 3) & (LVM_UINT32)~3); /* Ceil the size to a multiple of four */ pms->TotalSize += Size; pms->pNextMember += Size; @@ -84,30 +84,30 @@ LVM_UINT32 InstAlloc_GetTotal( INST_ALLOC *pms) void InstAlloc_InitAll( INST_ALLOC *pms, LVM_MemoryTable_st *pMemoryTable) { - LVM_UINT32 StartAddr; + uintptr_t StartAddr; - StartAddr = (LVM_UINT32)pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress; + StartAddr = (uintptr_t)pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress; pms[0].TotalSize = 3; - pms[0].pNextMember = (LVM_UINT32)(((LVM_UINT32)StartAddr + 3) & 0xFFFFFFFC); + pms[0].pNextMember = ((StartAddr + 3) & (uintptr_t)~3); - StartAddr = (LVM_UINT32)pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress; + StartAddr = (uintptr_t)pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress; pms[1].TotalSize = 3; - pms[1].pNextMember = (LVM_UINT32)(((LVM_UINT32)StartAddr + 3) & 0xFFFFFFFC); + pms[1].pNextMember = ((StartAddr + 3) & (uintptr_t)~3); - StartAddr = (LVM_UINT32)pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress; + StartAddr = (uintptr_t)pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress; pms[2].TotalSize = 3; - pms[2].pNextMember = (LVM_UINT32)(((LVM_UINT32)StartAddr + 3) & 0xFFFFFFFC); + pms[2].pNextMember = ((StartAddr + 3) & (uintptr_t)~3); - StartAddr = (LVM_UINT32)pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress; + StartAddr = (uintptr_t)pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress; pms[3].TotalSize = 3; - pms[3].pNextMember = (LVM_UINT32)(((LVM_UINT32)StartAddr + 3) & 0xFFFFFFFC); + pms[3].pNextMember = ((StartAddr + 3) & (uintptr_t)~3); } diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c index ac3c740..58f58ed 100644 --- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c +++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c @@ -77,7 +77,7 @@ LVEQNB_ReturnStatus_en LVEQNB_Process(LVEQNB_Handle_t hInstance, } /* Check if the input and output data buffers are 32-bit aligned */ - if ((((LVM_INT32)pInData % 4) != 0) || (((LVM_INT32)pOutData % 4) != 0)) + if ((((uintptr_t)pInData % 4) != 0) || (((uintptr_t)pOutData % 4) != 0)) { return LVEQNB_ALIGNMENTERROR; } diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index 58d7767..db5c78f 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -2813,9 +2813,9 @@ int Effect_command(effect_handle_t self, if(pContext->EffectType == LVM_BASS_BOOST){ if (pCmdData == NULL || - cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) || + cmdSize < (sizeof(effect_param_t) + sizeof(int32_t)) || pReplyData == NULL || - *replySize < (int) (sizeof(effect_param_t) + sizeof(int32_t))){ + *replySize < (sizeof(effect_param_t) + sizeof(int32_t))){ ALOGV("\tLVM_ERROR : BassBoost_command cmdCode Case: " "EFFECT_CMD_GET_PARAM: ERROR"); return -EINVAL; @@ -2844,9 +2844,9 @@ int Effect_command(effect_handle_t self, if(pContext->EffectType == LVM_VIRTUALIZER){ if (pCmdData == NULL || - cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) || + cmdSize < (sizeof(effect_param_t) + sizeof(int32_t)) || pReplyData == NULL || - *replySize < (int) (sizeof(effect_param_t) + sizeof(int32_t))){ + *replySize < (sizeof(effect_param_t) + sizeof(int32_t))){ ALOGV("\tLVM_ERROR : Virtualizer_command cmdCode Case: " "EFFECT_CMD_GET_PARAM: ERROR"); return -EINVAL; @@ -2876,7 +2876,7 @@ int Effect_command(effect_handle_t self, //ALOGV("\tEqualizer_command cmdCode Case: " // "EFFECT_CMD_GET_PARAM start"); if (pCmdData == NULL || - cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) || + cmdSize < (sizeof(effect_param_t) + sizeof(int32_t)) || pReplyData == NULL || *replySize < (int) (sizeof(effect_param_t) + sizeof(int32_t))) { ALOGV("\tLVM_ERROR : Equalizer_command cmdCode Case: " @@ -2908,7 +2908,7 @@ int Effect_command(effect_handle_t self, if(pContext->EffectType == LVM_VOLUME){ //ALOGV("\tVolume_command cmdCode Case: EFFECT_CMD_GET_PARAM start"); if (pCmdData == NULL || - cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) || + cmdSize < (sizeof(effect_param_t) + sizeof(int32_t)) || pReplyData == NULL || *replySize < (int) (sizeof(effect_param_t) + sizeof(int32_t))){ ALOGV("\tLVM_ERROR : Volume_command cmdCode Case: " @@ -2947,7 +2947,7 @@ int Effect_command(effect_handle_t self, // *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t))); if (pCmdData == NULL|| - cmdSize != (int)(sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int16_t))|| + cmdSize != (sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int16_t))|| pReplyData == NULL|| *replySize != sizeof(int32_t)){ ALOGV("\tLVM_ERROR : BassBoost_command cmdCode Case: " @@ -2980,7 +2980,7 @@ int Effect_command(effect_handle_t self, // *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t))); if (pCmdData == NULL|| - cmdSize != (int)(sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int16_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: " @@ -3014,7 +3014,7 @@ int Effect_command(effect_handle_t self, // *replySize, // *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t))); - if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) || + if (pCmdData == NULL || cmdSize < (sizeof(effect_param_t) + sizeof(int32_t)) || pReplyData == NULL || *replySize != sizeof(int32_t)) { ALOGV("\tLVM_ERROR : Equalizer_command cmdCode Case: " "EFFECT_CMD_SET_PARAM: ERROR"); @@ -3034,7 +3034,7 @@ int Effect_command(effect_handle_t self, // *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) +sizeof(int32_t))); if ( pCmdData == NULL|| - cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t))|| + cmdSize < (sizeof(effect_param_t) + sizeof(int32_t))|| pReplyData == NULL|| *replySize != sizeof(int32_t)){ ALOGV("\tLVM_ERROR : Volume_command cmdCode Case: " diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp index 0367302..c6d3759 100644 --- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp +++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp @@ -181,7 +181,7 @@ void Reverb_getConfig (ReverbContext *pContext, effect_config_t *pConfig); int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue); int Reverb_getParameter (ReverbContext *pContext, void *pParam, - size_t *pValueSize, + uint32_t *pValueSize, void *pValue); int Reverb_LoadPreset (ReverbContext *pContext); @@ -1534,7 +1534,7 @@ int Reverb_LoadPreset(ReverbContext *pContext) int Reverb_getParameter(ReverbContext *pContext, void *pParam, - size_t *pValueSize, + uint32_t *pValueSize, void *pValue){ int status = 0; int32_t *pParamTemp = (int32_t *)pParam; @@ -1956,9 +1956,9 @@ int Reverb_command(effect_handle_t self, //ALOGV("\tReverb_command cmdCode Case: " // "EFFECT_CMD_GET_PARAM start"); if (pCmdData == NULL || - cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) || + cmdSize < (sizeof(effect_param_t) + sizeof(int32_t)) || pReplyData == NULL || - *replySize < (int) (sizeof(effect_param_t) + sizeof(int32_t))){ + *replySize < (sizeof(effect_param_t) + sizeof(int32_t))){ ALOGV("\tLVM_ERROR : Reverb_command cmdCode Case: " "EFFECT_CMD_GET_PARAM: ERROR"); return -EINVAL; @@ -1973,7 +1973,7 @@ int Reverb_command(effect_handle_t self, p->status = android::Reverb_getParameter(pContext, (void *)p->data, - (size_t *)&p->vsize, + &p->vsize, p->data + voffset); *replySize = sizeof(effect_param_t) + voffset + p->vsize; @@ -1994,8 +1994,8 @@ int Reverb_command(effect_handle_t self, // *replySize, // *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t))); - if (pCmdData == NULL || (cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t))) - || pReplyData == NULL || *replySize != (int)sizeof(int32_t)) { + if (pCmdData == NULL || (cmdSize < (sizeof(effect_param_t) + sizeof(int32_t))) + || pReplyData == NULL || *replySize != sizeof(int32_t)) { ALOGV("\tLVM_ERROR : Reverb_command cmdCode Case: " "EFFECT_CMD_SET_PARAM: ERROR"); return -EINVAL; diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp index c56ff72..a96a703 100644 --- a/media/libeffects/preprocessing/PreProcessing.cpp +++ b/media/libeffects/preprocessing/PreProcessing.cpp @@ -77,7 +77,7 @@ struct preproc_ops_s { void (* enable)(preproc_effect_t *fx); void (* disable)(preproc_effect_t *fx); int (* set_parameter)(preproc_effect_t *fx, void *param, void *value); - int (* get_parameter)(preproc_effect_t *fx, void *param, size_t *size, void *value); + int (* get_parameter)(preproc_effect_t *fx, void *param, uint32_t *size, void *value); int (* set_device)(preproc_effect_t *fx, uint32_t device); }; @@ -291,7 +291,7 @@ int AgcCreate(preproc_effect_t *effect) int AgcGetParameter(preproc_effect_t *effect, void *pParam, - size_t *pValueSize, + uint32_t *pValueSize, void *pValue) { int status = 0; @@ -452,9 +452,9 @@ int AecCreate(preproc_effect_t *effect) return 0; } -int AecGetParameter(preproc_effect_t *effect, +int AecGetParameter(preproc_effect_t *effect, void *pParam, - size_t *pValueSize, + uint32_t *pValueSize, void *pValue) { int status = 0; @@ -575,9 +575,9 @@ int NsCreate(preproc_effect_t *effect) return 0; } -int NsGetParameter(preproc_effect_t *effect, +int NsGetParameter(preproc_effect_t *effect, void *pParam, - size_t *pValueSize, + uint32_t *pValueSize, void *pValue) { int status = 0; @@ -1453,7 +1453,7 @@ int PreProcessingFx_Command(effect_handle_t self, if (effect->ops->get_parameter) { p->status = effect->ops->get_parameter(effect, p->data, - (size_t *)&p->vsize, + &p->vsize, p->data + voffset); *replySize = sizeof(effect_param_t) + voffset + p->vsize; } diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp index 8d00206..3cb13f2 100644 --- a/media/libeffects/testlibs/EffectEqualizer.cpp +++ b/media/libeffects/testlibs/EffectEqualizer.cpp @@ -115,7 +115,7 @@ struct EqualizerContext { int Equalizer_init(EqualizerContext *pContext); int Equalizer_setConfig(EqualizerContext *pContext, effect_config_t *pConfig); -int Equalizer_getParameter(AudioEqualizer * pEqualizer, int32_t *pParam, size_t *pValueSize, void *pValue); +int Equalizer_getParameter(AudioEqualizer * pEqualizer, int32_t *pParam, uint32_t *pValueSize, void *pValue); int Equalizer_setParameter(AudioEqualizer * pEqualizer, int32_t *pParam, void *pValue); @@ -360,7 +360,7 @@ int Equalizer_init(EqualizerContext *pContext) // //---------------------------------------------------------------------------- -int Equalizer_getParameter(AudioEqualizer * pEqualizer, int32_t *pParam, size_t *pValueSize, void *pValue) +int Equalizer_getParameter(AudioEqualizer * pEqualizer, int32_t *pParam, uint32_t *pValueSize, void *pValue) { int status = 0; int32_t param = *pParam++; @@ -662,8 +662,8 @@ extern "C" int Equalizer_command(effect_handle_t self, uint32_t cmdCode, uint32_ Equalizer_setConfig(pContext, &pContext->config); break; case EFFECT_CMD_GET_PARAM: { - if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) || - pReplyData == NULL || *replySize < (int) (sizeof(effect_param_t) + sizeof(int32_t))) { + if (pCmdData == NULL || cmdSize < (sizeof(effect_param_t) + sizeof(int32_t)) || + pReplyData == NULL || *replySize < (sizeof(effect_param_t) + sizeof(int32_t))) { return -EINVAL; } effect_param_t *p = (effect_param_t *)pCmdData; @@ -682,7 +682,7 @@ extern "C" int Equalizer_command(effect_handle_t self, uint32_t cmdCode, uint32_ case EFFECT_CMD_SET_PARAM: { ALOGV("Equalizer_command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %d, pReplyData %p", cmdSize, pCmdData, *replySize, pReplyData); - if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) || + if (pCmdData == NULL || cmdSize < (sizeof(effect_param_t) + sizeof(int32_t)) || pReplyData == NULL || *replySize != sizeof(int32_t)) { return -EINVAL; } diff --git a/media/libeffects/testlibs/EffectReverb.c b/media/libeffects/testlibs/EffectReverb.c index c37f392..f056d19 100644 --- a/media/libeffects/testlibs/EffectReverb.c +++ b/media/libeffects/testlibs/EffectReverb.c @@ -750,7 +750,7 @@ void Reverb_Reset(reverb_object_t *pReverb, bool init) { * *---------------------------------------------------------------------------- */ -int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, size_t *pSize, +int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, uint32_t *pSize, void *pValue) { int32_t *pValue32; int16_t *pValue16; @@ -758,7 +758,7 @@ int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, size_t *pSize, int32_t i; int32_t temp; int32_t temp2; - size_t size; + uint32_t size; if (pReverb->m_Preset) { if (param != REVERB_PARAM_PRESET || *pSize < sizeof(int16_t)) { @@ -1033,7 +1033,7 @@ int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, size_t *pSize, * *---------------------------------------------------------------------------- */ -int Reverb_setParameter(reverb_object_t *pReverb, int32_t param, size_t size, +int Reverb_setParameter(reverb_object_t *pReverb, int32_t param, uint32_t size, void *pValue) { int32_t value32; int16_t value16; @@ -1044,7 +1044,7 @@ int Reverb_setParameter(reverb_object_t *pReverb, int32_t param, size_t size, reverb_preset_t *pPreset; int maxSamples; int32_t averageDelay; - size_t paramSize; + uint32_t paramSize; ALOGV("Reverb_setParameter, context %p, param %d, value16 %d, value32 %d", pReverb, param, *(int16_t *)pValue, *(int32_t *)pValue); diff --git a/media/libeffects/testlibs/EffectReverb.h b/media/libeffects/testlibs/EffectReverb.h index e5248fe..756c5ea 100644 --- a/media/libeffects/testlibs/EffectReverb.h +++ b/media/libeffects/testlibs/EffectReverb.h @@ -330,8 +330,8 @@ int Reverb_setConfig(reverb_module_t *pRvbModule, effect_config_t *pConfig, bool void Reverb_getConfig(reverb_module_t *pRvbModule, effect_config_t *pConfig); void Reverb_Reset(reverb_object_t *pReverb, bool init); -int Reverb_setParameter (reverb_object_t *pReverb, int32_t param, size_t size, void *pValue); -int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, size_t *pSize, void *pValue); +int Reverb_setParameter (reverb_object_t *pReverb, int32_t param, uint32_t size, void *pValue); +int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, uint32_t *pSize, void *pValue); /*---------------------------------------------------------------------------- * ReverbUpdateXfade diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index d25c40b..3217171 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); @@ -1488,6 +1507,7 @@ nsecs_t AudioTrack::processAudioBuffer() } size_t misalignment = mProxy->getMisalignment(); uint32_t sequence = mSequence; + sp<AudioTrackClientProxy> proxy = mProxy; // These fields don't need to be cached, because they are assigned only by set(): // mTransfer, mCbf, mUserData, mFormat, mFrameSize, mFrameSizeAF, mFlags @@ -1496,35 +1516,32 @@ nsecs_t AudioTrack::processAudioBuffer() mLock.unlock(); if (waitStreamEnd) { - AutoMutex lock(mLock); - - sp<AudioTrackClientProxy> proxy = mProxy; - sp<IMemory> 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 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 <audio_io_handle_t>(data.readInt32()); - uint32_t stream = data.readInt32(); + audio_stream_type_t stream = + static_cast <audio_stream_type_t>(data.readInt32()); int session = data.readInt32(); reply->writeInt32(static_cast <uint32_t>(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 <audio_io_handle_t>(data.readInt32()); - uint32_t stream = data.readInt32(); + audio_stream_type_t stream = + static_cast <audio_stream_type_t>(data.readInt32()); int session = data.readInt32(); reply->writeInt32(static_cast <uint32_t>(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; 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 ae8fac8..80bf61a 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)); - mBitShift = Format_frameBitShift(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), streamFormat); + mFrameSize = Format_frameSize(mFormat); } return NBAIO_Source::negotiate(offers, numOffers, counterOffers, numCounterOffers); } @@ -70,9 +68,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 aa9810e..c28d34d 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)); - mBitShift = Format_frameBitShift(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), streamFormat); + mFrameSize = Format_frameSize(mFormat); } return NBAIO_Sink::negotiate(offers, numOffers, counterOffers, numCounterOffers); } @@ -57,9 +55,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/NBAIO.cpp b/media/libnbaio/NBAIO.cpp index 51514de..ff3284c 100644 --- a/media/libnbaio/NBAIO.cpp +++ b/media/libnbaio/NBAIO.cpp @@ -24,63 +24,17 @@ 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) -{ - // 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 }; - -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 -}; +const NBAIO_Format Format_Invalid = { 0, 0, AUDIO_FORMAT_INVALID, 0 }; 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,59 +42,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) +NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount, + 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; } @@ -242,12 +158,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 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 062fa0f..e21ef48 100644 --- a/media/libnbaio/SourceAudioBufferProvider.cpp +++ b/media/libnbaio/SourceAudioBufferProvider.cpp @@ -24,7 +24,7 @@ namespace android { SourceAudioBufferProvider::SourceAudioBufferProvider(const sp<NBAIO_Source>& source) : mSource(source), - // mFrameBitShiftFormat below + // mFrameSize below mAllocated(NULL), mSize(0), mOffset(0), mRemaining(0), mGetCount(0), mFramesReleased(0) { ALOG_ASSERT(source != 0); @@ -37,7 +37,7 @@ SourceAudioBufferProvider::SourceAudioBufferProvider(const sp<NBAIO_Source>& sou numCounterOffers = 0; index = source->negotiate(counterOffers, 1, NULL, numCounterOffers); ALOG_ASSERT(index == 0); - mFrameBitShift = Format_frameBitShift(source->format()); + mFrameSize = Format_frameSize(source->format()); } SourceAudioBufferProvider::~SourceAudioBufferProvider() @@ -54,14 +54,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 @@ -84,7 +84,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)); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 4450d62..9c48587 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -964,6 +964,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<MetaData> &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 451e907..4ff805f 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<ABuffer> 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; @@ -528,6 +535,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/common/Config.mk b/media/libstagefright/codecs/common/Config.mk index a6d4286..a843cef 100644 --- a/media/libstagefright/codecs/common/Config.mk +++ b/media/libstagefright/codecs/common/Config.mk @@ -14,8 +14,10 @@ VOTT := pc endif # Do we also need to check on ARCH_ARM_HAVE_ARMV7A? - probably not -ifeq ($(ARCH_ARM_HAVE_NEON),true) -VOTT := v7 +ifeq ($(TARGET_ARCH),arm) + ifeq ($(ARCH_ARM_HAVE_NEON),true) + VOTT := v7 + endif endif VOTEST := 0 diff --git a/media/libstagefright/codecs/on2/h264dec/Android.mk b/media/libstagefright/codecs/on2/h264dec/Android.mk index 655b2ab..bf03ad9 100644 --- a/media/libstagefright/codecs/on2/h264dec/Android.mk +++ b/media/libstagefright/codecs/on2/h264dec/Android.mk @@ -84,8 +84,8 @@ MY_OMXDL_ASM_SRC := \ ./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S \ ./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S \ - -ifeq ($(ARCH_ARM_HAVE_NEON),true) +ifeq ($(TARGET_ARCH),arm) + ifeq ($(ARCH_ARM_HAVE_NEON),true) LOCAL_ARM_NEON := true # LOCAL_CFLAGS := -std=c99 -D._NEON -D._OMXDL LOCAL_CFLAGS := -DH264DEC_NEON -DH264DEC_OMXDL @@ -94,6 +94,7 @@ ifeq ($(ARCH_ARM_HAVE_NEON),true) LOCAL_C_INCLUDES += $(LOCAL_PATH)/./omxdl/arm_neon/api \ $(LOCAL_PATH)/./omxdl/arm_neon/vc/api \ $(LOCAL_PATH)/./omxdl/arm_neon/vc/m4p10/api + endif endif LOCAL_SHARED_LIBRARIES := \ 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..b8084ae --- /dev/null +++ b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp @@ -0,0 +1,540 @@ +/* + * 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 <utils/Log.h> + +#include "SoftOpus.h" +#include <OMX_AudioExt.h> +#include <OMX_IndexExt.h> + +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/MediaDefs.h> + +extern "C" { + #include <opus.h> + #include <opus_multistream.h> +} + +namespace android { + +static const int kRate = 48000; + +template<class T> +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<char *>(MEDIA_MIMETYPE_AUDIO_OPUS); + + def.format.audio.pNativeRender = NULL; + def.format.audio.bFlagErrorConcealment = OMX_FALSE; + def.format.audio.eEncoding = + (OMX_AUDIO_CODINGTYPE)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<char *>("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 ((int)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 ((int)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 size_t kOpusHeaderSize = 19; + + // Offset to the channel count byte in the Opus header. + const size_t kOpusHeaderChannelsOffset = 9; + + // Offset to the pre-skip value in the Opus header. + const size_t kOpusHeaderSkipSamplesOffset = 10; + + // Offset to the gain value in the Opus header. + const size_t kOpusHeaderGainOffset = 16; + + // Offset to the channel mapping byte in the Opus header. + 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 + // 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 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."); + 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<int16_t>( + 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<double>(ns) * kRate / 1000000000; +} + +void SoftOpus::onQueueFilled(OMX_U32 portIndex) { + List<BufferInfo *> &inQueue = getPortQueue(0); + List<BufferInfo *> &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<int64_t*>(header->pBuffer + + header->nOffset)), + kRate); + mSamplesToDiscard = mCodecDelay; + } else { + mSeekPreRoll = ns_to_samples( + *(reinterpret_cast<int64_t*>(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/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index b221c0c..9d7cb99 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -1233,6 +1233,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<ABuffer> unit = new ABuffer(aac_frame_length); 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<DataSource> &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" }, 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 <gui/SurfaceComposerClient.h> #include <binder/ProcessState.h> -#include <ui/FramebufferNativeWindow.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/MediaBufferGroup.h> diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 357ea22..8fdb50d 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -2567,7 +2567,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud // create an NBAIO sink for the HAL output stream, and negotiate mOutputSink = new AudioStreamOutSink(output->stream); size_t numCounterOffers = 0; - const NBAIO_Format offers[1] = {Format_from_SR_C(mSampleRate, mChannelCount)}; + const NBAIO_Format offers[1] = {Format_from_SR_C(mSampleRate, mChannelCount, mFormat)}; ssize_t index = mOutputSink->negotiate(offers, 1, NULL, numCounterOffers); ALOG_ASSERT(index == 0); @@ -5555,12 +5555,12 @@ void AudioFlinger::RecordThread::readInputParameters_l() mBufferSize = mInput->stream->common.get_buffer_size(&mInput->stream->common); mFrameCount = mBufferSize / mFrameSize; // This is the formula for calculating the temporary buffer size. - // With 3 HAL buffers, we can guarantee ability to down-sample the input by ratio of 2:1 to + // With 7 HAL buffers, we can guarantee ability to down-sample the input by ratio of 6:1 to // 1 full output buffer, regardless of the alignment of the available input. - // The "3" is somewhat arbitrary, and could probably be larger. + // The value is somewhat arbitrary, and could probably be even larger. // A larger value should allow more old data to be read after a track calls start(), // without increasing latency. - mRsmpInFrames = mFrameCount * 3; + mRsmpInFrames = mFrameCount * 7; mRsmpInFramesP2 = roundup(mRsmpInFrames); delete[] mRsmpInBuffer; // Over-allocate beyond mRsmpInFramesP2 to permit a HAL read past end of buffer |