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