1 /***************************************************************************
2   \file ADM_aacadts.cpp
3   \brief wrapper around libavcodec bitstream filter
4  ***************************************************************************/
5 
6 /***************************************************************************
7  *                                                                         *
8  *   This program is free software; you can redistribute it and/or modify  *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation; either version 2 of the License, or     *
11  *   (at your option) any later version.                                   *
12  *                                                                         *
13  ***************************************************************************/
14 
15 #include <math.h>
16 #include "ADM_default.h"
17 #include "ADM_aacadts.h"
18 
19 #if 0
20     #define aprintf printf
21 #else
22     #define aprintf(...) {}
23 #endif
24 
25 static const int aacChannels[16]=
26 {
27 0, //0: Defined in AOT Specifc Config
28 1, //1: 1 channel: front-center
29 2, //2: 2 channels: front-left, front-right
30 3, //3: 3 channels: front-center, front-left, front-right
31 4, //4: 4 channels: front-center, front-left, front-right, back-center
32 5, // 5: 5 channels: front-center, front-left, front-right, back-left, back-right
33 6, // 6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
34 8, // 7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
35 0,0,0,0,
36 0,0,0,0,
37 };
38 
39 static 	uint32_t aacSampleRate[16]=
40 {
41 	96000, 88200, 64000, 48000,
42 	44100, 32000, 24000, 22050,
43 	16000, 12000, 11025,  8000,
44 	0,     0,     0,     0
45 };
46 
47 /**
48     \fn ctor
49 */
50 
ADM_adts2aac(void)51 ADM_adts2aac::ADM_adts2aac(void)
52 {
53     hasExtra=false;
54     extra[0]=extra[1]=0;
55     head=tail=0;
56     buffer.setSize(ADTS_BUFFER_SIZE*2);
57     headOffset=0;
58 }
59 /**
60     \fn dtor
61 */
62 
~ADM_adts2aac()63 ADM_adts2aac::~ADM_adts2aac()
64 {
65 
66 }
67 
68 /**
69     \fn getExtraData
70     \brief extract extradata from adts/aac stream. You must have converted successfully at leat one frame.
71 */
getExtraData(uint32_t * len,uint8_t ** data)72 bool ADM_adts2aac::getExtraData(uint32_t *len,uint8_t **data)
73 {
74     if(hasExtra)
75     {
76         *data=extra;
77         *len=2;
78         return true;
79     }
80     return false;
81 }
82 /**
83     \fn getFrequency
84     \brief get stream frequency. Convert must have been called ok once.
85 */
getFrequency(void)86 int ADM_adts2aac::getFrequency(void)
87 {
88     if(!hasExtra)
89     {
90         ADM_error("No extradata in aac! using default of 48 kHz\n");
91         return 48000;
92     }
93     uint8_t *p=extra;
94     int dex=((p[0]&7)<<1)+(p[1]>>7);
95     return aacSampleRate[dex];
96 }
97 /**
98     \fn getChannels
99     \brief returns # of channels. Convert must have been called ok once.
100 */
getChannels(void)101 int ADM_adts2aac::getChannels(void)
102 {
103     if(!hasExtra)
104     {
105         ADM_error("No extradata in aac! using default of 2 channels\n");
106         return 2;
107     }
108     uint8_t *p=extra;
109     int dex=((p[1]>>3)&0xf);
110     return aacChannels[dex];
111 }
112 
113 
114 /**
115     \fn addData
116     \brief Add data to our pool
117 */
reset()118 bool ADM_adts2aac::reset()
119 {
120      head=tail=0;
121      hasExtra=false;
122      headOffset=0;
123      return true;
124 }
addData(int incomingLen,const uint8_t * inData)125 bool  ADM_adts2aac::addData(int incomingLen,const uint8_t *inData)
126 {
127      // Step 1 : append to our buffer...
128 
129     if(head==tail)
130     {
131         headOffset+=tail;
132         head=tail=0;
133     }
134     if(tail>ADTS_BUFFER_SIZE)
135     {
136         headOffset+=tail;
137         int size=head-tail;
138         memmove(buffer.at(0),buffer.at(tail),size);
139         head=size;
140         tail=0;
141 
142     }
143     if(head+incomingLen>ADTS_BUFFER_SIZE*2)
144     {
145         ADM_error("Head=%d tail=%d bufferSize=%d\n",head,tail,ADTS_BUFFER_SIZE*2);
146         ADM_error("Adts buffer overflow\n");
147         return false;
148     }
149     memcpy(buffer.at(head),inData,incomingLen);
150     head+=incomingLen;
151     return true;
152 }
153 /**
154  * \fn getAACFrame
155  * \brief try to extract a valid frame from ADTS
156  * @param outLen
157  * @param out
158  * @param offset, offset from the beginning of the stream i.e. 1st add Data
159  * @return
160  */
getAACFrame(int * outLen,uint8_t * out,int * offset)161 ADM_adts2aac::ADTS_STATE ADM_adts2aac::getAACFrame(int *outLen,uint8_t *out,int *offset)
162 {
163     if(outLen)
164         *outLen=0;
165 again:
166     aprintf("[ADTS] *** head=%d tail=%d size=%d***\n",head,tail,head-tail);
167     if(tail+7>head) // we neeed at least 7 bytes...
168     {
169         aprintf("Adts: Not enough data \n");
170         return ADTS_MORE_DATA_NEEDED;
171     }
172     // now search for sync....
173     bool found=false;
174     uint8_t *p=NULL;
175     int packetLen=0;
176     int nbFrames=0;
177     bool crc=false;
178     int match;
179     for( p=(buffer.at(tail));p<(buffer.at(head-6));p++)
180     {
181         if(p[0]!=0xff || (p[1]&0xf0)!=0xf0 || p[1]&6)
182             continue;
183 
184         match=p-buffer.at(0); // offset of syncword
185         packetLen=((p[3]&0x3)<<11)+(p[4]<<3)+(p[5]>>5);
186         nbFrames=1+(p[6]&3);
187         if(!(p[1]&1))
188         {
189             crc=true;
190         }
191         if(!packetLen || nbFrames!=1) continue;
192         aprintf("[ADTS] Packet len=%d, nbframes=%d\n",packetLen,nbFrames);
193         aprintf("[ADTS] Found sync at offset %d, buffer size=%d\n",(int)(p-buffer.at(0)),(int)(head-tail));
194         aprintf("[ADTS] Dropping %d bytes\n",(int)(p-buffer.at(0)-tail));
195         if(match==tail && match+packetLen==head)
196         {
197             aprintf("[ADTS] Perfect match\n");
198             found=true;
199             break;
200         }
201         if(match+packetLen+3>head && match+packetLen!=head)
202         {
203             aprintf("[ADTS]** not enough data **\n");
204             return ADTS_MORE_DATA_NEEDED;
205         }
206         // do we have sync at the end ?
207         if(p[packetLen]!=0xff || (p[packetLen+1]&0xf0)!=0xf0 || p[packetLen+1]&6)
208         {
209             aprintf("[ADTS] no syncword at the end or layer!=0\n");
210             continue;
211         }
212         aprintf("[ADTS] End marker found\n");
213         found=true;
214         break;
215 
216     }
217     if(found==false)
218     {
219         aprintf("[ADTS]No sync\n");
220         tail=head-6;
221         return ADTS_MORE_DATA_NEEDED;
222     }
223     if(!hasExtra)
224     { // build codec specific info, thanks vlc
225         int i_profile=p[2]>>6;
226         int i_sample_rate_idx=(p[2]>>2)&0x0f;
227         int pi_channels=((p[2]<<2)+((p[3]>>6)))&0x7;
228         extra[0] =   (i_profile + 1) << 3 | (i_sample_rate_idx >> 1);
229         extra[1] =   ((i_sample_rate_idx & 0x01) << 7) | (pi_channels <<3);
230         hasExtra=true;
231         aprintf("[ADTS] extradata %02x %02x\n",extra[0],extra[1]);
232     }
233     // size ?
234     uint8_t *o;
235     int produced=0;
236     // filter!
237     //-------
238 
239     if(crc)
240     {
241         o=p+9;
242         produced=packetLen-9;
243     }else
244     {
245         o=p+7;
246         produced=packetLen-7;
247     }
248     //
249     //---------
250     if(produced<1)
251     {
252         tail=match+1;
253         aprintf("[ADTS] No data produced\n");
254         goto again;
255     }
256     if(offset)
257     {
258         *offset=headOffset+(int)(p-buffer.at(0));
259     }
260     aprintf("[ADTS] Found adts packet of size %d, extradataLen=%d\n",produced,2);
261     if(out)
262     {
263         memcpy(out,o,produced);
264         out+=produced;
265         *outLen+=produced;
266         tail=match+packetLen; // ~ skip
267     }
268     ADM_assert(tail<=head);
269     return ADTS_OK;
270 }
271 /**
272     \fn convert
273     \brief strip adts header. Out can be null if you just want to get headers
274 */
275 
convert2(int incomingLen,const uint8_t * inData,int * outLen,uint8_t * out)276 ADM_adts2aac::ADTS_STATE ADM_adts2aac::convert2(int incomingLen,const uint8_t *inData,int *outLen,uint8_t *out)
277 {
278     *outLen=0;
279     bool r=false;
280     if(incomingLen)
281         r=addData(incomingLen,inData);
282     ADTS_STATE state=getAACFrame(outLen,out);
283     if(!r && state==ADTS_MORE_DATA_NEEDED)
284         return ADTS_ERROR;
285     return state;
286 }
287 //EOF
288