/* * 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. */ /** ************************************************************************* * @file VideoEditor3gpReader.cpp * @brief StageFright shell 3GP Reader ************************************************************************* */ #define LOG_NDEBUG 1 #define LOG_TAG "VIDEOEDITOR_3GPREADER" /** * HEADERS * */ #define VIDEOEDITOR_BITSTREAM_PARSER #include "M4OSA_Debug.h" #include "VideoEditor3gpReader.h" #include "M4SYS_AccessUnit.h" #include "VideoEditorUtils.h" #include "M4READER_3gpCom.h" #include "M4_Common.h" #include "M4OSA_FileWriter.h" #ifdef VIDEOEDITOR_BITSTREAM_PARSER #include "M4OSA_CoreID.h" #include "M4OSA_Error.h" #include "M4OSA_Memory.h" #include "M4_Utils.h" #endif #include "ESDS.h" #include "utils/Log.h" #include #include #include #include #include #include #include #include #include /** * SOURCE CLASS */ namespace android { /** * ENGINE INTERFACE */ /** ************************************************************************ * @brief Array of AMR NB/WB bitrates * @note Array to match the mode and the bit rate ************************************************************************ */ const M4OSA_UInt32 VideoEditor3gpReader_AmrBitRate [2 /* 8kHz / 16kHz */] [9 /* the bitrate mode */] = { {4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200, 0}, {6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850} }; /** ******************************************************************************* * structure VideoEditor3gpReader_Context * @brief:This structure defines the context of the StageFright 3GP shell Reader ******************************************************************************* */ typedef struct { sp mDataSource; sp mExtractor; sp mAudioSource; sp mVideoSource; M4_StreamHandler* mAudioStreamHandler; M4_StreamHandler* mVideoStreamHandler; M4SYS_AccessUnit mAudioAu; M4SYS_AccessUnit mVideoAu; M4OSA_Time mMaxDuration; int64_t mFileSize; M4_StreamType mStreamType; M4OSA_UInt32 mStreamId; int32_t mTracks; int32_t mCurrTrack; M4OSA_Bool mAudioSeeking; M4OSA_Time mAudioSeekTime; M4OSA_Bool mVideoSeeking; M4OSA_Time mVideoSeekTime; } VideoEditor3gpReader_Context; #ifdef VIDEOEDITOR_BITSTREAM_PARSER /** ************************************************************************ * structure VideoEditor3gpReader_BitStreamParserContext * @brief Internal BitStreamParser context ************************************************************************ */ typedef struct { M4OSA_UInt32* mPbitStream; /**< bitstream pointer (32bits aligned) */ M4OSA_Int32 mSize; /**< bitstream size in bytes */ M4OSA_Int32 mIndex; /**< byte index */ M4OSA_Int32 mBitIndex; /**< bit index */ M4OSA_Int32 mStructSize; /**< size of structure */ } VideoEditor3gpReader_BitStreamParserContext; /** ******************************************************************************* * @brief Allocates the context and initializes internal data. * @param pContext (OUT) Pointer to the BitStreamParser context to create. * @param bitStream A pointer to the bitstream * @param size The size of the bitstream in bytes ******************************************************************************* */ static void VideoEditor3gpReader_BitStreamParserInit(void** pContext, void* pBitStream, M4OSA_Int32 size) { VideoEditor3gpReader_BitStreamParserContext* pStreamContext; *pContext=M4OSA_NULL; pStreamContext = (VideoEditor3gpReader_BitStreamParserContext*)M4OSA_32bitAlignedMalloc( sizeof(VideoEditor3gpReader_BitStreamParserContext), M4READER_3GP, (M4OSA_Char*)"3GP BitStreamParser Context"); if (M4OSA_NULL == pStreamContext) { return; } pStreamContext->mPbitStream=(M4OSA_UInt32*)pBitStream; pStreamContext->mSize=size; pStreamContext->mIndex=0; pStreamContext->mBitIndex=0; pStreamContext->mStructSize = sizeof(VideoEditor3gpReader_BitStreamParserContext); *pContext=pStreamContext; } /** ********************************************************************** * @brief Clean up context * @param pContext (IN/OUT) BitStreamParser context. ********************************************************************** */ static void VideoEditor3gpReader_BitStreamParserCleanUp(void* pContext) { free((M4OSA_Int32*)pContext); } /** ***************************************************************************** * @brief Read the next bits in the bitstream. * @note The function does not update the bitstream pointer. * @param pContext (IN/OUT) BitStreamParser context. * @param length (IN) The number of bits to extract from the bitstream * @return the read bits ***************************************************************************** */ static M4OSA_UInt32 VideoEditor3gpReader_BitStreamParserShowBits(void* pContext, M4OSA_Int32 length) { VideoEditor3gpReader_BitStreamParserContext* pStreamContext = (VideoEditor3gpReader_BitStreamParserContext*)pContext; M4OSA_UInt32 u_mask; M4OSA_UInt32 retval; M4OSA_Int32 i_ovf; M4OSA_DEBUG_IF1((M4OSA_NULL==pStreamContext), 0, "VideoEditor3gpReader_BitStreamParserShowBits:invalid context pointer"); retval=(M4OSA_UInt32)GET_MEMORY32(pStreamContext->\ mPbitStream[ pStreamContext->mIndex ]); i_ovf = pStreamContext->mBitIndex + length - 32; u_mask = (length >= 32) ? 0xffffffff: (1 << length) - 1; /* do we have enough bits availble in the current word(32bits)*/ if (i_ovf <= 0) { retval=(retval >> (- i_ovf)) & u_mask; } else { M4OSA_UInt32 u_nextword = (M4OSA_UInt32)GET_MEMORY32( pStreamContext->mPbitStream[ pStreamContext->mIndex + 1 ]); M4OSA_UInt32 u_msb_mask, u_msb_value, u_lsb_mask, u_lsb_value; u_msb_mask = ((1 << (32 - pStreamContext->mBitIndex)) - 1) << i_ovf; u_msb_value = retval << i_ovf; u_lsb_mask = (1 << i_ovf) - 1; u_lsb_value = u_nextword >> (32 - i_ovf); retval= (u_msb_value & u_msb_mask ) | (u_lsb_value & u_lsb_mask); } /* return the bits...*/ return retval; } /** ************************************************************************ * @brief Increment the bitstream pointer of bits. * @param pContext (IN/OUT) BitStreamParser context. * @param length (IN) The number of bit to shift the bitstream ************************************************************************ */ static void VideoEditor3gpReader_BitStreamParserFlushBits(void* pContext, M4OSA_Int32 length) { VideoEditor3gpReader_BitStreamParserContext* pStreamContext=( VideoEditor3gpReader_BitStreamParserContext*)pContext; M4OSA_Int32 val; if (M4OSA_NULL == pStreamContext) { return; } val=pStreamContext->mBitIndex + length; /* update the bits...*/ pStreamContext->mBitIndex += length; if (val - 32 >= 0) { /* update the bits...*/ pStreamContext->mBitIndex -= 32; /* update the words*/ pStreamContext->mIndex++; } } static M4OSA_UInt32 VideoEditor3gpReader_BitStreamParserGetBits( void* pContext,M4OSA_Int32 bitPos, M4OSA_Int32 bitLength) { VideoEditor3gpReader_BitStreamParserContext* pStreamContext = (VideoEditor3gpReader_BitStreamParserContext*)pContext; M4OSA_Int32 bitLocation, bitIndex; M4OSA_UInt32 retval=0; M4OSA_DEBUG_IF1((M4OSA_NULL==pStreamContext), 0, "VideoEditor3gpReader_BitStreamParserGetBits: invalid context pointer"); /* computes the word location*/ bitLocation=bitPos/32; bitIndex=(bitPos) % 32; if (bitLocation < pStreamContext->mSize) { M4OSA_UInt32 u_mask; M4OSA_Int32 i_ovf = bitIndex + bitLength - 32; retval=(M4OSA_UInt32)GET_MEMORY32( pStreamContext->mPbitStream[ bitLocation ]); u_mask = (bitLength >= 32) ? 0xffffffff: (1 << bitLength) - 1; if (i_ovf <= 0) { retval=(retval >> (- i_ovf)) & u_mask; } else { M4OSA_UInt32 u_nextword = (M4OSA_UInt32)GET_MEMORY32( pStreamContext->mPbitStream[ bitLocation + 1 ]); M4OSA_UInt32 u_msb_mask, u_msb_value, u_lsb_mask, u_lsb_value; u_msb_mask = ((1 << (32 - bitIndex)) - 1) << i_ovf; u_msb_value = retval << i_ovf; u_lsb_mask = (1 << i_ovf) - 1; u_lsb_value = u_nextword >> (32 - i_ovf); retval= (u_msb_value & u_msb_mask ) | (u_lsb_value & u_lsb_mask); } } return retval; } static void VideoEditor3gpReader_BitStreamParserRestart(void* pContext) { VideoEditor3gpReader_BitStreamParserContext* pStreamContext = (VideoEditor3gpReader_BitStreamParserContext*)pContext; if (M4OSA_NULL == pStreamContext) { return; } /* resets the bitstream pointers*/ pStreamContext->mIndex=0; pStreamContext->mBitIndex=0; } /** ******************************************************************************* * @brief Get a pointer to the current byte pointed by the bitstream pointer. * @note It should be used carefully as the pointer is in the bitstream itself * and no copy is made. * @param pContext (IN/OUT) BitStreamParser context. * @return Pointer to the current location in the bitstream ******************************************************************************* */ static M4OSA_UInt8* VideoEditor3gpReader_GetCurrentbitStreamPointer( void* pContext) { VideoEditor3gpReader_BitStreamParserContext* pStreamContext = (VideoEditor3gpReader_BitStreamParserContext*)pContext; M4OSA_DEBUG_IF1((M4OSA_NULL==pStreamContext), 0, "invalid context pointer"); return (M4OSA_UInt8*)((M4OSA_UInt8*)pStreamContext->mPbitStream + \ pStreamContext->mIndex * sizeof(M4OSA_UInt32) + \ pStreamContext->mBitIndex/8) ; } static M4OSA_Int32 VideoEditor3gpReader_BitStreamParserGetSize(void* pContext) { VideoEditor3gpReader_BitStreamParserContext* pStreamContext = (VideoEditor3gpReader_BitStreamParserContext*)pContext; M4OSA_DEBUG_IF1((M4OSA_NULL==pStreamContext), 0, "invalid context pointer"); return pStreamContext->mSize; } static void VideoEditor3gpReader_MPEG4BitStreamParserInit(void** pContext, void* pBitStream, M4OSA_Int32 size) { VideoEditor3gpReader_BitStreamParserInit(pContext, pBitStream, size); } static M4OSA_Int32 VideoEditor3gpReader_GetMpegLengthFromInteger(void* pContext, M4OSA_UInt32 val) { M4OSA_UInt32 length=0; M4OSA_UInt32 numBytes=0; M4OSA_UInt32 b=0; M4OSA_DEBUG_IF1((M4OSA_NULL==pContext), 0, "invalid context pointer"); /* the length is encoded as a sequence of bytes. The highest bit is used to indicate that the length continues on the next byte. The length can be: 0x80 0x80 0x80 0x22 of just 0x22 (highest bit not set) */ do { b=(val & ((0xff)<< (8 * numBytes)))>> (8 * numBytes); length=(length << 7) | (b & 0x7f); numBytes++; } while ((b & 0x80) && numBytes < 4); return length; } /** ******************************************************************************* * @brief Decode an MPEG4 Systems descriptor size from an encoded SDL size data * @note The value is read from the current bitstream location. * @param pContext (IN/OUT) BitStreamParser context. * @return Size in a human readable form ******************************************************************************* */ static M4OSA_Int32 VideoEditor3gpReader_GetMpegLengthFromStream(void* pContext){ M4OSA_UInt32 length=0; M4OSA_UInt32 numBytes=0; M4OSA_UInt32 b=0; M4OSA_DEBUG_IF1((M4OSA_NULL==pContext), 0, "invalid context pointer"); /* the length is encoded as a sequence of bytes. The highest bit is used to indicate that the length continues on the next byte. The length can be: 0x80 0x80 0x80 0x22 of just 0x22 (highest bit not set) */ do { b=VideoEditor3gpReader_BitStreamParserShowBits(pContext, 8); VideoEditor3gpReader_BitStreamParserFlushBits(pContext, 8); length=(length << 7) | (b & 0x7f); numBytes++; } while ((b & 0x80) && numBytes < 4); return length; } #endif /* VIDEOEDITOR_BITSTREAM_PARSER */ /** ************************************************************************ * @brief create an instance of the 3gp reader * @note allocates the context * * @param pContext: (OUT) pointer on a reader context * * @return M4NO_ERROR there is no error * @return M4ERR_ALLOC a memory allocation has failed * @return M4ERR_PARAMETER at least one parameter is not valid ************************************************************************ */ M4OSA_ERR VideoEditor3gpReader_create(M4OSA_Context *pContext) { VideoEditor3gpReader_Context* pC = NULL; M4OSA_ERR err = M4NO_ERROR; VIDEOEDITOR_CHECK(M4OSA_NULL != pContext , M4ERR_PARAMETER); ALOGV("VideoEditor3gpReader_create begin"); /* Context allocation & initialization */ SAFE_MALLOC(pC, VideoEditor3gpReader_Context, 1, "VideoEditor3gpReader"); memset(pC, sizeof(VideoEditor3gpReader_Context), 0); pC->mAudioStreamHandler = M4OSA_NULL; pC->mAudioAu.dataAddress = M4OSA_NULL; pC->mVideoStreamHandler = M4OSA_NULL; pC->mVideoAu.dataAddress = M4OSA_NULL; pC->mAudioSeeking = M4OSA_FALSE; pC->mAudioSeekTime = 0; pC->mVideoSeeking = M4OSA_FALSE; pC->mVideoSeekTime = 0; pC->mMaxDuration = 0; *pContext=pC; cleanUp: if ( M4NO_ERROR == err ) { ALOGV("VideoEditor3gpReader_create no error"); } else { ALOGV("VideoEditor3gpReader_create ERROR 0x%X", err); } ALOGV("VideoEditor3gpReader_create end "); return err; } /** ************************************************************************** * @brief destroy the instance of the 3gp reader * @note after this call the context is invalid * @param context: (IN) Context of the reader * @return M4NO_ERROR there is no error * @return M4ERR_PARAMETER pContext parameter is not properly set ************************************************************************** */ M4OSA_ERR VideoEditor3gpReader_destroy(M4OSA_Context pContext) { M4OSA_ERR err = M4NO_ERROR; VideoEditor3gpReader_Context* pC = M4OSA_NULL; ALOGV("VideoEditor3gpReader_destroy begin"); VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER); pC = (VideoEditor3gpReader_Context*)pContext; SAFE_FREE(pC->mAudioAu.dataAddress); pC->mAudioAu.dataAddress = M4OSA_NULL; SAFE_FREE(pC->mVideoAu.dataAddress); pC->mVideoAu.dataAddress = M4OSA_NULL; SAFE_FREE(pC); pContext = M4OSA_NULL; cleanUp: if( M4NO_ERROR == err ) { ALOGV("VideoEditor3gpReader_destroy no error"); } else { ALOGV("VideoEditor3gpReader_destroy ERROR 0x%X", err); } ALOGV("VideoEditor3gpReader_destroy end "); return err; } /** ************************************************************************ * @brief open the reader and initializes its created instance * @note this function open the media file * @param context: (IN) Context of the reader * @param pFileDescriptor: (IN) Pointer to proprietary data identifying * the media to open * @return M4NO_ERROR there is no error * @return M4ERR_PARAMETER the context is NULL * @return M4ERR_UNSUPPORTED_MEDIA_TYPE * the media is DRM protected ************************************************************************ */ M4OSA_ERR VideoEditor3gpReader_open(M4OSA_Context pContext, M4OSA_Void* pFileDescriptor) { VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)pContext; M4OSA_ERR err = M4NO_ERROR; ALOGV("VideoEditor3gpReader_open start "); M4OSA_DEBUG_IF1((M4OSA_NULL == pC), M4ERR_PARAMETER, "VideoEditor3gpReader_open: invalid context pointer"); M4OSA_DEBUG_IF1((M4OSA_NULL == pFileDescriptor), M4ERR_PARAMETER, "VideoEditor3gpReader_open: invalid pointer pFileDescriptor"); ALOGV("VideoEditor3gpReader_open Datasource start %s", (char*)pFileDescriptor); //pC->mDataSource = DataSource::CreateFromURI((char*)pFileDescriptor); pC->mDataSource = new FileSource ((char*)pFileDescriptor); if (pC->mDataSource == NULL) { ALOGV("VideoEditor3gpReader_open Datasource error"); return M4ERR_PARAMETER; } pC->mExtractor = MediaExtractor::Create(pC->mDataSource, MEDIA_MIMETYPE_CONTAINER_MPEG4); if (pC->mExtractor == NULL) { ALOGV("VideoEditor3gpReader_open extractor error"); return M4ERR_PARAMETER; } int32_t isDRMProtected = 0; sp meta = pC->mExtractor->getMetaData(); meta->findInt32(kKeyIsDRM, &isDRMProtected); if (isDRMProtected) { ALOGV("VideoEditorMp3Reader_open error - DRM Protected"); return M4ERR_UNSUPPORTED_MEDIA_TYPE; } ALOGV("VideoEditor3gpReader_open end "); return err; } /** ************************************************************************ * @brief close the reader * @note close the 3GP file * @param context: (IN) Context of the reader * @return M4NO_ERROR there is no error * @return M4ERR_PARAMETER the context is NULL * @return M4ERR_BAD_CONTEXT provided context is not a valid one ************************************************************************ */ M4OSA_ERR VideoEditor3gpReader_close(M4OSA_Context context) { VideoEditor3gpReader_Context *pC = (VideoEditor3gpReader_Context*)context; M4READER_AudioSbrUserdata *pAudioSbrUserData; M4_AccessUnit *pAU; M4OSA_ERR err = M4NO_ERROR; ALOGV("VideoEditor3gpReader_close begin"); M4OSA_DEBUG_IF1((M4OSA_NULL == pC), M4ERR_PARAMETER, "VideoEditor3gpReader_close: invalid context pointer"); if (pC->mAudioStreamHandler) { ALOGV("VideoEditor3gpReader_close Audio"); if (M4OSA_NULL != pC->mAudioStreamHandler->m_pDecoderSpecificInfo) { free(pC->mAudioStreamHandler->\ m_pDecoderSpecificInfo); pC->mAudioStreamHandler->m_decoderSpecificInfoSize = 0; pC->mAudioStreamHandler->m_pDecoderSpecificInfo = M4OSA_NULL; } if ((M4DA_StreamTypeAudioAac == pC->mAudioStreamHandler->m_streamType) && (M4OSA_NULL != pC->mAudioStreamHandler->m_pUserData)) { pAudioSbrUserData = (M4READER_AudioSbrUserdata*)(\ pC->mAudioStreamHandler->m_pUserData); pAU = (M4_AccessUnit*)pAudioSbrUserData->m_pFirstAU; if (M4OSA_NULL != pAU) { free(pAU); } if (M4OSA_NULL != pAudioSbrUserData->m_pAacDecoderUserConfig) { free(pAudioSbrUserData->\ m_pAacDecoderUserConfig); } free(pAudioSbrUserData); pC->mAudioStreamHandler->m_pUserData = M4OSA_NULL; } if (pC->mAudioStreamHandler->m_pESDSInfo != M4OSA_NULL) { free(pC->mAudioStreamHandler->m_pESDSInfo); pC->mAudioStreamHandler->m_pESDSInfo = M4OSA_NULL; pC->mAudioStreamHandler->m_ESDSInfoSize = 0; } /* Finally destroy the stream handler */ free(pC->mAudioStreamHandler); pC->mAudioStreamHandler = M4OSA_NULL; pC->mAudioSource->stop(); pC->mAudioSource.clear(); } if (pC->mVideoStreamHandler) { ALOGV("VideoEditor3gpReader_close Video "); if(M4OSA_NULL != pC->mVideoStreamHandler->m_pDecoderSpecificInfo) { free(pC->mVideoStreamHandler->\ m_pDecoderSpecificInfo); pC->mVideoStreamHandler->m_decoderSpecificInfoSize = 0; pC->mVideoStreamHandler->m_pDecoderSpecificInfo = M4OSA_NULL; } if(M4OSA_NULL != pC->mVideoStreamHandler->m_pH264DecoderSpecificInfo) { free(pC->mVideoStreamHandler->\ m_pH264DecoderSpecificInfo); pC->mVideoStreamHandler->m_H264decoderSpecificInfoSize = 0; pC->mVideoStreamHandler->m_pH264DecoderSpecificInfo = M4OSA_NULL; } if(pC->mVideoStreamHandler->m_pESDSInfo != M4OSA_NULL) { free(pC->mVideoStreamHandler->m_pESDSInfo); pC->mVideoStreamHandler->m_pESDSInfo = M4OSA_NULL; pC->mVideoStreamHandler->m_ESDSInfoSize = 0; } /* Finally destroy the stream handler */ free(pC->mVideoStreamHandler); pC->mVideoStreamHandler = M4OSA_NULL; pC->mVideoSource->stop(); pC->mVideoSource.clear(); } pC->mExtractor.clear(); pC->mDataSource.clear(); ALOGV("VideoEditor3gpReader_close end"); return err; } /** ************************************************************************ * @brief get an option from the 3gp reader * @note it allows the caller to retrieve a property value: * * @param context: (IN) Context of the reader * @param optionId: (IN) indicates the option to get * @param pValue: (OUT) pointer to structure or value (allocated * by user) where option is stored * * @return M4NO_ERROR there is no error * @return M4ERR_BAD_CONTEXT provided context is not a valid one * @return M4ERR_PARAMETER at least one parameter is not properly set * @return M4ERR_BAD_OPTION_ID when the option ID is not a valid one * @return M4ERR_VIDEO_NOT_H263 No video stream H263 in file. * @return M4ERR_NO_VIDEO_STREAM_RETRIEVED_YET * Function 3gpReader_getNextStreamHandler must be called before ************************************************************************ */ M4OSA_ERR VideoEditor3gpReader_getOption(M4OSA_Context context, M4OSA_OptionID optionId, M4OSA_DataOption pValue) { VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context; M4OSA_ERR err = M4NO_ERROR; ALOGV("VideoEditor3gpReader_getOption begin %d", optionId); M4OSA_DEBUG_IF1((M4OSA_NULL == pC), M4ERR_PARAMETER, "invalid context pointer"); M4OSA_DEBUG_IF1((M4OSA_NULL == pValue), M4ERR_PARAMETER, "VideoEditor3gpReader_getOption: invalid pointer on value"); switch (optionId) { case M4READER_kOptionID_Duration: { ALOGV("VideoEditor3gpReader_getOption duration %d",pC->mMaxDuration); *(M4OSA_Time*)pValue = pC->mMaxDuration; } break; case M4READER_kOptionID_Version: /* not used */ ALOGV("VideoEditor3gpReader_getOption: M4READER_kOptionID_Version"); break; case M4READER_kOptionID_Copyright: /* not used */ ALOGV(">>>>>>> M4READER_kOptionID_Copyright"); break; case M4READER_kOptionID_CreationTime: /* not used */ ALOGV("VideoEditor3gpReader_getOption M4READER_kOptionID_CreationTime"); break; case M4READER_kOptionID_Bitrate: { M4OSA_UInt32* pBitrate = (M4OSA_UInt32*)pValue; if (pC->mMaxDuration != 0) { M4OSA_UInt32 ui32Tmp = (M4OSA_UInt32)pC->mMaxDuration; *pBitrate = (M4OSA_UInt32)(pC->mFileSize * 8000.0 / pC->mMaxDuration); } ALOGV("VideoEditor3gpReader_getOption bitrate %ld", *pBitrate); } break; case M4READER_3GP_kOptionID_H263Properties: { if(M4OSA_NULL == pC->mVideoStreamHandler) { ALOGV("VideoEditor3gpReader_getOption no videoStream retrieved"); err = M4ERR_NO_VIDEO_STREAM_RETRIEVED_YET; break; } if((M4DA_StreamTypeVideoH263 != pC->mVideoStreamHandler->\ m_streamType) || (pC->mVideoStreamHandler->\ m_decoderSpecificInfoSize < 7)) { ALOGV("VideoEditor3gpReader_getOption DSI Size %d", pC->mVideoStreamHandler->m_decoderSpecificInfoSize); err = M4ERR_VIDEO_NOT_H263; break; } /* MAGICAL in the decoder confi H263: the 7th byte is the profile * number, 6th byte is the level number */ ((M4READER_3GP_H263Properties *)pValue)->uiProfile = pC->mVideoStreamHandler->m_pDecoderSpecificInfo[6]; ((M4READER_3GP_H263Properties *)pValue)->uiLevel = pC->mVideoStreamHandler->m_pDecoderSpecificInfo[5]; ALOGV("VideoEditor3gpReader_getOption M4READER_3GP_kOptionID_\ H263Properties end"); } break; case M4READER_3GP_kOptionID_PurpleLabsDrm: ALOGV("VideoEditor3gpReaderOption M4READER_3GP_kOptionID_PurpleLabsDrm"); /* not used */ break; case M4READER_kOptionID_GetNumberOfAudioAu: /* not used */ ALOGV("VideoEditor3gpReadeOption M4READER_kOptionID_GetNumberOfAudioAu"); break; case M4READER_kOptionID_GetNumberOfVideoAu: /* not used */ ALOGV("VideoEditor3gpReader_getOption :GetNumberOfVideoAu"); break; case M4READER_kOptionID_GetMetadata: /* not used */ ALOGV("VideoEditor3gpReader_getOption M4READER_kOptionID_GetMetadata"); break; case M4READER_kOptionID_3gpFtypBox: /* used only for SEMC */ ALOGV("VideoEditor3gpReader_getOption M4READER_kOptionID_3gpFtypBox"); err = M4ERR_BAD_OPTION_ID; //check this break; #ifdef OPTIONID_GET_NEXT_VIDEO_CTS case M4READER_3GP_kOptionID_getNextVideoCTS: /* not used */ ALOGV("VideoEditor3gpReader_getOption: getNextVideoCTS"); break; #endif default: { err = M4ERR_BAD_OPTION_ID; ALOGV("VideoEditor3gpReader_getOption M4ERR_BAD_OPTION_ID"); } break; } ALOGV("VideoEditor3gpReader_getOption end: optionID: x%x", optionId); return err; } /** ************************************************************************ * @brief set an option on the 3gp reader * @note No option can be set yet. * @param context: (IN) Context of the reader * @param optionId: (IN) indicates the option to set * @param pValue: (IN) pointer to structure or value (allocated * by user) where option is stored * @return M4NO_ERROR there is no error * @return M4ERR_BAD_CONTEXT provided context is not a valid one * @return M4ERR_PARAMETER at least one parameter is not properly set * @return M4ERR_BAD_OPTION_ID when the option ID is not a valid one ************************************************************************ */ M4OSA_ERR VideoEditor3gpReader_setOption(M4OSA_Context context, M4OSA_OptionID optionId, M4OSA_DataOption pValue) { VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context; M4OSA_ERR err = M4NO_ERROR; /* Check function parameters */ M4OSA_DEBUG_IF1((M4OSA_NULL == pC), M4ERR_PARAMETER, "invalid context pointer"); M4OSA_DEBUG_IF1((M4OSA_NULL == pValue), M4ERR_PARAMETER, "invalid value pointer"); ALOGV("VideoEditor3gpReader_setOption begin %d",optionId); switch(optionId) { case M4READER_kOptionID_SetOsaFileReaderFctsPtr: break; case static_cast(M4READER_3GP_kOptionID_AudioOnly): break; case static_cast(M4READER_3GP_kOptionID_VideoOnly): break; case static_cast(M4READER_3GP_kOptionID_FastOpenMode): break; case static_cast(M4READER_kOptionID_MaxMetadataSize): break; default: { ALOGV("VideoEditor3gpReader_setOption: returns M4ERR_BAD_OPTION_ID"); err = M4ERR_BAD_OPTION_ID; } break; } ALOGV("VideoEditor3gpReader_setOption end "); return err; } /** ************************************************************************ * @brief fill the access unit structure with initialization values * @param context: (IN) Context of the reader * @param pStreamHandler: (IN) pointer to the stream handler to which * the access unit will be associated * @param pAccessUnit: (IN/OUT) pointer to the access unit (allocated * by the caller) to initialize * @return M4NO_ERROR there is no error * @return M4ERR_PARAMETER at least one parameter is not properly set ************************************************************************ */ M4OSA_ERR VideoEditor3gpReader_fillAuStruct(M4OSA_Context context, M4_StreamHandler *pStreamHandler, M4_AccessUnit *pAccessUnit) { VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context; M4OSA_ERR err= M4NO_ERROR; M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_fillAuStruct: invalid context"); M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_fillAuStruc invalid pointer to M4_StreamHandler"); M4OSA_DEBUG_IF1((pAccessUnit == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_fillAuStruct: invalid pointer to M4_AccessUnit"); ALOGV("VideoEditor3gpReader_fillAuStruct begin"); /* Initialize pAccessUnit structure */ pAccessUnit->m_size = 0; pAccessUnit->m_CTS = 0; pAccessUnit->m_DTS = 0; pAccessUnit->m_attribute = 0; pAccessUnit->m_dataAddress = M4OSA_NULL; pAccessUnit->m_maxsize = pStreamHandler->m_maxAUSize; pAccessUnit->m_streamID = pStreamHandler->m_streamId; pAccessUnit->m_structSize = sizeof(M4_AccessUnit); ALOGV("VideoEditor3gpReader_fillAuStruct end"); return M4NO_ERROR; } /** ******************************************************************************** * @brief jump into the stream at the specified time * @note * @param context: (IN) Context of the reader * @param pStreamHandler (IN) the stream handler of the stream to make jump * @param pTime (I/O)IN the time to jump to (in ms) * OUT the time to which the stream really jumped * @return M4NO_ERROR there is no error * @return M4ERR_PARAMETER at least one parameter is not properly set ******************************************************************************** */ M4OSA_ERR VideoEditor3gpReader_jump(M4OSA_Context context, M4_StreamHandler *pStreamHandler, M4OSA_Int32* pTime) { VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context; M4OSA_ERR err = M4NO_ERROR; M4SYS_AccessUnit* pAu; M4OSA_Time time64; M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_jump: invalid context"); M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_jump: invalid pointer to M4_StreamHandler"); M4OSA_DEBUG_IF1((pTime == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_jump: invalid time pointer"); ALOGV("VideoEditor3gpReader_jump begin"); if (*pTime == (pStreamHandler->m_duration)) { *pTime -= 1; } time64 = (M4OSA_Time)*pTime; ALOGV("VideoEditor3gpReader_jump time us %ld ", time64); if ((pC->mAudioStreamHandler != M4OSA_NULL) && (pStreamHandler->m_streamId == pC->mAudioStreamHandler->m_streamId)) { pAu = &pC->mAudioAu; pAu->CTS = time64; pAu->DTS = time64; time64 = time64 * 1000; /* Convert the time into micro sec */ pC->mAudioSeeking = M4OSA_TRUE; pC->mAudioSeekTime = time64; ALOGV("VideoEditor3gpReader_jump AUDIO time us %ld ", time64); } else if ((pC->mVideoStreamHandler != M4OSA_NULL) && (pStreamHandler->m_streamId == pC->mVideoStreamHandler->m_streamId)) { pAu = &pC->mVideoAu; pAu->CTS = time64; pAu->DTS = time64; time64 = time64 * 1000; /* Convert the time into micro sec */ pC->mVideoSeeking = M4OSA_TRUE; pC->mVideoSeekTime = time64; ALOGV("VideoEditor3gpReader_jump VIDEO time us %ld ", time64); } else { ALOGV("VideoEditor3gpReader_jump passed StreamHandler is not known\n"); return M4ERR_PARAMETER; } time64 = time64 / 1000; /* Convert the time into milli sec */ ALOGV("VideoEditor3gpReader_jump time ms before seekset %ld ", time64); *pTime = (M4OSA_Int32)time64; ALOGV("VideoEditor3gpReader_jump end"); err = M4NO_ERROR; return err; } /** ******************************************************************************** * @brief reset the stream, that is seek it to beginning and make it ready * @note * @param context: (IN) Context of the reader * @param pStreamHandler (IN) The stream handler of the stream to reset * @return M4NO_ERROR there is no error * @return M4ERR_PARAMETER at least one parameter is not properly set ******************************************************************************** */ M4OSA_ERR VideoEditor3gpReader_reset(M4OSA_Context context, M4_StreamHandler *pStreamHandler) { VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context; M4OSA_ERR err = M4NO_ERROR; M4SYS_StreamID streamIdArray[2]; M4SYS_AccessUnit* pAu; M4OSA_Time time64 = 0; M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_reset: invalid context"); M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_reset: invalid pointer to M4_StreamHandler"); ALOGV("VideoEditor3gpReader_reset begin"); if (pStreamHandler == (M4_StreamHandler*)pC->mAudioStreamHandler) { pAu = &pC->mAudioAu; } else if (pStreamHandler == (M4_StreamHandler*)pC->mVideoStreamHandler) { pAu = &pC->mVideoAu; } else { ALOGV("VideoEditor3gpReader_reset passed StreamHandler is not known\n"); return M4ERR_PARAMETER; } pAu->CTS = time64; pAu->DTS = time64; ALOGV("VideoEditor3gpReader_reset end"); return err; } /** ******************************************************************************** * @brief Gets an access unit (AU) from the stream handler source. * @note An AU is the smallest possible amount of data to be decoded by decoder * * @param context: (IN) Context of the reader * @param pStreamHandler (IN) The stream handler of the stream to make jump * @param pAccessUnit (IO) Pointer to access unit to fill with read data * @return M4NO_ERROR there is no error * @return M4ERR_PARAMETER at least one parameter is not properly set * @returns M4ERR_ALLOC memory allocation failed * @returns M4WAR_NO_MORE_AU there are no more access unit in the stream ******************************************************************************** */ M4OSA_ERR VideoEditor3gpReader_getNextAu(M4OSA_Context context, M4_StreamHandler *pStreamHandler, M4_AccessUnit *pAccessUnit) { VideoEditor3gpReader_Context* pC=(VideoEditor3gpReader_Context*)context; M4OSA_ERR err = M4NO_ERROR; M4SYS_AccessUnit* pAu; int64_t tempTime64 = 0; MediaBuffer *mMediaBuffer = NULL; MediaSource::ReadOptions options; M4OSA_Bool flag = M4OSA_FALSE; status_t error; int32_t i32Tmp = 0; M4OSA_DEBUG_IF1(( pC== 0), M4ERR_PARAMETER, "VideoEditor3gpReader_getNextAu: invalid context"); M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_getNextAu: invalid pointer to M4_StreamHandler"); M4OSA_DEBUG_IF1((pAccessUnit == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_getNextAu: invalid pointer to M4_AccessUnit"); ALOGV("VideoEditor3gpReader_getNextAu begin"); if (pStreamHandler == (M4_StreamHandler*)pC->mAudioStreamHandler) { ALOGV("VideoEditor3gpReader_getNextAu audio stream"); pAu = &pC->mAudioAu; if (pC->mAudioSeeking == M4OSA_TRUE) { ALOGV("VideoEditor3gpReader_getNextAu audio seek time: %ld", pC->mAudioSeekTime); options.setSeekTo(pC->mAudioSeekTime); pC->mAudioSource->read(&mMediaBuffer, &options); mMediaBuffer->meta_data()->findInt64(kKeyTime, (int64_t*)&tempTime64); options.clearSeekTo(); pC->mAudioSeeking = M4OSA_FALSE; flag = M4OSA_TRUE; } else { ALOGV("VideoEditor3gpReader_getNextAu audio no seek:"); pC->mAudioSource->read(&mMediaBuffer, &options); if (mMediaBuffer != NULL) { mMediaBuffer->meta_data()->findInt64(kKeyTime, (int64_t*)&tempTime64); } } } else if (pStreamHandler == (M4_StreamHandler*)pC->mVideoStreamHandler) { ALOGV("VideoEditor3gpReader_getNextAu video steram "); pAu = &pC->mVideoAu; if(pC->mVideoSeeking == M4OSA_TRUE) { flag = M4OSA_TRUE; ALOGV("VideoEditor3gpReader_getNextAu seek: %ld",pC->mVideoSeekTime); options.setSeekTo(pC->mVideoSeekTime, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); do { if (mMediaBuffer != NULL) { ALOGV("VideoEditor3gpReader_getNextAu free the MediaBuffer"); mMediaBuffer->release(); } error = pC->mVideoSource->read(&mMediaBuffer, &options); ALOGV("VE3gpReader_getNextAu MediaBuffer %x , error %d", mMediaBuffer, error); if (mMediaBuffer != NULL) { if (mMediaBuffer->meta_data()->findInt32(kKeyIsSyncFrame, &i32Tmp) && i32Tmp) { ALOGV("SYNC FRAME FOUND--%d", i32Tmp); pAu->attribute = AU_RAP; } else { pAu->attribute = AU_P_Frame; } mMediaBuffer->meta_data()->findInt64(kKeyTime, (int64_t*)&tempTime64); } else { break; } options.clearSeekTo(); } while(tempTime64 < pC->mVideoSeekTime); ALOGV("VE3gpReader_getNextAu: video time with seek = %lld:", tempTime64); pC->mVideoSeeking = M4OSA_FALSE; } else { ALOGV("VideoEditor3gpReader_getNextAu video no seek:"); pC->mVideoSource->read(&mMediaBuffer, &options); if(mMediaBuffer != NULL) { if (mMediaBuffer->meta_data()->findInt32(kKeyIsSyncFrame, &i32Tmp) && i32Tmp) { ALOGV("SYNC FRAME FOUND--%d", i32Tmp); pAu->attribute = AU_RAP; } else { pAu->attribute = AU_P_Frame; } mMediaBuffer->meta_data()->findInt64(kKeyTime, (int64_t*)&tempTime64); ALOGV("VE3gpReader_getNextAu: video no seek time = %lld:", tempTime64); }else { ALOGV("VE3gpReader_getNextAu:video no seek time buffer is NULL"); } } } else { ALOGV("VideoEditor3gpReader_getNextAu M4ERR_PARAMETER"); return M4ERR_PARAMETER; } if (mMediaBuffer != NULL) { if( (pAu->dataAddress == NULL) || (pAu->size < \ mMediaBuffer->range_length())) { if(pAu->dataAddress != NULL) { free((M4OSA_Int32*)pAu->dataAddress); pAu->dataAddress = NULL; } ALOGV("Buffer lenght = %d ,%d",(mMediaBuffer->range_length() +\ 3) & ~0x3,(mMediaBuffer->range_length())); pAu->dataAddress = (M4OSA_Int32*)M4OSA_32bitAlignedMalloc( (mMediaBuffer->range_length() + 3) & ~0x3,M4READER_3GP, (M4OSA_Char*)"pAccessUnit->m_dataAddress" ); if(pAu->dataAddress == NULL) { ALOGV("VideoEditor3gpReader_getNextAu malloc failed"); return M4ERR_ALLOC; } } pAu->size = mMediaBuffer->range_length(); memcpy((void *)pAu->dataAddress, (void *)((const char *)mMediaBuffer->data() + mMediaBuffer->range_offset()), mMediaBuffer->range_length()); if( (pStreamHandler == (M4_StreamHandler*)pC->mVideoStreamHandler) && (pStreamHandler->m_streamType == M4DA_StreamTypeVideoMpeg4Avc) ) { M4OSA_UInt32 size = mMediaBuffer->range_length(); M4OSA_UInt8 *lbuffer; lbuffer = (M4OSA_UInt8 *) pAu->dataAddress; ALOGV("pAccessUnit->m_dataAddress size = %x",size); lbuffer[0] = (size >> 24) & 0xFF; lbuffer[1] = (size >> 16) & 0xFF; lbuffer[2] = (size >> 8) & 0xFF; lbuffer[3] = (size) & 0xFF; } pAu->CTS = tempTime64; pAu->CTS = pAu->CTS / 1000; //converting the microsec to millisec ALOGV("VideoEditor3gpReader_getNextAu CTS = %ld",pAu->CTS); pAu->DTS = pAu->CTS; if (pStreamHandler == (M4_StreamHandler*)pC->mAudioStreamHandler) { pAu->attribute = M4SYS_kFragAttrOk; } mMediaBuffer->release(); pAccessUnit->m_dataAddress = (M4OSA_Int8*) pAu->dataAddress; pAccessUnit->m_size = pAu->size; pAccessUnit->m_maxsize = pAu->size; pAccessUnit->m_CTS = pAu->CTS; pAccessUnit->m_DTS = pAu->DTS; pAccessUnit->m_attribute = pAu->attribute; } else { ALOGV("VideoEditor3gpReader_getNextAu: M4WAR_NO_MORE_AU (EOS) reached"); pAccessUnit->m_size = 0; err = M4WAR_NO_MORE_AU; } options.clearSeekTo(); pAu->nbFrag = 0; mMediaBuffer = NULL; ALOGV("VideoEditor3gpReader_getNextAu end "); return err; } /** ******************************************************************************* * @brief Split the AVC DSI in its different components and write it in * ONE memory buffer * @note * @param pStreamHandler: (IN/OUT) The MPEG4-AVC stream * @param pDecoderConfigLocal: (IN) The DSI buffer * @param decoderConfigSizeLocal: (IN) The DSI buffer size * @return M4NO_ERROR there is no error * @return ERR_FILE_SYNTAX_ERROR pDecoderConfigLocal is NULL ******************************************************************************* */ static M4OSA_ERR VideoEditor3gpReader_AnalyseAvcDsi( M4_StreamHandler *pStreamHandler, M4OSA_Int32* pDecoderConfigLocal, M4OSA_Int32 decoderConfigSizeLocal) { struct _avcSpecificInfo *pAvcSpecInfo = M4OSA_NULL; M4OSA_UInt32 uiSpecInfoSize; M4OSA_Context pBitParserContext = M4OSA_NULL; M4OSA_MemAddr8 pPos; /** * First parsing to get the total allocation size (we must not do * multiple malloc, but only one instead) */ { M4OSA_Int32 val; M4OSA_UInt32 i,j; M4OSA_UInt8 nalUnitLength; M4OSA_UInt8 numOfSequenceParameterSets; M4OSA_UInt32 uiTotalSizeOfSPS = 0; M4OSA_UInt8 numOfPictureParameterSets; M4OSA_UInt32 uiTotalSizeOfPPS = 0; M4OSA_UInt32 uiSize; struct _avcSpecificInfo avcSpIf; avcSpIf.m_nalUnitLength = 0; if (M4OSA_NULL == pDecoderConfigLocal) { return M4ERR_READER3GP_DECODER_CONFIG_ERROR; } VideoEditor3gpReader_MPEG4BitStreamParserInit(&pBitParserContext, pDecoderConfigLocal, decoderConfigSizeLocal); if (M4OSA_NULL == pBitParserContext) { return M4ERR_ALLOC; } VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); /* 8 bits -- configuration version */ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); /* 8 bits -- avc profile indication*/ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); /* 8 bits -- profile compatibility */ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); /* 8 bits -- avc level indication*/ val=VideoEditor3gpReader_BitStreamParserShowBits(pBitParserContext, 8); /* 6 bits reserved 111111b 2 bits length Size minus one*/ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); /* m_nalUnitLength */ nalUnitLength = (M4OSA_UInt8)((val & 0x03) + 1);/*0b11111100*/ if (nalUnitLength > 4) { pStreamHandler->m_decoderSpecificInfoSize = 0; pStreamHandler->m_pDecoderSpecificInfo = M4OSA_NULL; VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext); } else { /** * SPS table */ val=VideoEditor3gpReader_BitStreamParserShowBits(pBitParserContext, 8);/* 3 bits-reserved 111b-5 bits number of sequence parameter set*/ numOfSequenceParameterSets = val & 0x1F; /*1F instead of E0*/ /*0b11100000*/ /*Number of seq parameter sets*/ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); for (i=0; i < numOfSequenceParameterSets; i++) { /** * Get the size of this element */ uiSize = (M4OSA_UInt32)VideoEditor3gpReader_BitStreamParserShowBits( pBitParserContext, 16); uiTotalSizeOfSPS += uiSize; VideoEditor3gpReader_BitStreamParserFlushBits( pBitParserContext, 16); /** *Read the element(dont keep it, we only want size right now) */ for (j=0; jm_nalUnitLength = nalUnitLength; pAvcSpecInfo->m_numOfSequenceParameterSets = numOfSequenceParameterSets; pAvcSpecInfo->m_numOfPictureParameterSets = numOfPictureParameterSets; /* We place the SPS param sets table after m_pPictureParameterSet */ pAvcSpecInfo->m_pSequenceParameterSet= (struct _parameterSet*)( (M4OSA_MemAddr8)(&pAvcSpecInfo->m_pPictureParameterSet) + sizeof(pAvcSpecInfo->m_pPictureParameterSet)); /*We place the PPS param sets table after the SPS param sets table*/ pAvcSpecInfo->m_pPictureParameterSet = (struct _parameterSet*)( (M4OSA_MemAddr8)(pAvcSpecInfo->m_pSequenceParameterSet) + (numOfSequenceParameterSets * sizeof(struct _parameterSet))); /**< The data will be placed after the PPS param sets table */ pPos = (M4OSA_MemAddr8)pAvcSpecInfo->m_pPictureParameterSet + (numOfPictureParameterSets * sizeof(struct _parameterSet)); /** * reset the bit parser */ VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext); } } /** * Second parsing to copy the data */ if (M4OSA_NULL != pAvcSpecInfo) { M4OSA_Int32 i,j; VideoEditor3gpReader_MPEG4BitStreamParserInit(&pBitParserContext, pDecoderConfigLocal, decoderConfigSizeLocal); if (M4OSA_NULL == pBitParserContext) { free(pAvcSpecInfo); return M4ERR_ALLOC; } VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); /* 8 bits -- configuration version */ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); /* 8 bits -- avc profile indication*/ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); /* 8 bits -- profile compatibility */ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); /* 8 bits -- avc level indication*/ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); /* m_nalUnitLength */ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); /* 3 bits -- reserved 111b -- 5 bits number of sequence parameter set*/ for (i=0; i < pAvcSpecInfo->m_numOfSequenceParameterSets; i++) { pAvcSpecInfo->m_pSequenceParameterSet[i].m_length = (M4OSA_UInt16)VideoEditor3gpReader_BitStreamParserShowBits( pBitParserContext, 16); VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext,16); pAvcSpecInfo->m_pSequenceParameterSet[i].m_pParameterSetUnit = (M4OSA_UInt8*)pPos; /**< current position in the buffer */ pPos += pAvcSpecInfo->m_pSequenceParameterSet[i].m_length; /**< increment the position in the buffer */ for (j=0; jm_pSequenceParameterSet[i].m_length;j++){ pAvcSpecInfo->m_pSequenceParameterSet[i].m_pParameterSetUnit[j]= (M4OSA_UInt8)VideoEditor3gpReader_BitStreamParserShowBits( pBitParserContext, 8); VideoEditor3gpReader_BitStreamParserFlushBits( pBitParserContext, 8); } } VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); /* number of pîcture parameter set*/ for (i=0; i < pAvcSpecInfo->m_numOfPictureParameterSets; i++) { pAvcSpecInfo->m_pPictureParameterSet[i].m_length = (M4OSA_UInt16)VideoEditor3gpReader_BitStreamParserShowBits( pBitParserContext, 16); VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext,16); pAvcSpecInfo->m_pPictureParameterSet[i].m_pParameterSetUnit = (M4OSA_UInt8*)pPos; /**< current position in the buffer */ pPos += pAvcSpecInfo->m_pPictureParameterSet[i].m_length; /**< increment the position in the buffer */ for (j=0; jm_pPictureParameterSet[i].m_length; j++) { pAvcSpecInfo->m_pPictureParameterSet[i].m_pParameterSetUnit[j] = (M4OSA_UInt8)VideoEditor3gpReader_BitStreamParserShowBits( pBitParserContext, 8); VideoEditor3gpReader_BitStreamParserFlushBits( pBitParserContext, 8); } } VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext); pStreamHandler->m_decoderSpecificInfoSize = uiSpecInfoSize; pStreamHandler->m_pDecoderSpecificInfo = (M4OSA_UInt8*)pAvcSpecInfo; } pStreamHandler->m_H264decoderSpecificInfoSize = decoderConfigSizeLocal; pStreamHandler->m_pH264DecoderSpecificInfo = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( decoderConfigSizeLocal, M4READER_3GP, (M4OSA_Char*)"MPEG-4 AVC DecoderSpecific"); if (M4OSA_NULL == pStreamHandler->m_pH264DecoderSpecificInfo) { goto cleanup; } memcpy((void * ) pStreamHandler->m_pH264DecoderSpecificInfo, (void * )pDecoderConfigLocal, pStreamHandler->m_H264decoderSpecificInfoSize); return M4NO_ERROR; cleanup: VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext); return M4ERR_READER3GP_DECODER_CONFIG_ERROR; } /** ******************************************************************************** * @brief Get the next stream found in the 3gp file * @note * @param context: (IN) Context of the reader * @param pMediaFamily: OUT) pointer to a user allocated * M4READER_MediaFamily that will be filled * with the media family of the found stream * @param pStreamHandler:(OUT) pointer to StreamHandler that will be allocated * and filled with the found stream description * @return M4NO_ERROR there is no error * @return M4ERR_BAD_CONTEXT provided context is not a valid one * @return M4ERR_PARAMETER at least one parameter is not properly set * @return M4WAR_NO_MORE_STREAM no more available stream in the media ******************************************************************************** */ M4OSA_ERR VideoEditor3gpReader_getNextStreamHandler(M4OSA_Context context, M4READER_MediaFamily *pMediaFamily, M4_StreamHandler **pStreamHandler) { VideoEditor3gpReader_Context* pC=(VideoEditor3gpReader_Context*)context; M4OSA_ERR err = M4NO_ERROR; M4SYS_StreamID streamIdArray[2]; M4SYS_StreamDescription streamDesc; M4_AudioStreamHandler* pAudioStreamHandler; M4_VideoStreamHandler* pVideoStreamHandler; M4OSA_Int8 *DecoderSpecificInfo = M4OSA_NULL; M4OSA_Int32 decoderSpecificInfoSize =0, maxAUSize = 0; M4_StreamType streamType = M4DA_StreamTypeUnknown; M4OSA_UInt8 temp, i, trackCount; M4OSA_Bool haveAudio = M4OSA_FALSE; M4OSA_Bool haveVideo = M4OSA_FALSE; sp meta = NULL; int64_t Duration = 0; M4OSA_UInt8* DecoderSpecific = M4OSA_NULL ; uint32_t type; const void *data; size_t size; const void *codec_specific_data; size_t codec_specific_data_size; M4OSA_Int32 ptempTime; M4OSA_Int32 avgFPS=0; ALOGV("VideoEditor3gpReader_getNextStreamHandler begin"); M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_getNextStreamHandler: invalid context"); M4OSA_DEBUG_IF1((pMediaFamily == 0), M4ERR_PARAMETER, "getNextStreamHandler: invalid pointer to MediaFamily"); M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER, "getNextStreamHandler: invalid pointer to StreamHandler"); trackCount = pC->mExtractor->countTracks(); temp = pC->mCurrTrack; if(temp >= trackCount) { ALOGV("VideoEditor3gpReader_getNextStreamHandler error = %d", M4WAR_NO_MORE_STREAM); return (M4WAR_NO_MORE_STREAM); } else { const char *mime; meta = pC->mExtractor->getTrackMetaData(temp); CHECK(meta->findCString(kKeyMIMEType, &mime)); if (!haveVideo && !strncasecmp(mime, "video/", 6)) { pC->mVideoSource = pC->mExtractor->getTrack(temp); pC->mVideoSource->start(); *pMediaFamily = M4READER_kMediaFamilyVideo; haveVideo = true; ALOGV("VideoEditor3gpReader_getNextStreamHandler getTrack called"); if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { streamType = M4DA_StreamTypeVideoMpeg4Avc; } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_H263)) { streamType = M4DA_StreamTypeVideoH263; } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) { streamType = M4DA_StreamTypeVideoMpeg4; } else { ALOGV("VideoEditor3gpReaderGetNextStreamHandler streamTypeNONE"); } ALOGV("VideoEditor3gpReader_getNextStreamHandler: stream type: %d ", streamType); if(streamType != M4DA_StreamTypeUnknown) { pC->mStreamType = streamType; pC->mStreamId = pC->mCurrTrack; pVideoStreamHandler = (M4_VideoStreamHandler*)M4OSA_32bitAlignedMalloc (sizeof(M4_VideoStreamHandler), M4READER_3GP, (M4OSA_Char*)"M4_VideoStreamHandler"); if (M4OSA_NULL == pVideoStreamHandler) { return M4ERR_ALLOC; } pVideoStreamHandler->m_structSize=sizeof(M4_VideoStreamHandler); meta->findInt32(kKeyWidth, (int32_t*)&(pVideoStreamHandler->m_videoWidth)); meta->findInt32(kKeyHeight, (int32_t*)&(pVideoStreamHandler->m_videoHeight)); (*pStreamHandler) = (M4_StreamHandler*)(pVideoStreamHandler); meta->findInt64(kKeyDuration, (int64_t*)&(Duration)); ((*pStreamHandler)->m_duration) = (int32_t)((Duration)/1000); // conversion to mS pC->mMaxDuration = ((*pStreamHandler)->m_duration); if (pC->mMaxDuration == 0) { ALOGE("Video is too short: %lld Us", Duration); delete pVideoStreamHandler; pVideoStreamHandler = NULL; return M4ERR_PARAMETER; } ALOGV("VideoEditor3gpReader_getNextStreamHandler m_duration %d", (*pStreamHandler)->m_duration); off64_t fileSize = 0; pC->mDataSource->getSize(&fileSize); pC->mFileSize = fileSize; ALOGV("VideoEditor3gpReader_getNextStreamHandler m_fileSize %d", pC->mFileSize); meta->findInt32(kKeyMaxInputSize, (int32_t*)&(maxAUSize)); if(maxAUSize == 0) { maxAUSize = 70000; } (*pStreamHandler)->m_maxAUSize = maxAUSize; ALOGV("<<<<<<<<<< video: mMaxAUSize from MP4 extractor: %d", (*pStreamHandler)->m_maxAUSize); ((M4_StreamHandler*)pVideoStreamHandler)->m_averageBitRate = (pC->mFileSize * 8000)/pC->mMaxDuration; ALOGV("VideoEditor3gpReader_getNextStreamHandler m_averageBitrate %d", ((M4_StreamHandler*)pVideoStreamHandler)->m_averageBitRate); meta->findInt32(kKeyFrameRate, (int32_t*)&(avgFPS)); ALOGV("<<<<<<<<<< video: Average FPS from MP4 extractor: %d", avgFPS); pVideoStreamHandler->m_averageFrameRate =(M4OSA_Float) avgFPS; ALOGV("<<<<<<<<<< video: Average FPS from MP4 extractor in FLOAT: %f", pVideoStreamHandler->m_averageFrameRate); // Get the video rotation degree int32_t rotationDegree; if(!meta->findInt32(kKeyRotation, &rotationDegree)) { rotationDegree = 0; } pVideoStreamHandler->videoRotationDegrees = rotationDegree; pC->mVideoStreamHandler = (M4_StreamHandler*)(pVideoStreamHandler); /* Get the DSI info */ if(M4DA_StreamTypeVideoH263 == streamType) { if (meta->findData(kKeyD263, &type, &data, &size)) { (*pStreamHandler)->m_decoderSpecificInfoSize = size; if ((*pStreamHandler)->m_decoderSpecificInfoSize != 0) { DecoderSpecific = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( (*pStreamHandler)->m_decoderSpecificInfoSize, M4READER_3GP,(M4OSA_Char*)"H263 DSI"); if (M4OSA_NULL == DecoderSpecific) { return M4ERR_ALLOC; } memcpy((void *)DecoderSpecific, (void *)data, size); (*pStreamHandler)->m_pDecoderSpecificInfo = DecoderSpecific; } else { (*pStreamHandler)->m_pDecoderSpecificInfo = M4OSA_NULL; (*pStreamHandler)->m_decoderSpecificInfoSize = 0; } (*pStreamHandler)->m_pESDSInfo = M4OSA_NULL; (*pStreamHandler)->m_ESDSInfoSize = 0; (*pStreamHandler)->m_pH264DecoderSpecificInfo = M4OSA_NULL; (*pStreamHandler)->m_H264decoderSpecificInfoSize = 0; } else { ALOGV("VE_getNextStreamHandler: H263 dsi not found"); (*pStreamHandler)->m_pDecoderSpecificInfo = M4OSA_NULL; (*pStreamHandler)->m_decoderSpecificInfoSize = 0; (*pStreamHandler)->m_H264decoderSpecificInfoSize = 0; (*pStreamHandler)->m_pH264DecoderSpecificInfo = M4OSA_NULL; (*pStreamHandler)->m_pESDSInfo = M4OSA_NULL; (*pStreamHandler)->m_ESDSInfoSize = 0; } } else if(M4DA_StreamTypeVideoMpeg4Avc == streamType) { if(meta->findData(kKeyAVCC, &type, &data, &size)) { decoderSpecificInfoSize = size; if (decoderSpecificInfoSize != 0) { DecoderSpecificInfo = (M4OSA_Int8*)M4OSA_32bitAlignedMalloc( decoderSpecificInfoSize, M4READER_3GP, (M4OSA_Char*)"H264 DecoderSpecific" ); if (M4OSA_NULL == DecoderSpecificInfo) { ALOGV("VideoEditor3gp_getNextStream is NULL "); return M4ERR_ALLOC; } memcpy((void *)DecoderSpecificInfo, (void *)data, decoderSpecificInfoSize); } else { ALOGV("DSI Size %d", decoderSpecificInfoSize); DecoderSpecificInfo = M4OSA_NULL; } } (*pStreamHandler)->m_pESDSInfo = M4OSA_NULL; (*pStreamHandler)->m_ESDSInfoSize = 0; err = VideoEditor3gpReader_AnalyseAvcDsi(*pStreamHandler, (M4OSA_Int32*)DecoderSpecificInfo, decoderSpecificInfoSize); if (M4NO_ERROR != err) { return err; } ALOGV("decsize %d, h264decsize %d: %d", (*pStreamHandler)->\ m_decoderSpecificInfoSize, (*pStreamHandler)->\ m_H264decoderSpecificInfoSize); if(M4OSA_NULL != DecoderSpecificInfo) { free(DecoderSpecificInfo); DecoderSpecificInfo = M4OSA_NULL; } } else if( (M4DA_StreamTypeVideoMpeg4 == streamType) ) { if (meta->findData(kKeyESDS, &type, &data, &size)) { ESDS esds((const char *)data, size); CHECK_EQ(esds.InitCheck(), (status_t)OK); (*pStreamHandler)->m_ESDSInfoSize = size; (*pStreamHandler)->m_pESDSInfo = (M4OSA_UInt8*)\ M4OSA_32bitAlignedMalloc((*pStreamHandler)->m_ESDSInfoSize, M4READER_3GP, (M4OSA_Char*)"M4V DecoderSpecific" ); if (M4OSA_NULL == (*pStreamHandler)->m_pESDSInfo) { return M4ERR_ALLOC; } memcpy((void *)(*pStreamHandler)->\ m_pESDSInfo, (void *)data, size); esds.getCodecSpecificInfo(&codec_specific_data, &codec_specific_data_size); ALOGV("VE MP4 dsisize: %d, %x", codec_specific_data_size, codec_specific_data); (*pStreamHandler)->m_decoderSpecificInfoSize = codec_specific_data_size; if ((*pStreamHandler)->m_decoderSpecificInfoSize != 0) { DecoderSpecific = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( (*pStreamHandler)->m_decoderSpecificInfoSize, M4READER_3GP, (M4OSA_Char*)" DecoderSpecific" ); if (M4OSA_NULL == DecoderSpecific) { return M4ERR_ALLOC; } memcpy((void *)DecoderSpecific, (void *)codec_specific_data, codec_specific_data_size); (*pStreamHandler)->m_pDecoderSpecificInfo = DecoderSpecific; } else { (*pStreamHandler)->m_pDecoderSpecificInfo = M4OSA_NULL; } (*pStreamHandler)->m_pH264DecoderSpecificInfo = M4OSA_NULL; (*pStreamHandler)->m_H264decoderSpecificInfoSize = 0; } } else { ALOGV("VideoEditor3gpReader_getNextStream NO video stream"); return M4ERR_READER_UNKNOWN_STREAM_TYPE; } } else { ALOGV("VideoEditor3gpReader_getNextStream NO video stream"); return M4ERR_READER_UNKNOWN_STREAM_TYPE; } } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) { ALOGV("VideoEditor3gpReader_getNextStream audio getTrack called"); pC->mAudioSource = pC->mExtractor->getTrack(pC->mCurrTrack); pC->mAudioSource->start(); *pMediaFamily = M4READER_kMediaFamilyAudio; if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) { streamType = M4DA_StreamTypeAudioAmrNarrowBand; } else if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) { streamType = M4DA_StreamTypeAudioAmrWideBand; } else if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { streamType = M4DA_StreamTypeAudioAac; } else { ALOGV("VideoEditor3gpReader_getNextStrea streamtype Unknown "); } if(streamType != M4DA_StreamTypeUnknown) { pC->mStreamType = streamType; pC->mStreamId = pC->mCurrTrack; ALOGV("VE streamtype %d ,id %d", streamType, pC->mCurrTrack); pAudioStreamHandler = (M4_AudioStreamHandler*)M4OSA_32bitAlignedMalloc (sizeof(M4_AudioStreamHandler), M4READER_3GP, (M4OSA_Char*)"M4_AudioStreamHandler"); if (M4OSA_NULL == pAudioStreamHandler) { return M4ERR_ALLOC; } pAudioStreamHandler->m_structSize=sizeof(M4_AudioStreamHandler); pAudioStreamHandler->m_byteSampleSize = 0; pAudioStreamHandler->m_nbChannels = 0; pAudioStreamHandler->m_samplingFrequency= 0; pAudioStreamHandler->m_byteFrameLength = 0; (*pStreamHandler) = (M4_StreamHandler*)(pAudioStreamHandler); pC->mAudioStreamHandler = (M4_StreamHandler*)(pAudioStreamHandler); (*pStreamHandler)->m_averageBitRate = 0; haveAudio = true; pC->mAudioStreamHandler=(M4_StreamHandler*)pAudioStreamHandler; pC->mAudioStreamHandler->m_pESDSInfo = M4OSA_NULL; pC->mAudioStreamHandler->m_ESDSInfoSize = 0; meta->findInt32(kKeyMaxInputSize, (int32_t*)&(maxAUSize)); if(maxAUSize == 0) { maxAUSize = 70000; } (*pStreamHandler)->m_maxAUSize = maxAUSize; ALOGV("VE Audio mMaxAUSize from MP4 extractor: %d", maxAUSize); } if((M4DA_StreamTypeAudioAmrNarrowBand == streamType) || (M4DA_StreamTypeAudioAmrWideBand == streamType)) { M4OSA_UInt32 freqIndex = 0; /**< AMR NB */ M4OSA_UInt32 modeSet; M4OSA_UInt32 i; M4OSA_Context pBitParserContext = M4OSA_NULL; if(M4DA_StreamTypeAudioAmrWideBand == streamType) { freqIndex = 1; /**< AMR WB */ } if (meta->findData(kKeyESDS, &type, &data, &size)) { ESDS esds((const char *)data, size); CHECK_EQ(esds.InitCheck(), (status_t)OK); esds.getCodecSpecificInfo(&codec_specific_data, &codec_specific_data_size); (*pStreamHandler)->m_decoderSpecificInfoSize = codec_specific_data_size; if ((*pStreamHandler)->m_decoderSpecificInfoSize != 0) { DecoderSpecific = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( (*pStreamHandler)->m_decoderSpecificInfoSize, M4READER_3GP, (M4OSA_Char*)"AMR DecoderSpecific" ); if (M4OSA_NULL == DecoderSpecific) { return M4ERR_ALLOC; } memcpy((void *)DecoderSpecific, (void *)codec_specific_data, codec_specific_data_size); (*pStreamHandler)->m_pDecoderSpecificInfo = DecoderSpecific; } else { (*pStreamHandler)->m_pDecoderSpecificInfo = M4OSA_NULL; } } else { M4OSA_UChar AmrDsi[] = {'P','H','L','P',0x00, 0x00, 0x80, 0x00, 0x01,}; (*pStreamHandler)->m_decoderSpecificInfoSize = 9; DecoderSpecific = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( (*pStreamHandler)->m_decoderSpecificInfoSize, M4READER_3GP, (M4OSA_Char*)"PHLP DecoderSpecific" ); if (M4OSA_NULL == DecoderSpecific) { return M4ERR_ALLOC; } if(freqIndex ==0) { AmrDsi[8] = 0x01; } else { AmrDsi[8] = 0x02; } for(i = 0; i< 9; i++) { DecoderSpecific[i] = AmrDsi[i]; } (*pStreamHandler)->m_pDecoderSpecificInfo = DecoderSpecific; } (*pStreamHandler)->m_averageBitRate = VideoEditor3gpReader_AmrBitRate[freqIndex][7]; } else if((M4DA_StreamTypeAudioAac == streamType)) { if (meta->findData(kKeyESDS, &type, &data, &size)) { ESDS esds((const char *)data, size); CHECK_EQ(esds.InitCheck(), (status_t)OK); (*pStreamHandler)->m_ESDSInfoSize = size; (*pStreamHandler)->m_pESDSInfo = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( (*pStreamHandler)->m_ESDSInfoSize, M4READER_3GP, (M4OSA_Char*)"AAC DecoderSpecific" ); if (M4OSA_NULL == (*pStreamHandler)->m_pESDSInfo) { return M4ERR_ALLOC; } memcpy((void *)(*pStreamHandler)->m_pESDSInfo, (void *)data, size); esds.getCodecSpecificInfo(&codec_specific_data, &codec_specific_data_size); ALOGV("VEdsi %d,%x",codec_specific_data_size, codec_specific_data); (*pStreamHandler)->m_decoderSpecificInfoSize = codec_specific_data_size; if ((*pStreamHandler)->m_decoderSpecificInfoSize != 0) { DecoderSpecific = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( (*pStreamHandler)->m_decoderSpecificInfoSize, M4READER_3GP, (M4OSA_Char*)"AAC DecoderSpecific" ); if (M4OSA_NULL == DecoderSpecific) { return M4ERR_ALLOC; } memcpy((void *)DecoderSpecific, (void *)codec_specific_data, codec_specific_data_size); (*pStreamHandler)->m_pDecoderSpecificInfo = DecoderSpecific; } else { (*pStreamHandler)->m_pDecoderSpecificInfo = M4OSA_NULL; } } } else { ALOGV("VideoEditor3gpReader_getNextStream mStreamType: none "); return M4ERR_READER_UNKNOWN_STREAM_TYPE; } } else { ALOGV("VE noaudio-video stream:pC->mCurrTrack = %d ",pC->mCurrTrack); pC->mCurrTrack++; //Increment current track to get the next track return M4ERR_READER_UNKNOWN_STREAM_TYPE; } ALOGV("VE StreamType: %d, stremhandler %x",streamType, *pStreamHandler ); (*pStreamHandler)->m_streamType = streamType; (*pStreamHandler)->m_streamId = pC->mStreamId; (*pStreamHandler)->m_pUserData = M4OSA_NULL; (*pStreamHandler)->m_structSize = sizeof(M4_StreamHandler); (*pStreamHandler)->m_bStreamIsOK = M4OSA_TRUE; meta->findInt64(kKeyDuration, (int64_t*)&(Duration)); (*pStreamHandler)->m_duration = (int32_t)(Duration / 1000); pC->mMaxDuration = ((*pStreamHandler)->m_duration); ALOGV("VE str duration duration: %d ", (*pStreamHandler)->m_duration); /* In AAC case: Put the first AU in pAudioStreamHandler->m_pUserData *since decoder has to know if stream contains SBR data(Implicit sig) */ if(M4DA_StreamTypeAudioAac == (*pStreamHandler)->m_streamType) { M4READER_AudioSbrUserdata* pAudioSbrUserdata; pAudioSbrUserdata = (M4READER_AudioSbrUserdata*)M4OSA_32bitAlignedMalloc( sizeof(M4READER_AudioSbrUserdata),M4READER_3GP, (M4OSA_Char*)"M4READER_AudioSbrUserdata"); if (M4OSA_NULL == pAudioSbrUserdata) { err = M4ERR_ALLOC; goto Error; } (*pStreamHandler)->m_pUserData = pAudioSbrUserdata; pAudioSbrUserdata->m_bIsSbrEnabled = M4OSA_FALSE; pAudioSbrUserdata->m_pFirstAU = (M4_AccessUnit*)M4OSA_32bitAlignedMalloc( sizeof(M4_AccessUnit),M4READER_3GP, (M4OSA_Char*)"1st AAC AU"); if (M4OSA_NULL == pAudioSbrUserdata->m_pFirstAU) { pAudioSbrUserdata->m_pAacDecoderUserConfig = M4OSA_NULL; err = M4ERR_ALLOC; goto Error; } pAudioSbrUserdata->m_pAacDecoderUserConfig = (M4_AacDecoderConfig*)\ M4OSA_32bitAlignedMalloc(sizeof(M4_AacDecoderConfig),M4READER_3GP, (M4OSA_Char*)"m_pAacDecoderUserConfig"); if (M4OSA_NULL == pAudioSbrUserdata->m_pAacDecoderUserConfig) { err = M4ERR_ALLOC; goto Error; } } if(M4DA_StreamTypeAudioAac == (*pStreamHandler)->m_streamType) { M4_AudioStreamHandler* pAudioStreamHandler = (M4_AudioStreamHandler*)(*pStreamHandler); M4READER_AudioSbrUserdata* pUserData = (M4READER_AudioSbrUserdata*)\ (pAudioStreamHandler->m_basicProperties.m_pUserData); err = VideoEditor3gpReader_fillAuStruct(pC, (*pStreamHandler), (M4_AccessUnit*)pUserData->m_pFirstAU); if (M4NO_ERROR != err) { goto Error; } err = VideoEditor3gpReader_getNextAu(pC, (*pStreamHandler), (M4_AccessUnit*)pUserData->m_pFirstAU); /* * 1. "M4WAR_NO_MORE_AU == err" indicates that there is no more * access unit from the current track. In other words, there * is only a single access unit from the current track, and * the parsing of this track has reached EOS. The reason why * the first access unit needs to be parsed here is because for * some audio codec (like AAC), the very first access unit * must be decoded before its configuration/encoding parameters * (such as # of channels and sample rate) can be correctly * determined. * * 2. "trackCount > pC->mCurrTrack" indicates that there are other * tracks to be parsed, in addition to the current track. * * When both conditions 1 & 2 hold, other tracks should be * parsed. Thus, we should not bail out. */ if (M4WAR_NO_MORE_AU == err && trackCount > pC->mCurrTrack) { err = M4NO_ERROR; } if (M4NO_ERROR != err) { goto Error; } err = VideoEditor3gpReader_reset(pC, (*pStreamHandler)); if (M4NO_ERROR != err) { goto Error; } } } pC->mCurrTrack++; //Increment the current track to get next track ALOGV("pC->mCurrTrack = %d",pC->mCurrTrack); if (!haveAudio && !haveVideo) { *pMediaFamily=M4READER_kMediaFamilyUnknown; return M4ERR_READER_UNKNOWN_STREAM_TYPE; } Error: ALOGV("VideoEditor3gpReader_getNextStreamHandler end error = %d",err); return err; } M4OSA_ERR VideoEditor3gpReader_getPrevRapTime(M4OSA_Context context, M4_StreamHandler *pStreamHandler, M4OSA_Int32* pTime) { VideoEditor3gpReader_Context *pC = (VideoEditor3gpReader_Context*)context; M4OSA_ERR err = M4NO_ERROR; MediaBuffer *mMediaBuffer = M4OSA_NULL; MediaSource::ReadOptions options; M4OSA_Time time64; int64_t tempTime64 = 0; status_t error; ALOGV("VideoEditor3gpReader_getPrevRapTime begin"); M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_getPrevRapTime: invalid context"); M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_getPrevRapTime invalid pointer to StreamHandler"); M4OSA_DEBUG_IF1((pTime == 0), M4ERR_PARAMETER, "VideoEditor3gpReader_getPrevRapTime: invalid time pointer"); if (*pTime == (pStreamHandler->m_duration)) { *pTime -= 1; } time64 = (M4OSA_Time)*pTime * 1000; ALOGV("VideoEditor3gpReader_getPrevRapTime seek time: %ld",time64); options.setSeekTo(time64, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); error = pC->mVideoSource->read(&mMediaBuffer, &options); if (error != OK) { //Can not get the previous Sync. //Must be end of stream. return M4WAR_NO_MORE_AU; } mMediaBuffer->meta_data()->findInt64(kKeyTime, (int64_t*)&tempTime64); ALOGV("VideoEditor3gpReader_getPrevRapTime read time %ld, %x", tempTime64, mMediaBuffer); *pTime = (M4OSA_Int32)(tempTime64 / 1000); if(mMediaBuffer != M4OSA_NULL) { ALOGV(" mMediaBuffer size = %d length %d", mMediaBuffer->size(), mMediaBuffer->range_length()); mMediaBuffer->release(); mMediaBuffer = M4OSA_NULL; } options.clearSeekTo(); if(error != OK) { ALOGV("VideoEditor3gpReader_getPrevRapTime end \ M4WAR_READER_INFORMATION_NOT_PRESENT"); return M4WAR_READER_INFORMATION_NOT_PRESENT; } else { ALOGV("VideoEditor3gpReader_getPrevRapTime end: err %x", err); err = M4NO_ERROR; return err; } } extern "C" { M4OSA_ERR VideoEditor3gpReader_getInterface(M4READER_MediaType *pMediaType, M4READER_GlobalInterface **pRdrGlobalInterface, M4READER_DataInterface **pRdrDataInterface) { M4OSA_ERR err = M4NO_ERROR; VIDEOEDITOR_CHECK(M4OSA_NULL != pMediaType, M4ERR_PARAMETER); VIDEOEDITOR_CHECK(M4OSA_NULL != pRdrGlobalInterface, M4ERR_PARAMETER); VIDEOEDITOR_CHECK(M4OSA_NULL != pRdrDataInterface, M4ERR_PARAMETER); ALOGV("VideoEditor3gpReader_getInterface begin"); ALOGV("VideoEditor3gpReader_getInterface %d 0x%x 0x%x", *pMediaType, *pRdrGlobalInterface,*pRdrDataInterface); SAFE_MALLOC(*pRdrGlobalInterface, M4READER_GlobalInterface, 1, "VideoEditor3gpReader_getInterface"); SAFE_MALLOC(*pRdrDataInterface, M4READER_DataInterface, 1, "VideoEditor3gpReader_getInterface"); *pMediaType = M4READER_kMediaType3GPP; (*pRdrGlobalInterface)->m_pFctCreate = VideoEditor3gpReader_create; (*pRdrGlobalInterface)->m_pFctDestroy = VideoEditor3gpReader_destroy; (*pRdrGlobalInterface)->m_pFctOpen = VideoEditor3gpReader_open; (*pRdrGlobalInterface)->m_pFctClose = VideoEditor3gpReader_close; (*pRdrGlobalInterface)->m_pFctGetOption = VideoEditor3gpReader_getOption; (*pRdrGlobalInterface)->m_pFctSetOption = VideoEditor3gpReader_setOption; (*pRdrGlobalInterface)->m_pFctGetNextStream = VideoEditor3gpReader_getNextStreamHandler; (*pRdrGlobalInterface)->m_pFctFillAuStruct = VideoEditor3gpReader_fillAuStruct; (*pRdrGlobalInterface)->m_pFctStart = M4OSA_NULL; (*pRdrGlobalInterface)->m_pFctStop = M4OSA_NULL; (*pRdrGlobalInterface)->m_pFctJump = VideoEditor3gpReader_jump; (*pRdrGlobalInterface)->m_pFctReset = VideoEditor3gpReader_reset; (*pRdrGlobalInterface)->m_pFctGetPrevRapTime = VideoEditor3gpReader_getPrevRapTime; (*pRdrDataInterface)->m_pFctGetNextAu = VideoEditor3gpReader_getNextAu; (*pRdrDataInterface)->m_readerContext = M4OSA_NULL; cleanUp: if( M4NO_ERROR == err ) { ALOGV("VideoEditor3gpReader_getInterface no error"); } else { SAFE_FREE(*pRdrGlobalInterface); SAFE_FREE(*pRdrDataInterface); ALOGV("VideoEditor3gpReader_getInterface ERROR 0x%X", err); } ALOGV("VideoEditor3gpReader_getInterface end"); return err; } } /* extern "C" */ } /* namespace android */