M4AMRR_CoreReader.c revision 7c9d8018755adf1857571125ba1b3598c96ea506
1/*
2 * Copyright (C) 2004-2011 NXP Software
3 * Copyright (C) 2011 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/**
19 ******************************************************************************
20 * @file        M4AMRR_CoreReader.c
21 * @brief       Implementation of AMR parser
22 * @note        This file contains the API Implementation for
23 *              AMR Parser.
24 ******************************************************************************
25*/
26#include "M4AMRR_CoreReader.h"
27#include "M4OSA_Debug.h"
28#include "M4OSA_CoreID.h"
29
30/**
31 ******************************************************************************
32 * Maximum bitrate per amr type
33 ******************************************************************************
34*/
35#define M4AMRR_NB_MAX_BIT_RATE    12200
36#define M4AMRR_WB_MAX_BIT_RATE    23850
37
38/**
39 ******************************************************************************
40 * AMR reader context ID
41 ******************************************************************************
42*/
43#define M4AMRR_CONTEXTID    0x414d5252
44
45/**
46 ******************************************************************************
47 * An AMR frame is 20ms
48 ******************************************************************************
49*/
50#define M4AMRR_FRAME_LENGTH     20
51
52/**
53 ******************************************************************************
54 * For the seek, the file is splitted in 40 segments for faster search
55 ******************************************************************************
56*/
57#define    M4AMRR_NUM_SEEK_ENTRIES 40
58
59#define M4AMRR_NB_SAMPLE_FREQUENCY 8000        /**< Narrow band sampling rate */
60#define M4AMRR_WB_SAMPLE_FREQUENCY 16000    /**< Wide band sampling rate */
61
62/**
63 ******************************************************************************
64 * AMR reader version numbers
65 ******************************************************************************
66*/
67/* CHANGE_VERSION_HERE */
68#define M4AMRR_VERSION_MAJOR 1
69#define M4AMRR_VERSION_MINOR 11
70#define M4AMRR_VERSION_REVISION 3
71
72/**
73 ******************************************************************************
74 * structure    M4_AMRR_Context
75 * @brief        Internal AMR reader context structure
76 ******************************************************************************
77*/
78typedef struct
79{
80    M4OSA_UInt32             m_contextId ;      /* Fixed Id. to check for valid Context*/
81    M4OSA_FileReadPointer*   m_pOsaFilePtrFct;  /* File function pointer */
82    M4SYS_StreamDescription* m_pStreamHandler;  /* Stream Description */
83    M4OSA_UInt32*            m_pSeekIndex;      /* Seek Index Table */
84    M4OSA_UInt32             m_seekInterval;    /* Stores the seek Interval stored in the Index */
85    M4OSA_UInt32             m_maxAuSize;       /* Stores the max Au Size */
86    M4OSA_MemAddr32          m_pdataAddress;    /* Pointer to store AU data */
87    M4SYS_StreamType         m_streamType;      /* Stores the stream type AMR NB or WB */
88    M4OSA_Context            m_pAMRFile;        /* Data storage */
89    M4AMRR_State             m_status;          /* AMR Reader Status */
90    M4OSA_Int32              m_structSize;      /* size of structure*/
91} M4_AMRR_Context;
92
93/**
94 ******************************************************************************
95 * Parser internal functions, not usable from outside the reader context
96 ******************************************************************************
97*/
98M4OSA_UInt32    M4AMRR_getAuSize(M4OSA_UInt32 frameType,  M4SYS_StreamType streamType);
99M4OSA_UInt32    M4AMRR_getBitrate(M4OSA_UInt32 frameType,  M4SYS_StreamType streamType);
100
101/**
102 ******************************************************************************
103 * M4OSA_UInt32    M4AMRR_getAuSize(M4OSA_UInt32 frameType,  M4SYS_StreamType streamType)
104 * @brief    Internal function to the AMR Parser, returns the AU size of the Frame
105 * @note     This function takes the stream type and the frametype and returns the
106 *           frame lenght
107 * @param    frameType(IN)    : AMR frame type
108 * @param    streamType(IN)    : AMR stream type NB or WB
109 * @returns  The frame size based on the frame type.
110 ******************************************************************************
111 */
112M4OSA_UInt32    M4AMRR_getAuSize(M4OSA_UInt32 frameType,  M4SYS_StreamType streamType)
113{
114    const M4OSA_UInt32    M4AMRR_NB_AUSIZE[]={13,14,16,18,20,21,27,32,6,6,6};
115    const M4OSA_UInt32    M4AMRR_WB_AUSIZE[]={18,24,33,37,41,47,51,59,61,6};
116
117    if ( streamType == M4SYS_kAMR )
118    {
119            return M4AMRR_NB_AUSIZE[frameType];
120    }
121    else /* M4SYS_kAMR_WB */
122    {
123            return M4AMRR_WB_AUSIZE[frameType];
124    }
125}
126
127/**
128 ******************************************************************************
129 * M4OSA_UInt32    M4AMRR_getBitrate(M4OSA_UInt32 frameType,  M4SYS_StreamType streamType)
130 * @brief    Internal function to the AMR Parser, returns the Bit rate of the Frame
131 * @note     This function takes the stream type and the frametype and returns the
132 *           bit rate for the given frame.
133 * @param    frameType(IN)    : AMR frame type
134 * @param    streamType(IN)    : AMR stream type NB or WB
135 * @returns  The frame's bit rate based on the frame type.
136 ******************************************************************************
137 */
138M4OSA_UInt32    M4AMRR_getBitrate(M4OSA_UInt32 frameType,  M4SYS_StreamType streamType)
139{
140    const M4OSA_UInt32    M4AMRR_NB_BITRATE[]=
141        {4750,5150,5900,6700,7400,7950,10200,12200,12200,12200,12200};
142    const M4OSA_UInt32    M4AMRR_WB_BITRATE[]=
143        {6600,8850,12650,14250,15850,18250,19850,23050,23850,12200};
144
145    if ( streamType == M4SYS_kAMR )
146    {
147            return M4AMRR_NB_BITRATE[frameType];
148    }
149    else /* M4SYS_kAMR_WB */
150    {
151            return M4AMRR_WB_BITRATE[frameType];
152    }
153}
154
155/*********************************************************/
156M4OSA_ERR M4AMRR_openRead(M4OSA_Context* pContext, M4OSA_Void* pFileDescriptor,
157                        M4OSA_FileReadPointer* pFileFunction)
158/*********************************************************/
159{
160    M4_AMRR_Context*    pStreamContext;
161    M4OSA_FilePosition  filePos;
162
163    M4OSA_ERR err = M4ERR_FILE_NOT_FOUND ;
164    M4OSA_UInt32 size ;
165    M4OSA_UInt32 data ;
166    M4OSA_Char *M4_Token;
167    M4OSA_UInt32 *tokenPtr;
168
169    /* Header for AMR NB */
170    M4OSA_UInt32 M4_AMR_1       = 0x4d412123;
171    M4OSA_UInt32 M4_AMR_NB_2    = 0x00000a52;
172
173    /* Header for AMR WB */
174    M4OSA_UInt32 M4_AMR_WB_2    = 0x42572d52;
175    M4OSA_UInt32 M4_AMR_WB_3    = 0x0000000a;
176    *pContext = M4OSA_NULL ;
177
178    M4OSA_DEBUG_IF2((M4OSA_NULL == pContext),M4ERR_PARAMETER,"Context M4OSA_NULL");
179    M4OSA_DEBUG_IF2((M4OSA_NULL == pFileDescriptor),M4ERR_PARAMETER,"File Desc. M4OSA_NULL");
180
181    M4_Token = (M4OSA_Char*)M4OSA_malloc(sizeof(M4OSA_MemAddr32)*3, M4AMR_READER,
182                 (M4OSA_Char *)("M4_Token"));
183    if(M4OSA_NULL == M4_Token)
184    {
185        M4OSA_DEBUG_IF3((M4OSA_NULL == M4_Token),M4ERR_ALLOC,"Mem Alloc failed - M4_Token");
186        return M4ERR_ALLOC ;
187    }
188
189    pStreamContext= (M4_AMRR_Context*)M4OSA_malloc(sizeof(M4_AMRR_Context), M4AMR_READER,
190                     (M4OSA_Char *)("pStreamContext"));
191    if(M4OSA_NULL == pStreamContext)
192    {
193        M4OSA_free((M4OSA_MemAddr32)M4_Token);
194        *pContext = M4OSA_NULL ;
195        return M4ERR_ALLOC ;
196    }
197
198    /* Initialize the context */
199    pStreamContext->m_contextId = M4AMRR_CONTEXTID;
200    pStreamContext->m_structSize=sizeof(M4_AMRR_Context);
201    pStreamContext->m_pOsaFilePtrFct=pFileFunction ;
202    pStreamContext->m_pStreamHandler = M4OSA_NULL ;
203    pStreamContext->m_pAMRFile = M4OSA_NULL ;
204    pStreamContext->m_status = M4AMRR_kOpening ;
205    pStreamContext->m_pSeekIndex = M4OSA_NULL ;
206    pStreamContext->m_seekInterval = 0;
207    pStreamContext->m_maxAuSize = 0 ;
208    pStreamContext->m_pdataAddress = M4OSA_NULL;
209    err=pStreamContext->m_pOsaFilePtrFct->openRead(&pStreamContext->m_pAMRFile,
210        (M4OSA_Char*)pFileDescriptor,M4OSA_kFileRead );
211    if ( err != M4NO_ERROR )
212    {
213        /* M4OSA_DEBUG_IF3((err != M4NO_ERROR),err,"File open failed"); */
214        M4OSA_free((M4OSA_MemAddr32)pStreamContext);
215        M4OSA_free((M4OSA_MemAddr32)M4_Token);
216        *pContext = M4OSA_NULL ;
217        return err ;
218    }
219
220    pStreamContext->m_status = M4AMRR_kOpening ;
221
222    size = 6;
223    pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile,
224                (M4OSA_MemAddr8)M4_Token, &size);
225    if(size != 6)
226    {
227        goto cleanup;
228    }
229
230    tokenPtr = (M4OSA_UInt32*)M4_Token ;
231    /* Check for the first 4 bytes of the header common to WB and NB*/
232    if (*tokenPtr != M4_AMR_1)
233    {
234        goto cleanup;
235    }
236
237    tokenPtr++;
238    data = *tokenPtr & 0x0000FFFF ;
239    /* Check if the next part is Narrow band header */
240    if (data!= M4_AMR_NB_2)
241    {
242        /* Stream is AMR Wide Band */
243        filePos = 4;
244        pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile,
245             M4OSA_kFileSeekBeginning, &filePos);
246        size = 5;
247        pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile,
248             (M4OSA_MemAddr8)M4_Token, &size);
249        if(size != 5)
250            goto cleanup;
251        tokenPtr=(M4OSA_UInt32*)M4_Token;
252        /* Check for the Wide band hader */
253        if(*tokenPtr!= M4_AMR_WB_2)
254            goto cleanup;
255        tokenPtr++;
256        data = *tokenPtr & 0x000000FF ;
257        if(data!= M4_AMR_WB_3)
258            goto cleanup;
259        pStreamContext->m_streamType = M4SYS_kAMR_WB ;
260    }
261    else
262    {
263        /* Stream is a Narrow band stream */
264        pStreamContext->m_streamType = M4SYS_kAMR ;
265    }
266    /*  No Profile level defined */
267    pStreamContext->m_status = M4AMRR_kOpened;
268
269    M4OSA_free((M4OSA_MemAddr32)M4_Token);
270    *pContext = pStreamContext ;
271    return M4NO_ERROR;
272
273cleanup:
274
275    if(M4OSA_NULL != pStreamContext->m_pAMRFile)
276    {
277        pStreamContext->m_pOsaFilePtrFct->closeRead(pStreamContext->m_pAMRFile);
278    }
279
280    M4OSA_free((M4OSA_MemAddr32)M4_Token);
281    M4OSA_free((M4OSA_MemAddr32)pStreamContext);
282
283    *pContext = M4OSA_NULL ;
284
285    return (M4OSA_ERR)M4ERR_AMR_NOT_COMPLIANT;
286}
287
288
289/*********************************************************/
290M4OSA_ERR M4AMRR_getNextStream(M4OSA_Context Context, M4SYS_StreamDescription* pStreamDesc )
291/*********************************************************/
292{
293    M4_AMRR_Context*    pStreamContext=(M4_AMRR_Context*)Context;
294    M4OSA_Char            frameHeader, frameType ;
295    M4OSA_UInt32        size, auCount=0;
296    M4OSA_FilePosition  filePos;
297
298    M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL");
299    M4OSA_DEBUG_IF2((M4OSA_NULL == pStreamDesc),M4ERR_PARAMETER,"Stream Desc. M4OSA_NULL");
300    M4OSA_DEBUG_IF2((pStreamContext->m_contextId != M4AMRR_CONTEXTID),M4ERR_BAD_CONTEXT,
301         "Bad Context");
302    M4OSA_DEBUG_IF1(( pStreamContext->m_status != M4AMRR_kOpened), M4ERR_STATE, "Invalid State");
303
304    if (M4OSA_NULL != pStreamContext->m_pStreamHandler)
305    {
306        return M4WAR_NO_MORE_STREAM ;
307    }
308
309    size = 1;
310    pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile,
311         (M4OSA_MemAddr8)&frameHeader, &size);
312
313    /* XFFF FXXX -> F is the Frame type */
314    frameType = ( frameHeader & 0x78 ) >> 3 ;
315
316    if ( frameType == 15 )
317    {
318        return M4WAR_NO_DATA_YET ;
319    }
320
321    if (( pStreamContext->m_streamType == M4SYS_kAMR ) && ( frameType > 11 ))
322    {
323        return (M4OSA_ERR)M4ERR_AMR_INVALID_FRAME_TYPE;
324    }
325
326    if (( pStreamContext->m_streamType == M4SYS_kAMR_WB ) && ( frameType > 9 ))
327    {
328        return (M4OSA_ERR)M4ERR_AMR_INVALID_FRAME_TYPE;
329    }
330
331    /* Average bit rate is assigned the bitrate of the first frame */
332    pStreamDesc->averageBitrate = M4AMRR_getBitrate(frameType,pStreamContext->m_streamType);
333
334    filePos = -1;
335    pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, M4OSA_kFileSeekCurrent,
336         &filePos);
337
338    /* Initialize pStreamDesc */
339    pStreamDesc->profileLevel = 0xFF ;
340    pStreamDesc->decoderSpecificInfoSize = 0 ;
341    pStreamDesc->decoderSpecificInfo = M4OSA_NULL ;
342    pStreamDesc->maxBitrate = (pStreamContext->m_streamType ==
343        M4SYS_kAMR )?M4AMRR_NB_MAX_BIT_RATE:M4AMRR_WB_MAX_BIT_RATE;
344    pStreamDesc->profileLevel = 0xFF ;
345    pStreamDesc->streamID = 1;
346    pStreamDesc->streamType = pStreamContext->m_streamType;
347
348    /* Timescale equals Sampling Frequency: NB-8000 Hz, WB-16000 Hz */
349    pStreamDesc->timeScale = (pStreamContext->m_streamType == M4SYS_kAMR )?8000:16000;
350    M4OSA_TIME_SET_UNKNOWN(pStreamDesc->duration);
351
352    pStreamContext->m_pStreamHandler =
353         (M4SYS_StreamDescription*)M4OSA_malloc(sizeof(M4SYS_StreamDescription),
354             M4AMR_READER, (M4OSA_Char *)("pStreamContext->m_pStreamHandler"));
355    if(M4OSA_NULL == pStreamContext->m_pStreamHandler)
356    {
357        return M4ERR_ALLOC;
358    }
359
360    /* Copy the Stream Desc. into the Context */
361    pStreamContext->m_pStreamHandler->averageBitrate = pStreamDesc->averageBitrate;
362    pStreamContext->m_pStreamHandler->decoderSpecificInfo = M4OSA_NULL ;
363    pStreamContext->m_pStreamHandler->decoderSpecificInfoSize = 0 ;
364    M4OSA_TIME_SET_UNKNOWN(pStreamContext->m_pStreamHandler->duration);
365    pStreamContext->m_pStreamHandler->profileLevel = 0xFF ;
366    pStreamContext->m_pStreamHandler->streamID = 1;
367    pStreamContext->m_pStreamHandler->streamType = pStreamDesc->streamType ;
368    pStreamContext->m_pStreamHandler->timeScale = pStreamDesc->timeScale ;
369
370    /* Count the number of Access Unit in the File to get the */
371    /* duration of the stream = 20 ms * number of access unit */
372    while(1)
373    {
374        size = 1;
375        pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile,
376             (M4OSA_MemAddr8)&frameHeader, &size);
377        if ( size == 0)
378            break ;
379        frameType = (frameHeader & 0x78) >> 3 ;
380        /* Get the frame size and skip so many bytes */
381        if(frameType != 15){
382            /* GLA 20050628 when frametype is >10 we read over a table */
383            if(frameType > 10)
384                continue ;
385
386            size = M4AMRR_getAuSize(frameType, pStreamContext->m_streamType);
387            if(size > pStreamContext->m_maxAuSize )
388            {
389                pStreamContext->m_maxAuSize = size ;
390            }
391            filePos = size-1;
392            pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile,
393                 M4OSA_kFileSeekCurrent, &filePos);
394            auCount++;
395        }
396    }
397
398    /* Each Frame is 20 m Sec. */
399    pStreamContext->m_pStreamHandler->duration = auCount * M4AMRR_FRAME_LENGTH ;
400    pStreamDesc->duration = pStreamContext->m_pStreamHandler->duration ;
401
402    /* Put the file pointer back at the first Access unit */
403    if( pStreamContext->m_streamType == M4SYS_kAMR )
404    {
405        filePos = 6;
406        pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile,
407             M4OSA_kFileSeekBeginning, &filePos);
408    }
409    if ( pStreamContext->m_streamType == M4SYS_kAMR_WB )
410    {
411        filePos = 9;
412        pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile,
413             M4OSA_kFileSeekBeginning, &filePos);
414    }
415    return M4NO_ERROR ;
416}
417
418/*********************************************************/
419M4OSA_ERR M4AMRR_startReading(M4OSA_Context Context, M4SYS_StreamID* pStreamIDs )
420/*********************************************************/
421{
422    M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context;
423    M4OSA_Int32 size = 0 ;
424
425    M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL");
426    M4OSA_DEBUG_IF2((M4OSA_NULL == pStreamIDs),M4ERR_PARAMETER,"Stream Ids. M4OSA_NULL");
427    M4OSA_DEBUG_IF2((pStreamContext->m_contextId != M4AMRR_CONTEXTID),M4ERR_BAD_CONTEXT,
428         "Bad Context");
429    M4OSA_DEBUG_IF1(( pStreamContext->m_status != M4AMRR_kOpened), M4ERR_STATE, "Invalid State");
430
431    while( pStreamIDs[size] != 0 )
432    {
433        if( pStreamIDs[size++] != 1 )
434        {
435            return M4ERR_BAD_STREAM_ID ;
436        }
437    }
438
439    /* Allocate memory for data Address for use in NextAU() */
440    if(M4OSA_NULL == pStreamContext->m_pdataAddress)
441    {
442        size = pStreamContext->m_maxAuSize ;
443        /* dataAddress is owned by Parser, application should not delete or free it */
444        pStreamContext->m_pdataAddress =(M4OSA_MemAddr32)M4OSA_malloc(size + (4 - size % 4),
445            M4AMR_READER, (M4OSA_Char *)("pStreamContext->m_pdataAddress"));
446        if(M4OSA_NULL == pStreamContext->m_pdataAddress)
447        {
448                M4OSA_DEBUG_IF3((M4OSA_NULL == pStreamContext->m_pdataAddress),M4ERR_ALLOC,
449                    "Mem Alloc failed - dataAddress");
450                return M4ERR_ALLOC;
451        }
452    }
453
454    /* Set the state of context to Reading */
455    pStreamContext->m_status = M4AMRR_kReading ;
456
457    return M4NO_ERROR ;
458}
459
460
461/*********************************************************/
462M4OSA_ERR M4AMRR_nextAU(M4OSA_Context Context, M4SYS_StreamID StreamID, M4SYS_AccessUnit* pAu)
463/*********************************************************/
464{
465    M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context;
466    M4OSA_Char        frameHeader ;
467    M4OSA_Char        frameType ;
468    M4OSA_Int32        auSize;
469    M4OSA_UInt32    size ;
470    M4OSA_FilePosition  filePos;
471
472    M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL");
473    M4OSA_DEBUG_IF2((M4OSA_NULL == pAu),M4ERR_PARAMETER,"Access Unit . M4OSA_NULL");
474    M4OSA_DEBUG_IF2((pStreamContext->m_contextId != M4AMRR_CONTEXTID),M4ERR_BAD_CONTEXT,
475         "Bad Context");
476    M4OSA_DEBUG_IF1(( pStreamContext->m_status != M4AMRR_kReading), M4ERR_STATE, "Invalid State");
477
478    if ( StreamID != 1 )
479    {
480            return M4ERR_BAD_STREAM_ID;
481    }
482
483    /* Read the frame header byte */
484    size = pStreamContext->m_maxAuSize;
485    pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile,
486         (M4OSA_MemAddr8)pStreamContext->m_pdataAddress, &size);
487    if(size != pStreamContext->m_maxAuSize)
488    {
489        return M4WAR_NO_MORE_AU;
490    }
491
492    frameHeader = ((M4OSA_MemAddr8)pStreamContext->m_pdataAddress)[0];
493
494    frameType = ( frameHeader & 0x78 ) >> 3 ;
495
496    if (( pStreamContext->m_streamType == M4SYS_kAMR ) &&
497        ( frameType > 11 ) && ( frameType != 15 ))
498    {
499        return (M4OSA_ERR)M4ERR_AMR_INVALID_FRAME_TYPE;
500    }
501
502    if (( pStreamContext->m_streamType == M4SYS_kAMR_WB ) &&
503        ( frameType > 9 ) && ( frameType != 15 ))
504    {
505        return (M4OSA_ERR)M4ERR_AMR_INVALID_FRAME_TYPE;
506    }
507
508    /* Get the frame size */
509    if(frameType == 15)
510    {
511        auSize = 1;
512    }
513    else
514    {
515        auSize = M4AMRR_getAuSize(frameType, pStreamContext->m_streamType);
516    }
517
518    size -= auSize ;
519    if(size != 0)
520    {
521        filePos = -((M4OSA_FilePosition)size);
522        pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile,
523             M4OSA_kFileSeekCurrent, &filePos);
524    }
525
526    pAu->size = auSize ;
527
528    /* even when frameType == 15 (no data frame), ARM core decoder outputs full PCM buffer */
529    /*if(frameType == 15 )
530    {
531        pAu->CTS += 0;
532    }*/
533    /*else*/
534    {
535        pAu->CTS += M4AMRR_FRAME_LENGTH ;
536    }
537
538
539    pAu->DTS = pAu->CTS ;
540    pAu->attribute = M4SYS_kFragAttrOk;
541
542    pAu->stream = pStreamContext->m_pStreamHandler;
543    pAu->dataAddress = pStreamContext->m_pdataAddress ;
544
545    if(frameHeader & 0x80)
546    {
547        return M4WAR_NO_MORE_AU;
548    }
549
550    /* Change the state to implement NextAu->freeAu->NextAu FSM */
551    pStreamContext->m_status = M4AMRR_kReading_nextAU ;
552
553    return M4NO_ERROR ;
554}
555
556/*********************************************************/
557M4OSA_ERR M4AMRR_freeAU(M4OSA_Context Context, M4SYS_StreamID StreamID, M4SYS_AccessUnit* pAu)
558/*********************************************************/
559{
560    M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context;
561    M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL");
562    M4OSA_DEBUG_IF2((M4OSA_NULL == pAu),M4ERR_PARAMETER,"Access Unit . M4OSA_NULL");
563    M4OSA_DEBUG_IF2((pStreamContext->m_contextId != M4AMRR_CONTEXTID),M4ERR_BAD_CONTEXT,
564         "Bad Context");
565    M4OSA_DEBUG_IF1(( pStreamContext->m_status != M4AMRR_kReading_nextAU), M4ERR_STATE,
566         "Invalid State");
567
568    if (( StreamID != 1 ) && ( StreamID != 0))
569    {
570            return M4ERR_BAD_STREAM_ID;
571    }
572
573    /* Change the state to Reading so as to allow access to next AU */
574    pStreamContext->m_status = M4AMRR_kReading ;
575
576    return M4NO_ERROR ;
577}
578
579/*********************************************************/
580M4OSA_ERR M4AMRR_seek(M4OSA_Context Context, M4SYS_StreamID* pStreamID, M4OSA_Time time,
581                         M4SYS_SeekAccessMode seekMode, M4OSA_Time* pObtainCTS)
582/*********************************************************/
583{
584    M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context;
585    M4OSA_UInt32 count, prevAU, nextAU ;
586    M4OSA_UInt32 size ;
587    M4OSA_UInt32 auSize ;
588    M4OSA_UInt32 position, partSeekTime;
589    M4OSA_UInt32 auCount = 0, skipAuCount = 0 ;
590    M4OSA_Char    frameHeader ;
591    M4OSA_Char    frameType ;
592    M4OSA_FilePosition  filePos;
593    M4OSA_Double time_double;
594
595    /*Make explicit time cast, but take care that timescale is not used !!!*/
596    M4OSA_TIME_TO_MS(time_double, time, 1000);
597
598    M4OSA_INT64_FROM_INT32(*pObtainCTS, 0);
599
600    M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL");
601    M4OSA_DEBUG_IF2((pStreamContext->m_contextId != M4AMRR_CONTEXTID),M4ERR_BAD_CONTEXT,
602         "Bad Context");
603    M4OSA_DEBUG_IF1(( pStreamContext->m_status != M4AMRR_kReading) && \
604        ( pStreamContext->m_status != M4AMRR_kOpened), M4ERR_STATE, "Invalid State");
605    M4OSA_DEBUG_IF1((time_double < 0),M4ERR_PARAMETER,"negative time");
606
607    /* Coming to seek for the first time, need to build the seekIndex Table */
608    if(M4OSA_NULL == pStreamContext->m_pSeekIndex)
609    {
610        M4OSA_Double duration_double;
611
612        count = 0 ;
613        pStreamContext->m_pSeekIndex =
614             (M4OSA_UInt32*)M4OSA_malloc(M4AMRR_NUM_SEEK_ENTRIES * sizeof(M4OSA_UInt32),
615                 M4AMR_READER, (M4OSA_Char *)("pStreamContext->m_pSeekIndex"));
616
617        if(M4OSA_NULL == pStreamContext->m_pSeekIndex)
618        {
619            M4OSA_DEBUG_IF3((M4OSA_NULL == pStreamContext->m_pSeekIndex),M4ERR_ALLOC,
620                "Mem Alloc Failed - SeekIndex");
621            return M4ERR_ALLOC ;
622        }
623
624        /* point to the first AU */
625        if( pStreamContext->m_streamType == M4SYS_kAMR )
626        {
627            filePos = 6;
628        }
629        else /*if ( pStreamContext->m_streamType == M4SYS_kAMR_WB )*/
630        {
631            filePos = 9;
632        }
633
634        pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile,
635             M4OSA_kFileSeekBeginning, &filePos);
636
637        /* Set the postion to begining of first AU */
638        position = (pStreamContext->m_streamType != M4SYS_kAMR)?9:6;
639
640        /*Make explicit time cast, but take care that timescale is not used !!!*/
641        M4OSA_TIME_TO_MS(duration_double, pStreamContext->m_pStreamHandler->duration, 1000);
642
643        /* Calculate the seek Interval duration based on total dutation */
644        /* Interval = (duration / ENTRIES) in multiples of AU frame length */
645        pStreamContext->m_seekInterval =
646             (M4OSA_UInt32)(duration_double / M4AMRR_NUM_SEEK_ENTRIES) ;
647        pStreamContext->m_seekInterval /= M4AMRR_FRAME_LENGTH ;
648        pStreamContext->m_seekInterval *= M4AMRR_FRAME_LENGTH ;
649        skipAuCount = pStreamContext->m_seekInterval / M4AMRR_FRAME_LENGTH ;
650
651        pStreamContext->m_pSeekIndex[count++]=position;
652        while(count < M4AMRR_NUM_SEEK_ENTRIES )
653        {
654            size = 1;
655            pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile,
656                 (M4OSA_MemAddr8)&frameHeader, &size);
657            if ( size == 0)
658            {
659                break ;
660            }
661            frameType = (frameHeader & 0x78) >> 3 ;
662            if(frameType != 15)
663            {
664                /**< bugfix Ronan Cousyn 05/04/2006: In the core reader AMR, the
665                 * function M4AMRR_seek doesn't check the frameType */
666                if (( pStreamContext->m_streamType == M4SYS_kAMR ) && ( frameType > 10 ))
667                {
668                    return M4ERR_AMR_INVALID_FRAME_TYPE;
669                }
670                if (( pStreamContext->m_streamType == M4SYS_kAMR_WB ) && ( frameType > 9 ))
671                {
672                    return M4ERR_AMR_INVALID_FRAME_TYPE;
673                }
674                auSize = M4AMRR_getAuSize(frameType, pStreamContext->m_streamType);
675                position += auSize ;
676                filePos = auSize-1;
677                pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile,
678                     M4OSA_kFileSeekCurrent, &filePos);
679                auCount++;
680            }
681            else
682            {
683                position ++;
684            }
685            /* Skip the number of AU's as per interval and store in the Index table */
686            if ( (skipAuCount != 0) && !(auCount % skipAuCount))
687            {
688                pStreamContext->m_pSeekIndex[count++] = position;
689            }
690        }
691    }/* End of Building the seek table */
692
693    /* Use the seek table to seek the required time in the stream */
694
695    /* If we are seeking the begining of the file point to first AU */
696    if ( seekMode == M4SYS_kBeginning )
697    {
698        if( pStreamContext->m_streamType == M4SYS_kAMR )
699        {
700            filePos = 6;
701        }
702        else /*if ( pStreamContext->m_streamType == M4SYS_kAMR_WB )*/
703        {
704            filePos = 9;
705        }
706        pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile,
707             M4OSA_kFileSeekBeginning, &filePos );
708        return M4NO_ERROR ;
709    }
710
711    /* Get the Nearest Second */
712    if (0 != pStreamContext->m_seekInterval)
713    {
714        position = (M4OSA_UInt32)(time_double / pStreamContext->m_seekInterval);
715    }
716    else
717    {
718        /*avoid division by 0*/
719        position = 0;
720    }
721
722    /* We have only 40 seek Index. */
723    position=(position >= M4AMRR_NUM_SEEK_ENTRIES)?M4AMRR_NUM_SEEK_ENTRIES-1:position;
724
725    /* SeekIndex will point to nearest Au, we need to search for the
726    required time form that position */
727    partSeekTime = (M4OSA_UInt32)time_double - position * pStreamContext->m_seekInterval;
728
729    position = pStreamContext->m_pSeekIndex[position];
730
731    if(!position)
732    {
733        return M4WAR_INVALID_TIME ;
734    }
735
736    /* point the file pointer to nearest AU */
737    filePos = position;
738    pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile, M4OSA_kFileSeekBeginning,
739         &filePos );
740
741    if ( partSeekTime == 0)
742    {
743        M4OSA_TIME_SET(*pObtainCTS, time);
744        return M4NO_ERROR;
745    }
746
747    M4OSA_INT64_FROM_DOUBLE(*pObtainCTS, (time_double - (M4OSA_Double)partSeekTime)) ;
748
749    switch(seekMode)
750    {
751        /* Get the AU before the target time */
752        case M4SYS_kPreviousRAP:
753        case M4SYS_kNoRAPprevious:
754            position = partSeekTime / M4AMRR_FRAME_LENGTH ;
755            if ( !(partSeekTime % M4AMRR_FRAME_LENGTH) )
756            {
757                position -- ;
758            }
759        break;
760        /* Get the Closest AU following the target time */
761        case M4SYS_kNextRAP:
762        case M4SYS_kNoRAPnext:
763            position = (partSeekTime + M4AMRR_FRAME_LENGTH )/ M4AMRR_FRAME_LENGTH ;
764        break;
765        /*  Get the closest AU to target time */
766        case M4SYS_kClosestRAP:
767        case M4SYS_kNoRAPclosest:
768            prevAU = partSeekTime-(partSeekTime/M4AMRR_FRAME_LENGTH)*M4AMRR_FRAME_LENGTH;
769            nextAU =
770                 ((partSeekTime+M4AMRR_FRAME_LENGTH)/M4AMRR_FRAME_LENGTH)*M4AMRR_FRAME_LENGTH -\
771                     partSeekTime ;
772            if(prevAU < nextAU)
773            {
774                position = partSeekTime / M4AMRR_FRAME_LENGTH ;
775            }
776            else
777            {
778                position = (partSeekTime + M4AMRR_FRAME_LENGTH )/ M4AMRR_FRAME_LENGTH ;
779            }
780        break;
781        case M4SYS_kBeginning:
782        break;
783    }
784
785    count = 0 ;
786    /* Skip the Access unit in the stream to skip the part seek time,
787       to reach the required target time */
788    while(count < position )
789    {
790        size = 1;
791        pStreamContext->m_pOsaFilePtrFct->readData(pStreamContext->m_pAMRFile,
792             (M4OSA_MemAddr8)&frameHeader, &size);
793        if ( size == 0)
794        {
795            /* If the target time is invalid, point to begining and return */
796            M4OSA_INT64_FROM_INT32(*pObtainCTS, 0);
797            filePos = pStreamContext->m_pSeekIndex[0];
798            pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile,
799                 M4OSA_kFileSeekBeginning, &filePos);
800            return M4WAR_INVALID_TIME ;
801        }
802        *pObtainCTS += M4AMRR_FRAME_LENGTH; /*Should use M4OSA_INT64_ADD !!*/
803        count++;
804        frameType = (frameHeader & 0x78) >> 3 ;
805        if(frameType == 15)
806        {
807            auSize = 1 ;
808        }
809        else
810        {
811            auSize = M4AMRR_getAuSize(frameType, pStreamContext->m_streamType);
812        }
813
814        filePos = auSize-1;
815        pStreamContext->m_pOsaFilePtrFct->seek(pStreamContext->m_pAMRFile,
816             M4OSA_kFileSeekCurrent, &filePos);
817    }
818
819    return M4NO_ERROR;
820}
821
822/*********************************************************/
823M4OSA_ERR M4AMRR_closeRead(M4OSA_Context Context)
824/*********************************************************/
825{
826    M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context;
827    M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL");
828
829    /* Close the AMR stream */
830    pStreamContext->m_pOsaFilePtrFct->closeRead(pStreamContext->m_pAMRFile);
831
832    pStreamContext->m_status=M4AMRR_kClosed ;
833
834    /* Check if AU data Address is allocated memory and free it */
835    if(M4OSA_NULL != pStreamContext->m_pdataAddress)
836    {
837        M4OSA_free((M4OSA_MemAddr32)pStreamContext->m_pdataAddress);
838    }
839
840    /* Check if the stream handler is allocated memory */
841    if(M4OSA_NULL != pStreamContext->m_pStreamHandler)
842    {
843        M4OSA_free((M4OSA_MemAddr32)pStreamContext->m_pStreamHandler);
844    }
845
846    /* Seek table is created only when seek is used, so check if memory is allocated */
847    if(M4OSA_NULL != pStreamContext->m_pSeekIndex)
848    {
849        M4OSA_free((M4OSA_MemAddr32)pStreamContext->m_pSeekIndex);
850    }
851
852    /* Free the context */
853    M4OSA_free((M4OSA_MemAddr32)pStreamContext);
854
855    return M4NO_ERROR ;
856}
857
858/*********************************************************/
859M4OSA_ERR M4AMRR_getState(M4OSA_Context Context, M4AMRR_State* pState, M4SYS_StreamID streamId)
860/*********************************************************/
861{
862    M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context;
863    M4OSA_DEBUG_IF2((M4OSA_NULL == Context),M4ERR_PARAMETER,"Context M4OSA_NULL");
864    M4OSA_DEBUG_IF2((pStreamContext->m_contextId != M4AMRR_CONTEXTID),M4ERR_BAD_CONTEXT,
865         "Bad Context");
866
867    if (( streamId != 1 ) && ( streamId != 0))
868    {
869            return M4ERR_BAD_STREAM_ID;
870    }
871
872    *pState = pStreamContext->m_status ;
873
874    return M4NO_ERROR ;
875}
876
877
878/*********************************************************/
879M4OSA_ERR M4AMRR_getVersion    (M4_VersionInfo *pVersion)
880/*********************************************************/
881{
882    M4OSA_TRACE1_1("M4AMRR_getVersion called with pVersion: 0x%x\n", pVersion);
883    M4OSA_DEBUG_IF1(((M4OSA_UInt32) pVersion == 0),M4ERR_PARAMETER,
884         "pVersion is NULL in M4AMRR_getVersion");
885
886    pVersion->m_major = M4AMRR_VERSION_MAJOR;
887    pVersion->m_minor = M4AMRR_VERSION_MINOR;
888    pVersion->m_revision = M4AMRR_VERSION_REVISION;
889
890    return M4NO_ERROR;
891}
892
893/*********************************************************/
894M4OSA_ERR M4AMRR_getmaxAUsize(M4OSA_Context Context, M4OSA_UInt32 *pMaxAuSize)
895/*********************************************************/
896{
897    M4_AMRR_Context* pStreamContext=(M4_AMRR_Context*)Context;
898
899    /**
900     * Check input parameters */
901    M4OSA_DEBUG_IF1((M4OSA_NULL == Context),  M4ERR_PARAMETER,
902                "M4AMRR_getmaxAUsize: Context is M4OSA_NULL");
903    M4OSA_DEBUG_IF1((M4OSA_NULL == pMaxAuSize),M4ERR_PARAMETER,
904                "M4AMRR_getmaxAUsize: pMaxAuSize is M4OSA_NULL");
905
906    *pMaxAuSize = pStreamContext->m_maxAuSize;
907
908    return M4NO_ERROR;
909}
910
911