| /* |
| * 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 M4AMRR_CoreReader.c |
| * @brief Implementation of AMR parser |
| * @note This file contains the API Implementation for |
| * AMR Parser. |
| ****************************************************************************** |
| */ |
| #include "M4AMRR_CoreReader.h" |
| #include "M4OSA_Debug.h" |
| #include "M4OSA_CoreID.h" |
| |
| /** |
| ****************************************************************************** |
| * Maximum bitrate per amr type |
| ****************************************************************************** |
| */ |
| #define M4AMRR_NB_MAX_BIT_RATE 12200 |
| #define M4AMRR_WB_MAX_BIT_RATE 23850 |
| |
| /** |
| ****************************************************************************** |
| * AMR reader context ID |
| ****************************************************************************** |
| */ |
| #define M4AMRR_CONTEXTID 0x414d5252 |
| |
| /** |
| ****************************************************************************** |
| * An AMR frame is 20ms |
| ****************************************************************************** |
| */ |
| #define M4AMRR_FRAME_LENGTH 20 |
| |
| /** |
| ****************************************************************************** |
| * For the seek, the file is splitted in 40 segments for faster search |
| ****************************************************************************** |
| */ |
| #define M4AMRR_NUM_SEEK_ENTRIES 40 |
| |
| #define M4AMRR_NB_SAMPLE_FREQUENCY 8000 /**< Narrow band sampling rate */ |
| #define M4AMRR_WB_SAMPLE_FREQUENCY 16000 /**< Wide band sampling rate */ |
| |
| /** |
| ****************************************************************************** |
| * AMR reader version numbers |
| ****************************************************************************** |
| */ |
| /* CHANGE_VERSION_HERE */ |
| #define M4AMRR_VERSION_MAJOR 1 |
| #define M4AMRR_VERSION_MINOR 11 |
| #define M4AMRR_VERSION_REVISION 3 |
| |
| /** |
| ****************************************************************************** |
| * structure M4_AMRR_Context |
| * @brief Internal AMR reader context structure |
| ****************************************************************************** |
| */ |
| typedef struct |
| { |
| M4OSA_UInt32 m_contextId ; /* Fixed Id. to check for valid Context*/ |
| M4OSA_FileReadPointer* m_pOsaFilePtrFct; /* File function pointer */ |
| M4SYS_StreamDescription* m_pStreamHandler; /* Stream Description */ |
| M4OSA_UInt32* m_pSeekIndex; /* Seek Index Table */ |
| M4OSA_UInt32 m_seekInterval; /* Stores the seek Interval stored in the Index */ |
| M4OSA_UInt32 m_maxAuSize; /* Stores the max Au Size */ |
| M4OSA_MemAddr32 m_pdataAddress; /* Pointer to store AU data */ |
| M4SYS_StreamType m_streamType; /* Stores the stream type AMR NB or WB */ |
| M4OSA_Context m_pAMRFile; /* Data storage */ |
| M4AMRR_State m_status; /* AMR Reader Status */ |
| M4OSA_Int32 m_structSize; /* size of structure*/ |
| } M4_AMRR_Context; |
| |
| /** |
| ****************************************************************************** |
| * Parser internal functions, not usable from outside the reader context |
| ****************************************************************************** |
| */ |
| M4OSA_UInt32 M4AMRR_getAuSize(M4OSA_UInt32 frameType, M4SYS_StreamType streamType); |
| M4OSA_UInt32 M4AMRR_getBitrate(M4OSA_UInt32 frameType, M4SYS_StreamType streamType); |
| |
| /** |
| ****************************************************************************** |
| * M4OSA_UInt32 M4AMRR_getAuSize(M4OSA_UInt32 frameType, M4SYS_StreamType streamType) |
| * @brief Internal function to the AMR Parser, returns the AU size of the Frame |
| * @note This function takes the stream type and the frametype and returns the |
| * frame lenght |
| * @param frameType(IN) : AMR frame type |
| * @param streamType(IN) : AMR stream type NB or WB |
| * @returns The frame size based on the frame type. |
| ****************************************************************************** |
| */ |
| M4OSA_UInt32 M4AMRR_getAuSize(M4OSA_UInt32 frameType, M4SYS_StreamType streamType) |
| { |
| const M4OSA_UInt32 M4AMRR_NB_AUSIZE[]={13,14,16,18,20,21,27,32,6,6,6}; |
| const M4OSA_UInt32 M4AMRR_WB_AUSIZE[]={18,24,33,37,41,47,51,59,61,6}; |
| |
| if ( streamType == M4SYS_kAMR ) |
| { |
| return M4AMRR_NB_AUSIZE[frameType]; |
| } |
| else /* M4SYS_kAMR_WB */ |
| { |
| return M4AMRR_WB_AUSIZE[frameType]; |
| } |
| } |
| |
| /** |
| ****************************************************************************** |
| * M4OSA_UInt32 M4AMRR_getBitrate(M4OSA_UInt32 frameType, M4SYS_StreamType streamType) |
| * @brief Internal function to the AMR Parser, returns the Bit rate of the Frame |
| * @note This function takes the stream type and the frametype and returns the |
| * bit rate for the given frame. |
| * @param frameType(IN) : AMR frame type |
| * @param streamType(IN) : AMR stream type NB or WB |
| * @returns The frame's bit rate based on the frame type. |
| ****************************************************************************** |
| */ |
| M4OSA_UInt32 M4AMRR_getBitrate(M4OSA_UInt32 frameType, M4SYS_StreamType streamType) |
| { |
| const M4OSA_UInt32 M4AMRR_NB_BITRATE[]= |
| {4750,5150,5900,6700,7400,7950,10200,12200,12200,12200,12200}; |
| const M4OSA_UInt32 M4AMRR_WB_BITRATE[]= |
| {6600,8850,12650,14250,15850,18250,19850,23050,23850,12200}; |
| |
| if ( streamType == M4SYS_kAMR ) |
| { |
| return M4AMRR_NB_BITRATE[frameType]; |
| } |
| else /* M4SYS_kAMR_WB */ |
| { |
| return M4AMRR_WB_BITRATE[frameType]; |
| } |
| } |
| |
| /*********************************************************/ |
| M4OSA_ERR M4AMRR_openRead(M4OSA_Context* pContext, M4OSA_Void* pFileDescriptor, |
| M4OSA_FileReadPointer* pFileFunction) |
| /*********************************************************/ |
| { |
| M4_AMRR_Context* pStreamContext; |
| M4OSA_FilePosition filePos; |
| |
| M4OSA_ERR err = M4ERR_FILE_NOT_FOUND ; |
| M4OSA_UInt32 size ; |
| M4OSA_UInt32 data ; |
| M4OSA_Char *M4_Token; |
| M4OSA_UInt32 *tokenPtr; |
| |
| /* Header for AMR NB */ |
| M4OSA_UInt32 M4_AMR_1 = 0x4d412123; |
| M4OSA_UInt32 M4_AMR_NB_2 = 0x00000a52; |
| |
| /* Header for AMR WB */ |
| M4OSA_UInt32 M4_AMR_WB_2 = 0x42572d52; |
| M4OSA_UInt32 M4_AMR_WB_3 = 0x0000000a; |
| *pContext = M4OSA_NULL ; |
| |
| M4OSA_DEBUG_IF2((M4OSA_NULL == pContext),M4ERR_PARAMETER,"Context M4OSA_NULL"); |
| M4OSA_DEBUG_IF2((M4OSA_NULL == pFileDescriptor),M4ERR_PARAMETER,"File Desc. M4OSA_NULL"); |
| |
| M4_Token = (M4OSA_Char*)M4OSA_32bitAlignedMalloc(sizeof(M4OSA_MemAddr32)*3, M4AMR_READER, |
| (M4OSA_Char *)("M4_Token")); |
| if(M4OSA_NULL == M4_Token) |
| { |
| M4OSA_DEBUG_IF3((M4OSA_NULL == M4_Token),M4ERR_ALLOC,"Mem Alloc failed - M4_Token"); |
| return M4ERR_ALLOC ; |
| } |
| |
| pStreamContext= (M4_AMRR_Context*)M4OSA_32bitAlignedMalloc(sizeof(M4_AMRR_Context), M4AMR_READER, |
| (M4OSA_Char *)("pStreamContext")); |
| if(M4OSA_NULL == pStreamContext) |
| { |
| free(M4_Token); |
| *pContext = M4OSA_NULL ; |
| return M4ERR_ALLOC ; |
| } |
| |
| /* Initialize the context */ |
| pStreamContext->m_contextId = M4AMRR_CONTEXTID; |
| pStreamContext->m_structSize=sizeof(M4_AMRR_Context); |
| pStreamContext->m_pOsaFilePtrFct=pFileFunction ; |
| pStreamContext->m_pStreamHandler = M4OSA_NULL ; |
| pStreamContext->m_pAMRFile = M4OSA_NULL ; |
| pStreamContext->m_status = M4AMRR_kOpening ; |
| pStreamContext->m_pSeekIndex = M4OSA_NULL ; |
| pStreamContext->m_seekInterval = 0; |
| pStreamContext->m_maxAuSize = 0 ; |
| pStreamContext->m_pdataAddress = M4OSA_NULL; |
| err=pStreamContext->m_pOsaFilePtrFct->openRead(&pStreamContext->m_pAMRFile, |
| (M4OSA_Char*)pFileDescriptor,M4OSA_kFileRead ); |
| if ( err != M4NO_ERROR ) |
| { |
| /* M4OSA_DEBUG_IF3((err != M4NO_ERROR),err,"File open failed"); */ |
| free(pStreamContext); |
| free(M4_Token); |
| *pContext = M4OSA_NULL ; |
| return err ; |
| } |
| |
| pStreamContext->m_status = M4AMRR_kOpening ; |
| |
| size = 6; |
| pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile, |
| (M4OSA_MemAddr8)M4_Token, &size); |
| if(size != 6) |
| { |
| goto cleanup; |
| } |
| |
| tokenPtr = (M4OSA_UInt32*)M4_Token ; |
| /* Check for the first 4 bytes of the header common to WB and NB*/ |
| if (*tokenPtr != M4_AMR_1) |
| { |
| goto cleanup; |
| } |
| |
| tokenPtr++; |
| data = *tokenPtr & 0x0000FFFF ; |
| /* Check if the next part is Narrow band header */ |
| if (data!= M4_AMR_NB_2) |
| { |
| /* Stream is AMR Wide Band */ |
| filePos = 4; |
| pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, |
| M4OSA_kFileSeekBeginning, &filePos); |
| size = 5; |
| pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile, |
| (M4OSA_MemAddr8)M4_Token, &size); |
| if(size != 5) |
| goto cleanup; |
| tokenPtr=(M4OSA_UInt32*)M4_Token; |
| /* Check for the Wide band hader */ |
| if(*tokenPtr!= M4_AMR_WB_2) |
| goto cleanup; |
| tokenPtr++; |
| data = *tokenPtr & 0x000000FF ; |
| if(data!= M4_AMR_WB_3) |
| goto cleanup; |
| pStreamContext->m_streamType = M4SYS_kAMR_WB ; |
| } |
| else |
| { |
| /* Stream is a Narrow band stream */ |
| pStreamContext->m_streamType = M4SYS_kAMR ; |
| } |
| /* No Profile level defined */ |
| pStreamContext->m_status = M4AMRR_kOpened; |
| |
| free(M4_Token); |
| *pContext = pStreamContext ; |
| return M4NO_ERROR; |
| |
| cleanup: |
| |
| if(M4OSA_NULL != pStreamContext->m_pAMRFile) |
| { |
| pStreamContext->m_pOsaFilePtrFct->closeRead(pStreamContext->m_pAMRFile); |
| } |
| |
| free(M4_Token); |
| free(pStreamContext); |
| |
| *pContext = M4OSA_NULL ; |
| |
| return (M4OSA_ERR)M4ERR_AMR_NOT_COMPLIANT; |
| } |
| |
| |
| /*********************************************************/ |
| M4OSA_ERR M4AMRR_getNextStream(M4OSA_Context Context, M4SYS_StreamDescription* pStreamDesc ) |
| /*********************************************************/ |
| { |
| M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context; |
| M4OSA_Char frameHeader, frameType ; |
| M4OSA_UInt32 size, auCount=0; |
| M4OSA_FilePosition filePos; |
| |
| M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL"); |
| M4OSA_DEBUG_IF2((M4OSA_NULL == pStreamDesc),M4ERR_PARAMETER,"Stream Desc. M4OSA_NULL"); |
| M4OSA_DEBUG_IF2((pStreamContext->m_contextId != M4AMRR_CONTEXTID),M4ERR_BAD_CONTEXT, |
| "Bad Context"); |
| M4OSA_DEBUG_IF1(( pStreamContext->m_status != M4AMRR_kOpened), M4ERR_STATE, "Invalid State"); |
| |
| if (M4OSA_NULL != pStreamContext->m_pStreamHandler) |
| { |
| return M4WAR_NO_MORE_STREAM ; |
| } |
| |
| size = 1; |
| pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile, |
| (M4OSA_MemAddr8)&frameHeader, &size); |
| |
| /* XFFF FXXX -> F is the Frame type */ |
| frameType = ( frameHeader & 0x78 ) >> 3 ; |
| |
| if ( frameType == 15 ) |
| { |
| return M4WAR_NO_DATA_YET ; |
| } |
| |
| if (( pStreamContext->m_streamType == M4SYS_kAMR ) && ( frameType > 11 )) |
| { |
| return (M4OSA_ERR)M4ERR_AMR_INVALID_FRAME_TYPE; |
| } |
| |
| if (( pStreamContext->m_streamType == M4SYS_kAMR_WB ) && ( frameType > 9 )) |
| { |
| return (M4OSA_ERR)M4ERR_AMR_INVALID_FRAME_TYPE; |
| } |
| |
| /* Average bit rate is assigned the bitrate of the first frame */ |
| pStreamDesc->averageBitrate = M4AMRR_getBitrate(frameType,pStreamContext->m_streamType); |
| |
| filePos = -1; |
| pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, M4OSA_kFileSeekCurrent, |
| &filePos); |
| |
| /* Initialize pStreamDesc */ |
| pStreamDesc->profileLevel = 0xFF ; |
| pStreamDesc->decoderSpecificInfoSize = 0 ; |
| pStreamDesc->decoderSpecificInfo = M4OSA_NULL ; |
| pStreamDesc->maxBitrate = (pStreamContext->m_streamType == |
| M4SYS_kAMR )?M4AMRR_NB_MAX_BIT_RATE:M4AMRR_WB_MAX_BIT_RATE; |
| pStreamDesc->profileLevel = 0xFF ; |
| pStreamDesc->streamID = 1; |
| pStreamDesc->streamType = pStreamContext->m_streamType; |
| |
| /* Timescale equals Sampling Frequency: NB-8000 Hz, WB-16000 Hz */ |
| pStreamDesc->timeScale = (pStreamContext->m_streamType == M4SYS_kAMR )?8000:16000; |
| pStreamDesc->duration = M4OSA_TIME_UNKNOWN; |
| |
| pStreamContext->m_pStreamHandler = |
| (M4SYS_StreamDescription*)M4OSA_32bitAlignedMalloc(sizeof(M4SYS_StreamDescription), |
| M4AMR_READER, (M4OSA_Char *)("pStreamContext->m_pStreamHandler")); |
| if(M4OSA_NULL == pStreamContext->m_pStreamHandler) |
| { |
| return M4ERR_ALLOC; |
| } |
| |
| /* Copy the Stream Desc. into the Context */ |
| pStreamContext->m_pStreamHandler->averageBitrate = pStreamDesc->averageBitrate; |
| pStreamContext->m_pStreamHandler->decoderSpecificInfo = M4OSA_NULL ; |
| pStreamContext->m_pStreamHandler->decoderSpecificInfoSize = 0 ; |
| pStreamContext->m_pStreamHandler->duration = M4OSA_TIME_UNKNOWN; |
| pStreamContext->m_pStreamHandler->profileLevel = 0xFF ; |
| pStreamContext->m_pStreamHandler->streamID = 1; |
| pStreamContext->m_pStreamHandler->streamType = pStreamDesc->streamType ; |
| pStreamContext->m_pStreamHandler->timeScale = pStreamDesc->timeScale ; |
| |
| /* Count the number of Access Unit in the File to get the */ |
| /* duration of the stream = 20 ms * number of access unit */ |
| while(1) |
| { |
| size = 1; |
| pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile, |
| (M4OSA_MemAddr8)&frameHeader, &size); |
| if ( size == 0) |
| break ; |
| frameType = (frameHeader & 0x78) >> 3 ; |
| /* Get the frame size and skip so many bytes */ |
| if(frameType != 15){ |
| /* GLA 20050628 when frametype is >10 we read over a table */ |
| if(frameType > 10) |
| continue ; |
| |
| size = M4AMRR_getAuSize(frameType, pStreamContext->m_streamType); |
| if(size > pStreamContext->m_maxAuSize ) |
| { |
| pStreamContext->m_maxAuSize = size ; |
| } |
| filePos = size-1; |
| pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, |
| M4OSA_kFileSeekCurrent, &filePos); |
| auCount++; |
| } |
| } |
| |
| /* Each Frame is 20 m Sec. */ |
| pStreamContext->m_pStreamHandler->duration = auCount * M4AMRR_FRAME_LENGTH ; |
| pStreamDesc->duration = pStreamContext->m_pStreamHandler->duration ; |
| |
| /* Put the file pointer back at the first Access unit */ |
| if( pStreamContext->m_streamType == M4SYS_kAMR ) |
| { |
| filePos = 6; |
| pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, |
| M4OSA_kFileSeekBeginning, &filePos); |
| } |
| if ( pStreamContext->m_streamType == M4SYS_kAMR_WB ) |
| { |
| filePos = 9; |
| pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, |
| M4OSA_kFileSeekBeginning, &filePos); |
| } |
| return M4NO_ERROR ; |
| } |
| |
| /*********************************************************/ |
| M4OSA_ERR M4AMRR_startReading(M4OSA_Context Context, M4SYS_StreamID* pStreamIDs ) |
| /*********************************************************/ |
| { |
| M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context; |
| M4OSA_Int32 size = 0 ; |
| |
| M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL"); |
| M4OSA_DEBUG_IF2((M4OSA_NULL == pStreamIDs),M4ERR_PARAMETER,"Stream Ids. M4OSA_NULL"); |
| M4OSA_DEBUG_IF2((pStreamContext->m_contextId != M4AMRR_CONTEXTID),M4ERR_BAD_CONTEXT, |
| "Bad Context"); |
| M4OSA_DEBUG_IF1(( pStreamContext->m_status != M4AMRR_kOpened), M4ERR_STATE, "Invalid State"); |
| |
| while( pStreamIDs[size] != 0 ) |
| { |
| if( pStreamIDs[size++] != 1 ) |
| { |
| return M4ERR_BAD_STREAM_ID ; |
| } |
| } |
| |
| /* Allocate memory for data Address for use in NextAU() */ |
| if(M4OSA_NULL == pStreamContext->m_pdataAddress) |
| { |
| size = pStreamContext->m_maxAuSize ; |
| /* dataAddress is owned by Parser, application should not delete or free it */ |
| pStreamContext->m_pdataAddress =(M4OSA_MemAddr32)M4OSA_32bitAlignedMalloc(size + (4 - size % 4), |
| M4AMR_READER, (M4OSA_Char *)("pStreamContext->m_pdataAddress")); |
| if(M4OSA_NULL == pStreamContext->m_pdataAddress) |
| { |
| M4OSA_DEBUG_IF3((M4OSA_NULL == pStreamContext->m_pdataAddress),M4ERR_ALLOC, |
| "Mem Alloc failed - dataAddress"); |
| return M4ERR_ALLOC; |
| } |
| } |
| |
| /* Set the state of context to Reading */ |
| pStreamContext->m_status = M4AMRR_kReading ; |
| |
| return M4NO_ERROR ; |
| } |
| |
| |
| /*********************************************************/ |
| M4OSA_ERR M4AMRR_nextAU(M4OSA_Context Context, M4SYS_StreamID StreamID, M4SYS_AccessUnit* pAu) |
| /*********************************************************/ |
| { |
| M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context; |
| M4OSA_Char frameHeader ; |
| M4OSA_Char frameType ; |
| M4OSA_Int32 auSize; |
| M4OSA_UInt32 size ; |
| M4OSA_FilePosition filePos; |
| |
| M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL"); |
| M4OSA_DEBUG_IF2((M4OSA_NULL == pAu),M4ERR_PARAMETER,"Access Unit . M4OSA_NULL"); |
| M4OSA_DEBUG_IF2((pStreamContext->m_contextId != M4AMRR_CONTEXTID),M4ERR_BAD_CONTEXT, |
| "Bad Context"); |
| M4OSA_DEBUG_IF1(( pStreamContext->m_status != M4AMRR_kReading), M4ERR_STATE, "Invalid State"); |
| |
| if ( StreamID != 1 ) |
| { |
| return M4ERR_BAD_STREAM_ID; |
| } |
| |
| /* Read the frame header byte */ |
| size = pStreamContext->m_maxAuSize; |
| pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile, |
| (M4OSA_MemAddr8)pStreamContext->m_pdataAddress, &size); |
| if(size != pStreamContext->m_maxAuSize) |
| { |
| return M4WAR_NO_MORE_AU; |
| } |
| |
| frameHeader = ((M4OSA_MemAddr8)pStreamContext->m_pdataAddress)[0]; |
| |
| frameType = ( frameHeader & 0x78 ) >> 3 ; |
| |
| if (( pStreamContext->m_streamType == M4SYS_kAMR ) && |
| ( frameType > 11 ) && ( frameType != 15 )) |
| { |
| return (M4OSA_ERR)M4ERR_AMR_INVALID_FRAME_TYPE; |
| } |
| |
| if (( pStreamContext->m_streamType == M4SYS_kAMR_WB ) && |
| ( frameType > 9 ) && ( frameType != 15 )) |
| { |
| return (M4OSA_ERR)M4ERR_AMR_INVALID_FRAME_TYPE; |
| } |
| |
| /* Get the frame size */ |
| if(frameType == 15) |
| { |
| auSize = 1; |
| } |
| else |
| { |
| auSize = M4AMRR_getAuSize(frameType, pStreamContext->m_streamType); |
| } |
| |
| size -= auSize ; |
| if(size != 0) |
| { |
| filePos = -((M4OSA_FilePosition)size); |
| pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, |
| M4OSA_kFileSeekCurrent, &filePos); |
| } |
| |
| pAu->size = auSize ; |
| |
| /* even when frameType == 15 (no data frame), ARM core decoder outputs full PCM buffer */ |
| /*if(frameType == 15 ) |
| { |
| pAu->CTS += 0; |
| }*/ |
| /*else*/ |
| { |
| pAu->CTS += M4AMRR_FRAME_LENGTH ; |
| } |
| |
| |
| pAu->DTS = pAu->CTS ; |
| pAu->attribute = M4SYS_kFragAttrOk; |
| |
| pAu->stream = pStreamContext->m_pStreamHandler; |
| pAu->dataAddress = pStreamContext->m_pdataAddress ; |
| |
| if(frameHeader & 0x80) |
| { |
| return M4WAR_NO_MORE_AU; |
| } |
| |
| /* Change the state to implement NextAu->freeAu->NextAu FSM */ |
| pStreamContext->m_status = M4AMRR_kReading_nextAU ; |
| |
| return M4NO_ERROR ; |
| } |
| |
| /*********************************************************/ |
| M4OSA_ERR M4AMRR_freeAU(M4OSA_Context Context, M4SYS_StreamID StreamID, M4SYS_AccessUnit* pAu) |
| /*********************************************************/ |
| { |
| M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context; |
| M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL"); |
| M4OSA_DEBUG_IF2((M4OSA_NULL == pAu),M4ERR_PARAMETER,"Access Unit . M4OSA_NULL"); |
| M4OSA_DEBUG_IF2((pStreamContext->m_contextId != M4AMRR_CONTEXTID),M4ERR_BAD_CONTEXT, |
| "Bad Context"); |
| M4OSA_DEBUG_IF1(( pStreamContext->m_status != M4AMRR_kReading_nextAU), M4ERR_STATE, |
| "Invalid State"); |
| |
| if (( StreamID != 1 ) && ( StreamID != 0)) |
| { |
| return M4ERR_BAD_STREAM_ID; |
| } |
| |
| /* Change the state to Reading so as to allow access to next AU */ |
| pStreamContext->m_status = M4AMRR_kReading ; |
| |
| return M4NO_ERROR ; |
| } |
| |
| /*********************************************************/ |
| M4OSA_ERR M4AMRR_seek(M4OSA_Context Context, M4SYS_StreamID* pStreamID, M4OSA_Time time, |
| M4SYS_SeekAccessMode seekMode, M4OSA_Time* pObtainCTS) |
| /*********************************************************/ |
| { |
| M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context; |
| M4OSA_UInt32 count, prevAU, nextAU ; |
| M4OSA_UInt32 size ; |
| M4OSA_UInt32 auSize ; |
| M4OSA_UInt32 position, partSeekTime; |
| M4OSA_UInt32 auCount = 0, skipAuCount = 0 ; |
| M4OSA_Char frameHeader ; |
| M4OSA_Char frameType ; |
| M4OSA_FilePosition filePos; |
| M4OSA_Double time_double; |
| |
| /*Make explicit time cast, but take care that timescale is not used !!!*/ |
| M4OSA_TIME_TO_MS(time_double, time, 1000); |
| |
| *pObtainCTS = 0; |
| |
| M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL"); |
| M4OSA_DEBUG_IF2((pStreamContext->m_contextId != M4AMRR_CONTEXTID),M4ERR_BAD_CONTEXT, |
| "Bad Context"); |
| M4OSA_DEBUG_IF1(( pStreamContext->m_status != M4AMRR_kReading) && \ |
| ( pStreamContext->m_status != M4AMRR_kOpened), M4ERR_STATE, "Invalid State"); |
| M4OSA_DEBUG_IF1((time_double < 0),M4ERR_PARAMETER,"negative time"); |
| |
| /* Coming to seek for the first time, need to build the seekIndex Table */ |
| if(M4OSA_NULL == pStreamContext->m_pSeekIndex) |
| { |
| M4OSA_Double duration_double; |
| |
| count = 0 ; |
| pStreamContext->m_pSeekIndex = |
| (M4OSA_UInt32*)M4OSA_32bitAlignedMalloc(M4AMRR_NUM_SEEK_ENTRIES * sizeof(M4OSA_UInt32), |
| M4AMR_READER, (M4OSA_Char *)("pStreamContext->m_pSeekIndex")); |
| |
| if(M4OSA_NULL == pStreamContext->m_pSeekIndex) |
| { |
| M4OSA_DEBUG_IF3((M4OSA_NULL == pStreamContext->m_pSeekIndex),M4ERR_ALLOC, |
| "Mem Alloc Failed - SeekIndex"); |
| return M4ERR_ALLOC ; |
| } |
| |
| /* point to the first AU */ |
| if( pStreamContext->m_streamType == M4SYS_kAMR ) |
| { |
| filePos = 6; |
| } |
| else /*if ( pStreamContext->m_streamType == M4SYS_kAMR_WB )*/ |
| { |
| filePos = 9; |
| } |
| |
| pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, |
| M4OSA_kFileSeekBeginning, &filePos); |
| |
| /* Set the postion to begining of first AU */ |
| position = (pStreamContext->m_streamType != M4SYS_kAMR)?9:6; |
| |
| /*Make explicit time cast, but take care that timescale is not used !!!*/ |
| M4OSA_TIME_TO_MS(duration_double, pStreamContext->m_pStreamHandler->duration, 1000); |
| |
| /* Calculate the seek Interval duration based on total dutation */ |
| /* Interval = (duration / ENTRIES) in multiples of AU frame length */ |
| pStreamContext->m_seekInterval = |
| (M4OSA_UInt32)(duration_double / M4AMRR_NUM_SEEK_ENTRIES) ; |
| pStreamContext->m_seekInterval /= M4AMRR_FRAME_LENGTH ; |
| pStreamContext->m_seekInterval *= M4AMRR_FRAME_LENGTH ; |
| skipAuCount = pStreamContext->m_seekInterval / M4AMRR_FRAME_LENGTH ; |
| |
| pStreamContext->m_pSeekIndex[count++]=position; |
| while(count < M4AMRR_NUM_SEEK_ENTRIES ) |
| { |
| size = 1; |
| pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile, |
| (M4OSA_MemAddr8)&frameHeader, &size); |
| if ( size == 0) |
| { |
| break ; |
| } |
| frameType = (frameHeader & 0x78) >> 3 ; |
| if(frameType != 15) |
| { |
| /**< bugfix Ronan Cousyn 05/04/2006: In the core reader AMR, the |
| * function M4AMRR_seek doesn't check the frameType */ |
| if (( pStreamContext->m_streamType == M4SYS_kAMR ) && ( frameType > 10 )) |
| { |
| return M4ERR_AMR_INVALID_FRAME_TYPE; |
| } |
| if (( pStreamContext->m_streamType == M4SYS_kAMR_WB ) && ( frameType > 9 )) |
| { |
| return M4ERR_AMR_INVALID_FRAME_TYPE; |
| } |
| auSize = M4AMRR_getAuSize(frameType, pStreamContext->m_streamType); |
| position += auSize ; |
| filePos = auSize-1; |
| pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, |
| M4OSA_kFileSeekCurrent, &filePos); |
| auCount++; |
| } |
| else |
| { |
| position ++; |
| } |
| /* Skip the number of AU's as per interval and store in the Index table */ |
| if ( (skipAuCount != 0) && !(auCount % skipAuCount)) |
| { |
| pStreamContext->m_pSeekIndex[count++] = position; |
| } |
| } |
| }/* End of Building the seek table */ |
| |
| /* Use the seek table to seek the required time in the stream */ |
| |
| /* If we are seeking the begining of the file point to first AU */ |
| if ( seekMode == M4SYS_kBeginning ) |
| { |
| if( pStreamContext->m_streamType == M4SYS_kAMR ) |
| { |
| filePos = 6; |
| } |
| else /*if ( pStreamContext->m_streamType == M4SYS_kAMR_WB )*/ |
| { |
| filePos = 9; |
| } |
| pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, |
| M4OSA_kFileSeekBeginning, &filePos ); |
| return M4NO_ERROR ; |
| } |
| |
| /* Get the Nearest Second */ |
| if (0 != pStreamContext->m_seekInterval) |
| { |
| position = (M4OSA_UInt32)(time_double / pStreamContext->m_seekInterval); |
| } |
| else |
| { |
| /*avoid division by 0*/ |
| position = 0; |
| } |
| |
| /* We have only 40 seek Index. */ |
| position=(position >= M4AMRR_NUM_SEEK_ENTRIES)?M4AMRR_NUM_SEEK_ENTRIES-1:position; |
| |
| /* SeekIndex will point to nearest Au, we need to search for the |
| required time form that position */ |
| partSeekTime = (M4OSA_UInt32)time_double - position * pStreamContext->m_seekInterval; |
| |
| position = pStreamContext->m_pSeekIndex[position]; |
| |
| if(!position) |
| { |
| return M4WAR_INVALID_TIME ; |
| } |
| |
| /* point the file pointer to nearest AU */ |
| filePos = position; |
| pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, M4OSA_kFileSeekBeginning, |
| &filePos ); |
| |
| if ( partSeekTime == 0) |
| { |
| *pObtainCTS = time; |
| return M4NO_ERROR; |
| } |
| |
| *pObtainCTS = (M4OSA_Time)(time_double - (M4OSA_Double)partSeekTime); |
| |
| switch(seekMode) |
| { |
| /* Get the AU before the target time */ |
| case M4SYS_kPreviousRAP: |
| case M4SYS_kNoRAPprevious: |
| position = partSeekTime / M4AMRR_FRAME_LENGTH ; |
| if ( !(partSeekTime % M4AMRR_FRAME_LENGTH) ) |
| { |
| position -- ; |
| } |
| break; |
| /* Get the Closest AU following the target time */ |
| case M4SYS_kNextRAP: |
| case M4SYS_kNoRAPnext: |
| position = (partSeekTime + M4AMRR_FRAME_LENGTH )/ M4AMRR_FRAME_LENGTH ; |
| break; |
| /* Get the closest AU to target time */ |
| case M4SYS_kClosestRAP: |
| case M4SYS_kNoRAPclosest: |
| prevAU = partSeekTime-(partSeekTime/M4AMRR_FRAME_LENGTH)*M4AMRR_FRAME_LENGTH; |
| nextAU = |
| ((partSeekTime+M4AMRR_FRAME_LENGTH)/M4AMRR_FRAME_LENGTH)*M4AMRR_FRAME_LENGTH -\ |
| partSeekTime ; |
| if(prevAU < nextAU) |
| { |
| position = partSeekTime / M4AMRR_FRAME_LENGTH ; |
| } |
| else |
| { |
| position = (partSeekTime + M4AMRR_FRAME_LENGTH )/ M4AMRR_FRAME_LENGTH ; |
| } |
| break; |
| case M4SYS_kBeginning: |
| break; |
| } |
| |
| count = 0 ; |
| /* Skip the Access unit in the stream to skip the part seek time, |
| to reach the required target time */ |
| while(count < position ) |
| { |
| size = 1; |
| pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile, |
| (M4OSA_MemAddr8)&frameHeader, &size); |
| if ( size == 0) |
| { |
| /* If the target time is invalid, point to begining and return */ |
| *pObtainCTS = 0; |
| filePos = pStreamContext->m_pSeekIndex[0]; |
| pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, |
| M4OSA_kFileSeekBeginning, &filePos); |
| return M4WAR_INVALID_TIME ; |
| } |
| *pObtainCTS += M4AMRR_FRAME_LENGTH; /*Should use M4OSA_INT64_ADD !!*/ |
| count++; |
| frameType = (frameHeader & 0x78) >> 3 ; |
| if(frameType == 15) |
| { |
| auSize = 1 ; |
| } |
| else |
| { |
| auSize = M4AMRR_getAuSize(frameType, pStreamContext->m_streamType); |
| } |
| |
| filePos = auSize-1; |
| pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, |
| M4OSA_kFileSeekCurrent, &filePos); |
| } |
| |
| return M4NO_ERROR; |
| } |
| |
| /*********************************************************/ |
| M4OSA_ERR M4AMRR_closeRead(M4OSA_Context Context) |
| /*********************************************************/ |
| { |
| M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context; |
| M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL"); |
| |
| /* Close the AMR stream */ |
| pStreamContext->m_pOsaFilePtrFct->closeRead(pStreamContext->m_pAMRFile); |
| |
| pStreamContext->m_status=M4AMRR_kClosed ; |
| |
| /* Check if AU data Address is allocated memory and free it */ |
| if(M4OSA_NULL != pStreamContext->m_pdataAddress) |
| { |
| free(pStreamContext->m_pdataAddress); |
| } |
| |
| /* Check if the stream handler is allocated memory */ |
| if(M4OSA_NULL != pStreamContext->m_pStreamHandler) |
| { |
| free(pStreamContext->m_pStreamHandler); |
| } |
| |
| /* Seek table is created only when seek is used, so check if memory is allocated */ |
| if(M4OSA_NULL != pStreamContext->m_pSeekIndex) |
| { |
| free(pStreamContext->m_pSeekIndex); |
| } |
| |
| /* Free the context */ |
| free(pStreamContext); |
| |
| return M4NO_ERROR ; |
| } |
| |
| /*********************************************************/ |
| M4OSA_ERR M4AMRR_getState(M4OSA_Context Context, M4AMRR_State* pState, M4SYS_StreamID streamId) |
| /*********************************************************/ |
| { |
| M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context; |
| M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL"); |
| M4OSA_DEBUG_IF2((pStreamContext->m_contextId != M4AMRR_CONTEXTID),M4ERR_BAD_CONTEXT, |
| "Bad Context"); |
| |
| if (( streamId != 1 ) && ( streamId != 0)) |
| { |
| return M4ERR_BAD_STREAM_ID; |
| } |
| |
| *pState = pStreamContext->m_status ; |
| |
| return M4NO_ERROR ; |
| } |
| |
| |
| /*********************************************************/ |
| M4OSA_ERR M4AMRR_getVersion (M4_VersionInfo *pVersion) |
| /*********************************************************/ |
| { |
| M4OSA_TRACE1_1("M4AMRR_getVersion called with pVersion: 0x%x\n", pVersion); |
| M4OSA_DEBUG_IF1(((M4OSA_UInt32) pVersion == 0),M4ERR_PARAMETER, |
| "pVersion is NULL in M4AMRR_getVersion"); |
| |
| pVersion->m_major = M4AMRR_VERSION_MAJOR; |
| pVersion->m_minor = M4AMRR_VERSION_MINOR; |
| pVersion->m_revision = M4AMRR_VERSION_REVISION; |
| |
| return M4NO_ERROR; |
| } |
| |
| /*********************************************************/ |
| M4OSA_ERR M4AMRR_getmaxAUsize(M4OSA_Context Context, M4OSA_UInt32 *pMaxAuSize) |
| /*********************************************************/ |
| { |
| M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context; |
| |
| /** |
| * Check input parameters */ |
| M4OSA_DEBUG_IF1((M4OSA_NULL == Context), M4ERR_PARAMETER, |
| "M4AMRR_getmaxAUsize: Context is M4OSA_NULL"); |
| M4OSA_DEBUG_IF1((M4OSA_NULL == pMaxAuSize),M4ERR_PARAMETER, |
| "M4AMRR_getmaxAUsize: pMaxAuSize is M4OSA_NULL"); |
| |
| *pMaxAuSize = pStreamContext->m_maxAuSize; |
| |
| return M4NO_ERROR; |
| } |
| |