| /* |
| * 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 <media/stagefright/foundation/ADebug.h> |
| #include <media/stagefright/MediaBufferGroup.h> |
| #include <media/stagefright/DataSource.h> |
| #include <media/stagefright/FileSource.h> |
| #include <media/stagefright/MediaBuffer.h> |
| #include <media/stagefright/MediaDefs.h> |
| #include <media/stagefright/MediaExtractor.h> |
| #include <media/stagefright/MediaSource.h> |
| #include <media/stagefright/MetaData.h> |
| |
| /** |
| * SOURCE CLASS |
| */ |
| namespace android { |
| /** |
| * ENGINE INTERFACE |
| */ |
| |
| const char *MEDIA_MIMETYPE_AUDIO_AACEXTENDED = "audio/mp4a-aacextended"; |
| /** |
| ************************************************************************ |
| * @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<DataSource> mDataSource; |
| sp<MediaExtractor> mExtractor; |
| sp<MediaSource> mAudioSource; |
| sp<MediaSource> 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 <length> 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 <length> 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<MetaData> meta = pC->mExtractor->getMetaData(); |
| meta->findInt32(kKeyIsDRM, &isDRMProtected); |
| if (isDRMProtected) { |
| ALOGV("VideoEditorMp3Reader_open error - DRM Protected"); |
| return M4ERR_UNSUPPORTED_MEDIA_TYPE; |
| } |
| |
| M4OSA_UInt8 temp, trackCount; |
| const char *mime; |
| temp = 0; |
| trackCount = pC->mExtractor->countTracks(); |
| while (temp < trackCount) { |
| meta = pC->mExtractor->getTrackMetaData(temp); |
| CHECK(meta->findCString(kKeyMIMEType, &mime)); |
| if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_MPEG)) { |
| ALOGV("VideoEditorMp3Reader_open error - audio/mpeg is not supported"); |
| return M4ERR_READER_UNKNOWN_STREAM_TYPE; |
| } |
| if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AACEXTENDED)) { |
| ALOGV("VideoEditorMp3Reader_open error - audio/aacextended is not supported"); |
| return M4ERR_READER_UNKNOWN_STREAM_TYPE; |
| } |
| temp++; |
| } |
| |
| 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 M4READER_3GP_kOptionID_AudioOnly: |
| break; |
| |
| case M4READER_3GP_kOptionID_VideoOnly: |
| break; |
| |
| case M4READER_3GP_kOptionID_FastOpenMode: |
| break; |
| |
| case 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((pReaderContext == 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; j<uiSize; j++) { |
| VideoEditor3gpReader_BitStreamParserFlushBits( |
| pBitParserContext, 8); |
| } |
| } |
| |
| /** |
| * SPS table */ |
| numOfPictureParameterSets=(M4OSA_UInt8)\ |
| VideoEditor3gpReader_BitStreamParserShowBits(pBitParserContext, |
| 8); |
| VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); |
| for (i=0; i < numOfPictureParameterSets; i++) { |
| /** |
| * Get the size of this element */ |
| uiSize = (M4OSA_UInt32) |
| VideoEditor3gpReader_BitStreamParserShowBits( |
| pBitParserContext, 16); |
| uiTotalSizeOfPPS += uiSize; |
| VideoEditor3gpReader_BitStreamParserFlushBits( |
| pBitParserContext, 16); |
| /** |
| *Read the element(dont keep it,we only want size right now)*/ |
| for (j=0; j<uiSize; j++) { |
| VideoEditor3gpReader_BitStreamParserFlushBits( |
| pBitParserContext, 8); |
| } |
| } |
| |
| /** |
| * Compute the size of the full buffer */ |
| uiSpecInfoSize = sizeof(struct _avcSpecificInfo) + |
| numOfSequenceParameterSets * sizeof(struct _parameterSet) |
| + /**< size of the table of SPS elements */ |
| numOfPictureParameterSets * sizeof(struct _parameterSet) |
| + /**< size of the table of PPS elements */ |
| uiTotalSizeOfSPS + |
| uiTotalSizeOfPPS; |
| /** |
| * Allocate the buffer */ |
| pAvcSpecInfo =(struct _avcSpecificInfo*)M4OSA_32bitAlignedMalloc(uiSpecInfoSize, |
| M4READER_3GP, (M4OSA_Char*)"MPEG-4 AVC DecoderSpecific"); |
| if (M4OSA_NULL == pAvcSpecInfo) { |
| VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext); |
| return M4ERR_ALLOC; |
| } |
| |
| /** |
| * Set the pointers to the correct part of the buffer */ |
| pAvcSpecInfo->m_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; j<pAvcSpecInfo->m_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; j<pAvcSpecInfo->m_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<MetaData> 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); |
| 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 */ |
| |
| |