blob: 630f9dc3af6ca4dea244a5b5e491c390cdc2f750 [file] [log] [blame]
/*
* 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;
}