diff options
author | Dave Chapman <dave@dchapman.com> | 2005-10-31 18:56:29 +0000 |
---|---|---|
committer | Dave Chapman <dave@dchapman.com> | 2005-10-31 18:56:29 +0000 |
commit | 65de1cc6af31f547bd36d320f09cbcc6e6975421 (patch) | |
tree | d1ab6e97adfacb3ef8ca95cdf1c90fcb025271b0 /apps/codecs/libfaad/decoder.c | |
parent | b83dc3861e5552a802767f37cb97d6b41c9f01cc (diff) | |
download | rockbox-65de1cc6af31f547bd36d320f09cbcc6e6975421.tar.gz rockbox-65de1cc6af31f547bd36d320f09cbcc6e6975421.zip |
Initial check-in of unmodified libfaad (part of the FAAD2 project). This is the last version of libfaad available under the GPL - the state of FAAD2 CVS at midnight on 2005-02-01
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7699 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/libfaad/decoder.c')
-rw-r--r-- | apps/codecs/libfaad/decoder.c | 1024 |
1 files changed, 1024 insertions, 0 deletions
diff --git a/apps/codecs/libfaad/decoder.c b/apps/codecs/libfaad/decoder.c new file mode 100644 index 0000000000..b2c37dadb8 --- /dev/null +++ b/apps/codecs/libfaad/decoder.c | |||
@@ -0,0 +1,1024 @@ | |||
1 | /* | ||
2 | ** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding | ||
3 | ** Copyright (C) 2003-2004 M. Bakker, Ahead Software AG, http://www.nero.com | ||
4 | ** | ||
5 | ** This program is free software; you can redistribute it and/or modify | ||
6 | ** it under the terms of the GNU General Public License as published by | ||
7 | ** the Free Software Foundation; either version 2 of the License, or | ||
8 | ** (at your option) any later version. | ||
9 | ** | ||
10 | ** This program is distributed in the hope that it will be useful, | ||
11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | ** GNU General Public License for more details. | ||
14 | ** | ||
15 | ** You should have received a copy of the GNU General Public License | ||
16 | ** along with this program; if not, write to the Free Software | ||
17 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | ** | ||
19 | ** Any non-GPL usage of this software or parts of this software is strictly | ||
20 | ** forbidden. | ||
21 | ** | ||
22 | ** Commercial non-GPL licensing of this software is possible. | ||
23 | ** For more info contact Ahead Software through Mpeg4AAClicense@nero.com. | ||
24 | ** | ||
25 | ** $Id$ | ||
26 | **/ | ||
27 | |||
28 | #include "common.h" | ||
29 | #include "structs.h" | ||
30 | |||
31 | #include <stdlib.h> | ||
32 | #include <string.h> | ||
33 | |||
34 | #include "decoder.h" | ||
35 | #include "mp4.h" | ||
36 | #include "syntax.h" | ||
37 | #include "error.h" | ||
38 | #include "output.h" | ||
39 | #include "filtbank.h" | ||
40 | #include "drc.h" | ||
41 | #ifdef SBR_DEC | ||
42 | #include "sbr_dec.h" | ||
43 | #include "sbr_syntax.h" | ||
44 | #endif | ||
45 | #ifdef SSR_DEC | ||
46 | #include "ssr.h" | ||
47 | #endif | ||
48 | |||
49 | #ifdef ANALYSIS | ||
50 | uint16_t dbg_count; | ||
51 | #endif | ||
52 | |||
53 | /* static function declarations */ | ||
54 | static void* aac_frame_decode(NeAACDecHandle hDecoder, NeAACDecFrameInfo *hInfo, | ||
55 | uint8_t *buffer, uint32_t buffer_size, | ||
56 | void **sample_buffer, uint32_t sample_buffer_size); | ||
57 | static void create_channel_config(NeAACDecHandle hDecoder, NeAACDecFrameInfo *hInfo); | ||
58 | |||
59 | |||
60 | char* NEAACDECAPI NeAACDecGetErrorMessage(uint8_t errcode) | ||
61 | { | ||
62 | if (errcode >= NUM_ERROR_MESSAGES) | ||
63 | return NULL; | ||
64 | return err_msg[errcode]; | ||
65 | } | ||
66 | |||
67 | uint32_t NEAACDECAPI NeAACDecGetCapabilities(void) | ||
68 | { | ||
69 | uint32_t cap = 0; | ||
70 | |||
71 | /* can't do without it */ | ||
72 | cap += LC_DEC_CAP; | ||
73 | |||
74 | #ifdef MAIN_DEC | ||
75 | cap += MAIN_DEC_CAP; | ||
76 | #endif | ||
77 | #ifdef LTP_DEC | ||
78 | cap += LTP_DEC_CAP; | ||
79 | #endif | ||
80 | #ifdef LD_DEC | ||
81 | cap += LD_DEC_CAP; | ||
82 | #endif | ||
83 | #ifdef ERROR_RESILIENCE | ||
84 | cap += ERROR_RESILIENCE_CAP; | ||
85 | #endif | ||
86 | #ifdef FIXED_POINT | ||
87 | cap += FIXED_POINT_CAP; | ||
88 | #endif | ||
89 | |||
90 | return cap; | ||
91 | } | ||
92 | |||
93 | NeAACDecHandle NEAACDECAPI NeAACDecOpen(void) | ||
94 | { | ||
95 | uint8_t i; | ||
96 | NeAACDecHandle hDecoder = NULL; | ||
97 | |||
98 | if ((hDecoder = (NeAACDecHandle)faad_malloc(sizeof(NeAACDecStruct))) == NULL) | ||
99 | return NULL; | ||
100 | |||
101 | memset(hDecoder, 0, sizeof(NeAACDecStruct)); | ||
102 | |||
103 | hDecoder->config.outputFormat = FAAD_FMT_16BIT; | ||
104 | hDecoder->config.defObjectType = MAIN; | ||
105 | hDecoder->config.defSampleRate = 44100; /* Default: 44.1kHz */ | ||
106 | hDecoder->config.downMatrix = 0; | ||
107 | hDecoder->adts_header_present = 0; | ||
108 | hDecoder->adif_header_present = 0; | ||
109 | #ifdef ERROR_RESILIENCE | ||
110 | hDecoder->aacSectionDataResilienceFlag = 0; | ||
111 | hDecoder->aacScalefactorDataResilienceFlag = 0; | ||
112 | hDecoder->aacSpectralDataResilienceFlag = 0; | ||
113 | #endif | ||
114 | hDecoder->frameLength = 1024; | ||
115 | |||
116 | hDecoder->frame = 0; | ||
117 | hDecoder->sample_buffer = NULL; | ||
118 | |||
119 | for (i = 0; i < MAX_CHANNELS; i++) | ||
120 | { | ||
121 | hDecoder->window_shape_prev[i] = 0; | ||
122 | hDecoder->time_out[i] = NULL; | ||
123 | hDecoder->fb_intermed[i] = NULL; | ||
124 | #ifdef SSR_DEC | ||
125 | hDecoder->ssr_overlap[i] = NULL; | ||
126 | hDecoder->prev_fmd[i] = NULL; | ||
127 | #endif | ||
128 | #ifdef MAIN_DEC | ||
129 | hDecoder->pred_stat[i] = NULL; | ||
130 | #endif | ||
131 | #ifdef LTP_DEC | ||
132 | hDecoder->ltp_lag[i] = 0; | ||
133 | hDecoder->lt_pred_stat[i] = NULL; | ||
134 | #endif | ||
135 | } | ||
136 | |||
137 | #ifdef SBR_DEC | ||
138 | for (i = 0; i < MAX_SYNTAX_ELEMENTS; i++) | ||
139 | { | ||
140 | hDecoder->sbr[i] = NULL; | ||
141 | } | ||
142 | #endif | ||
143 | |||
144 | hDecoder->drc = drc_init(REAL_CONST(1.0), REAL_CONST(1.0)); | ||
145 | |||
146 | return hDecoder; | ||
147 | } | ||
148 | |||
149 | NeAACDecConfigurationPtr NEAACDECAPI NeAACDecGetCurrentConfiguration(NeAACDecHandle hDecoder) | ||
150 | { | ||
151 | if (hDecoder) | ||
152 | { | ||
153 | NeAACDecConfigurationPtr config = &(hDecoder->config); | ||
154 | |||
155 | return config; | ||
156 | } | ||
157 | |||
158 | return NULL; | ||
159 | } | ||
160 | |||
161 | uint8_t NEAACDECAPI NeAACDecSetConfiguration(NeAACDecHandle hDecoder, | ||
162 | NeAACDecConfigurationPtr config) | ||
163 | { | ||
164 | if (hDecoder && config) | ||
165 | { | ||
166 | /* check if we can decode this object type */ | ||
167 | if (can_decode_ot(config->defObjectType) < 0) | ||
168 | return 0; | ||
169 | hDecoder->config.defObjectType = config->defObjectType; | ||
170 | |||
171 | /* samplerate: anything but 0 should be possible */ | ||
172 | if (config->defSampleRate == 0) | ||
173 | return 0; | ||
174 | hDecoder->config.defSampleRate = config->defSampleRate; | ||
175 | |||
176 | /* check output format */ | ||
177 | #ifdef FIXED_POINT | ||
178 | if ((config->outputFormat < 1) || (config->outputFormat > 4)) | ||
179 | return 0; | ||
180 | #else | ||
181 | if ((config->outputFormat < 1) || (config->outputFormat > 5)) | ||
182 | return 0; | ||
183 | #endif | ||
184 | hDecoder->config.outputFormat = config->outputFormat; | ||
185 | |||
186 | if (config->downMatrix > 1) | ||
187 | return 0; | ||
188 | hDecoder->config.downMatrix = config->downMatrix; | ||
189 | |||
190 | /* OK */ | ||
191 | return 1; | ||
192 | } | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | int32_t NEAACDECAPI NeAACDecInit(NeAACDecHandle hDecoder, uint8_t *buffer, | ||
198 | uint32_t buffer_size, | ||
199 | uint32_t *samplerate, uint8_t *channels) | ||
200 | { | ||
201 | uint32_t bits = 0; | ||
202 | bitfile ld; | ||
203 | adif_header adif; | ||
204 | adts_header adts; | ||
205 | |||
206 | if ((hDecoder == NULL) || (samplerate == NULL) || (channels == NULL)) | ||
207 | return -1; | ||
208 | |||
209 | hDecoder->sf_index = get_sr_index(hDecoder->config.defSampleRate); | ||
210 | hDecoder->object_type = hDecoder->config.defObjectType; | ||
211 | *samplerate = get_sample_rate(hDecoder->sf_index); | ||
212 | *channels = 1; | ||
213 | |||
214 | if (buffer != NULL) | ||
215 | { | ||
216 | faad_initbits(&ld, buffer, buffer_size); | ||
217 | |||
218 | /* Check if an ADIF header is present */ | ||
219 | if ((buffer[0] == 'A') && (buffer[1] == 'D') && | ||
220 | (buffer[2] == 'I') && (buffer[3] == 'F')) | ||
221 | { | ||
222 | hDecoder->adif_header_present = 1; | ||
223 | |||
224 | get_adif_header(&adif, &ld); | ||
225 | faad_byte_align(&ld); | ||
226 | |||
227 | hDecoder->sf_index = adif.pce[0].sf_index; | ||
228 | hDecoder->object_type = adif.pce[0].object_type + 1; | ||
229 | |||
230 | *samplerate = get_sample_rate(hDecoder->sf_index); | ||
231 | *channels = adif.pce[0].channels; | ||
232 | |||
233 | memcpy(&(hDecoder->pce), &(adif.pce[0]), sizeof(program_config)); | ||
234 | hDecoder->pce_set = 1; | ||
235 | |||
236 | bits = bit2byte(faad_get_processed_bits(&ld)); | ||
237 | |||
238 | /* Check if an ADTS header is present */ | ||
239 | } else if (faad_showbits(&ld, 12) == 0xfff) { | ||
240 | hDecoder->adts_header_present = 1; | ||
241 | |||
242 | adts.old_format = hDecoder->config.useOldADTSFormat; | ||
243 | adts_frame(&adts, &ld); | ||
244 | |||
245 | hDecoder->sf_index = adts.sf_index; | ||
246 | hDecoder->object_type = adts.profile + 1; | ||
247 | |||
248 | *samplerate = get_sample_rate(hDecoder->sf_index); | ||
249 | *channels = (adts.channel_configuration > 6) ? | ||
250 | 2 : adts.channel_configuration; | ||
251 | } | ||
252 | |||
253 | if (ld.error) | ||
254 | { | ||
255 | faad_endbits(&ld); | ||
256 | return -1; | ||
257 | } | ||
258 | faad_endbits(&ld); | ||
259 | } | ||
260 | hDecoder->channelConfiguration = *channels; | ||
261 | |||
262 | #if (defined(PS_DEC) || defined(DRM_PS)) | ||
263 | /* check if we have a mono file */ | ||
264 | if (*channels == 1) | ||
265 | { | ||
266 | /* upMatrix to 2 channels for implicit signalling of PS */ | ||
267 | *channels = 2; | ||
268 | } | ||
269 | #endif | ||
270 | |||
271 | #ifdef SBR_DEC | ||
272 | /* implicit signalling */ | ||
273 | if (*samplerate <= 24000 && !(hDecoder->config.dontUpSampleImplicitSBR)) | ||
274 | { | ||
275 | *samplerate *= 2; | ||
276 | hDecoder->forceUpSampling = 1; | ||
277 | } else if (*samplerate > 24000 && !(hDecoder->config.dontUpSampleImplicitSBR)) { | ||
278 | hDecoder->downSampledSBR = 1; | ||
279 | } | ||
280 | #endif | ||
281 | |||
282 | /* must be done before frameLength is divided by 2 for LD */ | ||
283 | #ifdef SSR_DEC | ||
284 | if (hDecoder->object_type == SSR) | ||
285 | hDecoder->fb = ssr_filter_bank_init(hDecoder->frameLength/SSR_BANDS); | ||
286 | else | ||
287 | #endif | ||
288 | hDecoder->fb = filter_bank_init(hDecoder->frameLength); | ||
289 | |||
290 | #ifdef LD_DEC | ||
291 | if (hDecoder->object_type == LD) | ||
292 | hDecoder->frameLength >>= 1; | ||
293 | #endif | ||
294 | |||
295 | if (can_decode_ot(hDecoder->object_type) < 0) | ||
296 | return -1; | ||
297 | |||
298 | return bits; | ||
299 | } | ||
300 | |||
301 | /* Init the library using a DecoderSpecificInfo */ | ||
302 | int8_t NEAACDECAPI NeAACDecInit2(NeAACDecHandle hDecoder, uint8_t *pBuffer, | ||
303 | uint32_t SizeOfDecoderSpecificInfo, | ||
304 | uint32_t *samplerate, uint8_t *channels) | ||
305 | { | ||
306 | int8_t rc; | ||
307 | mp4AudioSpecificConfig mp4ASC; | ||
308 | |||
309 | if((hDecoder == NULL) | ||
310 | || (pBuffer == NULL) | ||
311 | || (SizeOfDecoderSpecificInfo < 2) | ||
312 | || (samplerate == NULL) | ||
313 | || (channels == NULL)) | ||
314 | { | ||
315 | return -1; | ||
316 | } | ||
317 | |||
318 | hDecoder->adif_header_present = 0; | ||
319 | hDecoder->adts_header_present = 0; | ||
320 | |||
321 | /* decode the audio specific config */ | ||
322 | rc = AudioSpecificConfig2(pBuffer, SizeOfDecoderSpecificInfo, &mp4ASC, | ||
323 | &(hDecoder->pce)); | ||
324 | |||
325 | /* copy the relevant info to the decoder handle */ | ||
326 | *samplerate = mp4ASC.samplingFrequency; | ||
327 | if (mp4ASC.channelsConfiguration) | ||
328 | { | ||
329 | *channels = mp4ASC.channelsConfiguration; | ||
330 | } else { | ||
331 | *channels = hDecoder->pce.channels; | ||
332 | hDecoder->pce_set = 1; | ||
333 | } | ||
334 | #if (defined(PS_DEC) || defined(DRM_PS)) | ||
335 | /* check if we have a mono file */ | ||
336 | if (*channels == 1) | ||
337 | { | ||
338 | /* upMatrix to 2 channels for implicit signalling of PS */ | ||
339 | *channels = 2; | ||
340 | } | ||
341 | #endif | ||
342 | hDecoder->sf_index = mp4ASC.samplingFrequencyIndex; | ||
343 | hDecoder->object_type = mp4ASC.objectTypeIndex; | ||
344 | #ifdef ERROR_RESILIENCE | ||
345 | hDecoder->aacSectionDataResilienceFlag = mp4ASC.aacSectionDataResilienceFlag; | ||
346 | hDecoder->aacScalefactorDataResilienceFlag = mp4ASC.aacScalefactorDataResilienceFlag; | ||
347 | hDecoder->aacSpectralDataResilienceFlag = mp4ASC.aacSpectralDataResilienceFlag; | ||
348 | #endif | ||
349 | #ifdef SBR_DEC | ||
350 | hDecoder->sbr_present_flag = mp4ASC.sbr_present_flag; | ||
351 | hDecoder->downSampledSBR = mp4ASC.downSampledSBR; | ||
352 | if (hDecoder->config.dontUpSampleImplicitSBR == 0) | ||
353 | hDecoder->forceUpSampling = mp4ASC.forceUpSampling; | ||
354 | else | ||
355 | hDecoder->forceUpSampling = 0; | ||
356 | |||
357 | /* AAC core decoder samplerate is 2 times as low */ | ||
358 | if (((hDecoder->sbr_present_flag == 1)&&(!hDecoder->downSampledSBR)) || hDecoder->forceUpSampling == 1) | ||
359 | { | ||
360 | hDecoder->sf_index = get_sr_index(mp4ASC.samplingFrequency / 2); | ||
361 | } | ||
362 | #endif | ||
363 | |||
364 | if (rc != 0) | ||
365 | { | ||
366 | return rc; | ||
367 | } | ||
368 | hDecoder->channelConfiguration = mp4ASC.channelsConfiguration; | ||
369 | if (mp4ASC.frameLengthFlag) | ||
370 | #ifdef ALLOW_SMALL_FRAMELENGTH | ||
371 | hDecoder->frameLength = 960; | ||
372 | #else | ||
373 | return -1; | ||
374 | #endif | ||
375 | |||
376 | /* must be done before frameLength is divided by 2 for LD */ | ||
377 | #ifdef SSR_DEC | ||
378 | if (hDecoder->object_type == SSR) | ||
379 | hDecoder->fb = ssr_filter_bank_init(hDecoder->frameLength/SSR_BANDS); | ||
380 | else | ||
381 | #endif | ||
382 | hDecoder->fb = filter_bank_init(hDecoder->frameLength); | ||
383 | |||
384 | #ifdef LD_DEC | ||
385 | if (hDecoder->object_type == LD) | ||
386 | hDecoder->frameLength >>= 1; | ||
387 | #endif | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | #ifdef DRM | ||
393 | int8_t NEAACDECAPI NeAACDecInitDRM(NeAACDecHandle *hDecoder, uint32_t samplerate, | ||
394 | uint8_t channels) | ||
395 | { | ||
396 | if (hDecoder == NULL) | ||
397 | return 1; /* error */ | ||
398 | |||
399 | NeAACDecClose(*hDecoder); | ||
400 | |||
401 | *hDecoder = NeAACDecOpen(); | ||
402 | |||
403 | /* Special object type defined for DRM */ | ||
404 | (*hDecoder)->config.defObjectType = DRM_ER_LC; | ||
405 | |||
406 | (*hDecoder)->config.defSampleRate = samplerate; | ||
407 | #ifdef ERROR_RESILIENCE // This shoudl always be defined for DRM | ||
408 | (*hDecoder)->aacSectionDataResilienceFlag = 1; /* VCB11 */ | ||
409 | (*hDecoder)->aacScalefactorDataResilienceFlag = 0; /* no RVLC */ | ||
410 | (*hDecoder)->aacSpectralDataResilienceFlag = 1; /* HCR */ | ||
411 | #endif | ||
412 | (*hDecoder)->frameLength = 960; | ||
413 | (*hDecoder)->sf_index = get_sr_index((*hDecoder)->config.defSampleRate); | ||
414 | (*hDecoder)->object_type = (*hDecoder)->config.defObjectType; | ||
415 | |||
416 | if ((channels == DRMCH_STEREO) || (channels == DRMCH_SBR_STEREO)) | ||
417 | (*hDecoder)->channelConfiguration = 2; | ||
418 | else | ||
419 | (*hDecoder)->channelConfiguration = 1; | ||
420 | |||
421 | #ifdef SBR_DEC | ||
422 | if ((channels == DRMCH_MONO) || (channels == DRMCH_STEREO)) | ||
423 | (*hDecoder)->sbr_present_flag = 0; | ||
424 | else | ||
425 | (*hDecoder)->sbr_present_flag = 1; | ||
426 | #endif | ||
427 | |||
428 | (*hDecoder)->fb = filter_bank_init((*hDecoder)->frameLength); | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | #endif | ||
433 | |||
434 | void NEAACDECAPI NeAACDecClose(NeAACDecHandle hDecoder) | ||
435 | { | ||
436 | uint8_t i; | ||
437 | |||
438 | if (hDecoder == NULL) | ||
439 | return; | ||
440 | |||
441 | #ifdef PROFILE | ||
442 | printf("AAC decoder total: %I64d cycles\n", hDecoder->cycles); | ||
443 | printf("requant: %I64d cycles\n", hDecoder->requant_cycles); | ||
444 | printf("spectral_data: %I64d cycles\n", hDecoder->spectral_cycles); | ||
445 | printf("scalefactors: %I64d cycles\n", hDecoder->scalefac_cycles); | ||
446 | printf("output: %I64d cycles\n", hDecoder->output_cycles); | ||
447 | #endif | ||
448 | |||
449 | for (i = 0; i < MAX_CHANNELS; i++) | ||
450 | { | ||
451 | if (hDecoder->time_out[i]) faad_free(hDecoder->time_out[i]); | ||
452 | if (hDecoder->fb_intermed[i]) faad_free(hDecoder->fb_intermed[i]); | ||
453 | #ifdef SSR_DEC | ||
454 | if (hDecoder->ssr_overlap[i]) faad_free(hDecoder->ssr_overlap[i]); | ||
455 | if (hDecoder->prev_fmd[i]) faad_free(hDecoder->prev_fmd[i]); | ||
456 | #endif | ||
457 | #ifdef MAIN_DEC | ||
458 | if (hDecoder->pred_stat[i]) faad_free(hDecoder->pred_stat[i]); | ||
459 | #endif | ||
460 | #ifdef LTP_DEC | ||
461 | if (hDecoder->lt_pred_stat[i]) faad_free(hDecoder->lt_pred_stat[i]); | ||
462 | #endif | ||
463 | } | ||
464 | |||
465 | #ifdef SSR_DEC | ||
466 | if (hDecoder->object_type == SSR) | ||
467 | ssr_filter_bank_end(hDecoder->fb); | ||
468 | else | ||
469 | #endif | ||
470 | filter_bank_end(hDecoder->fb); | ||
471 | |||
472 | drc_end(hDecoder->drc); | ||
473 | |||
474 | if (hDecoder->sample_buffer) faad_free(hDecoder->sample_buffer); | ||
475 | |||
476 | #ifdef SBR_DEC | ||
477 | for (i = 0; i < MAX_SYNTAX_ELEMENTS; i++) | ||
478 | { | ||
479 | if (hDecoder->sbr[i]) | ||
480 | sbrDecodeEnd(hDecoder->sbr[i]); | ||
481 | } | ||
482 | #endif | ||
483 | |||
484 | if (hDecoder) faad_free(hDecoder); | ||
485 | } | ||
486 | |||
487 | void NEAACDECAPI NeAACDecPostSeekReset(NeAACDecHandle hDecoder, int32_t frame) | ||
488 | { | ||
489 | if (hDecoder) | ||
490 | { | ||
491 | hDecoder->postSeekResetFlag = 1; | ||
492 | |||
493 | if (frame != -1) | ||
494 | hDecoder->frame = frame; | ||
495 | } | ||
496 | } | ||
497 | |||
498 | static void create_channel_config(NeAACDecHandle hDecoder, NeAACDecFrameInfo *hInfo) | ||
499 | { | ||
500 | hInfo->num_front_channels = 0; | ||
501 | hInfo->num_side_channels = 0; | ||
502 | hInfo->num_back_channels = 0; | ||
503 | hInfo->num_lfe_channels = 0; | ||
504 | memset(hInfo->channel_position, 0, MAX_CHANNELS*sizeof(uint8_t)); | ||
505 | |||
506 | if (hDecoder->downMatrix) | ||
507 | { | ||
508 | hInfo->num_front_channels = 2; | ||
509 | hInfo->channel_position[0] = FRONT_CHANNEL_LEFT; | ||
510 | hInfo->channel_position[1] = FRONT_CHANNEL_RIGHT; | ||
511 | return; | ||
512 | } | ||
513 | |||
514 | /* check if there is a PCE */ | ||
515 | if (hDecoder->pce_set) | ||
516 | { | ||
517 | uint8_t i, chpos = 0; | ||
518 | uint8_t chdir, back_center = 0; | ||
519 | |||
520 | hInfo->num_front_channels = hDecoder->pce.num_front_channels; | ||
521 | hInfo->num_side_channels = hDecoder->pce.num_side_channels; | ||
522 | hInfo->num_back_channels = hDecoder->pce.num_back_channels; | ||
523 | hInfo->num_lfe_channels = hDecoder->pce.num_lfe_channels; | ||
524 | |||
525 | chdir = hInfo->num_front_channels; | ||
526 | if (chdir & 1) | ||
527 | { | ||
528 | hInfo->channel_position[chpos++] = FRONT_CHANNEL_CENTER; | ||
529 | chdir--; | ||
530 | } | ||
531 | for (i = 0; i < chdir; i += 2) | ||
532 | { | ||
533 | hInfo->channel_position[chpos++] = FRONT_CHANNEL_LEFT; | ||
534 | hInfo->channel_position[chpos++] = FRONT_CHANNEL_RIGHT; | ||
535 | } | ||
536 | |||
537 | for (i = 0; i < hInfo->num_side_channels; i += 2) | ||
538 | { | ||
539 | hInfo->channel_position[chpos++] = SIDE_CHANNEL_LEFT; | ||
540 | hInfo->channel_position[chpos++] = SIDE_CHANNEL_RIGHT; | ||
541 | } | ||
542 | |||
543 | chdir = hInfo->num_back_channels; | ||
544 | if (chdir & 1) | ||
545 | { | ||
546 | back_center = 1; | ||
547 | chdir--; | ||
548 | } | ||
549 | for (i = 0; i < chdir; i += 2) | ||
550 | { | ||
551 | hInfo->channel_position[chpos++] = BACK_CHANNEL_LEFT; | ||
552 | hInfo->channel_position[chpos++] = BACK_CHANNEL_RIGHT; | ||
553 | } | ||
554 | if (back_center) | ||
555 | { | ||
556 | hInfo->channel_position[chpos++] = BACK_CHANNEL_CENTER; | ||
557 | } | ||
558 | |||
559 | for (i = 0; i < hInfo->num_lfe_channels; i++) | ||
560 | { | ||
561 | hInfo->channel_position[chpos++] = LFE_CHANNEL; | ||
562 | } | ||
563 | |||
564 | } else { | ||
565 | switch (hDecoder->channelConfiguration) | ||
566 | { | ||
567 | case 1: | ||
568 | hInfo->num_front_channels = 1; | ||
569 | hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; | ||
570 | break; | ||
571 | case 2: | ||
572 | hInfo->num_front_channels = 2; | ||
573 | hInfo->channel_position[0] = FRONT_CHANNEL_LEFT; | ||
574 | hInfo->channel_position[1] = FRONT_CHANNEL_RIGHT; | ||
575 | break; | ||
576 | case 3: | ||
577 | hInfo->num_front_channels = 3; | ||
578 | hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; | ||
579 | hInfo->channel_position[1] = FRONT_CHANNEL_LEFT; | ||
580 | hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT; | ||
581 | break; | ||
582 | case 4: | ||
583 | hInfo->num_front_channels = 3; | ||
584 | hInfo->num_back_channels = 1; | ||
585 | hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; | ||
586 | hInfo->channel_position[1] = FRONT_CHANNEL_LEFT; | ||
587 | hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT; | ||
588 | hInfo->channel_position[3] = BACK_CHANNEL_CENTER; | ||
589 | break; | ||
590 | case 5: | ||
591 | hInfo->num_front_channels = 3; | ||
592 | hInfo->num_back_channels = 2; | ||
593 | hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; | ||
594 | hInfo->channel_position[1] = FRONT_CHANNEL_LEFT; | ||
595 | hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT; | ||
596 | hInfo->channel_position[3] = BACK_CHANNEL_LEFT; | ||
597 | hInfo->channel_position[4] = BACK_CHANNEL_RIGHT; | ||
598 | break; | ||
599 | case 6: | ||
600 | hInfo->num_front_channels = 3; | ||
601 | hInfo->num_back_channels = 2; | ||
602 | hInfo->num_lfe_channels = 1; | ||
603 | hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; | ||
604 | hInfo->channel_position[1] = FRONT_CHANNEL_LEFT; | ||
605 | hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT; | ||
606 | hInfo->channel_position[3] = BACK_CHANNEL_LEFT; | ||
607 | hInfo->channel_position[4] = BACK_CHANNEL_RIGHT; | ||
608 | hInfo->channel_position[5] = LFE_CHANNEL; | ||
609 | break; | ||
610 | case 7: | ||
611 | hInfo->num_front_channels = 3; | ||
612 | hInfo->num_side_channels = 2; | ||
613 | hInfo->num_back_channels = 2; | ||
614 | hInfo->num_lfe_channels = 1; | ||
615 | hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; | ||
616 | hInfo->channel_position[1] = FRONT_CHANNEL_LEFT; | ||
617 | hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT; | ||
618 | hInfo->channel_position[3] = SIDE_CHANNEL_LEFT; | ||
619 | hInfo->channel_position[4] = SIDE_CHANNEL_RIGHT; | ||
620 | hInfo->channel_position[5] = BACK_CHANNEL_LEFT; | ||
621 | hInfo->channel_position[6] = BACK_CHANNEL_RIGHT; | ||
622 | hInfo->channel_position[7] = LFE_CHANNEL; | ||
623 | break; | ||
624 | default: /* channelConfiguration == 0 || channelConfiguration > 7 */ | ||
625 | { | ||
626 | uint8_t i; | ||
627 | uint8_t ch = hDecoder->fr_channels - hDecoder->has_lfe; | ||
628 | if (ch & 1) /* there's either a center front or a center back channel */ | ||
629 | { | ||
630 | uint8_t ch1 = (ch-1)/2; | ||
631 | if (hDecoder->first_syn_ele == ID_SCE) | ||
632 | { | ||
633 | hInfo->num_front_channels = ch1 + 1; | ||
634 | hInfo->num_back_channels = ch1; | ||
635 | hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; | ||
636 | for (i = 1; i <= ch1; i+=2) | ||
637 | { | ||
638 | hInfo->channel_position[i] = FRONT_CHANNEL_LEFT; | ||
639 | hInfo->channel_position[i+1] = FRONT_CHANNEL_RIGHT; | ||
640 | } | ||
641 | for (i = ch1+1; i < ch; i+=2) | ||
642 | { | ||
643 | hInfo->channel_position[i] = BACK_CHANNEL_LEFT; | ||
644 | hInfo->channel_position[i+1] = BACK_CHANNEL_RIGHT; | ||
645 | } | ||
646 | } else { | ||
647 | hInfo->num_front_channels = ch1; | ||
648 | hInfo->num_back_channels = ch1 + 1; | ||
649 | for (i = 0; i < ch1; i+=2) | ||
650 | { | ||
651 | hInfo->channel_position[i] = FRONT_CHANNEL_LEFT; | ||
652 | hInfo->channel_position[i+1] = FRONT_CHANNEL_RIGHT; | ||
653 | } | ||
654 | for (i = ch1; i < ch-1; i+=2) | ||
655 | { | ||
656 | hInfo->channel_position[i] = BACK_CHANNEL_LEFT; | ||
657 | hInfo->channel_position[i+1] = BACK_CHANNEL_RIGHT; | ||
658 | } | ||
659 | hInfo->channel_position[ch-1] = BACK_CHANNEL_CENTER; | ||
660 | } | ||
661 | } else { | ||
662 | uint8_t ch1 = (ch)/2; | ||
663 | hInfo->num_front_channels = ch1; | ||
664 | hInfo->num_back_channels = ch1; | ||
665 | if (ch1 & 1) | ||
666 | { | ||
667 | hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; | ||
668 | for (i = 1; i <= ch1; i+=2) | ||
669 | { | ||
670 | hInfo->channel_position[i] = FRONT_CHANNEL_LEFT; | ||
671 | hInfo->channel_position[i+1] = FRONT_CHANNEL_RIGHT; | ||
672 | } | ||
673 | for (i = ch1+1; i < ch-1; i+=2) | ||
674 | { | ||
675 | hInfo->channel_position[i] = BACK_CHANNEL_LEFT; | ||
676 | hInfo->channel_position[i+1] = BACK_CHANNEL_RIGHT; | ||
677 | } | ||
678 | hInfo->channel_position[ch-1] = BACK_CHANNEL_CENTER; | ||
679 | } else { | ||
680 | for (i = 0; i < ch1; i+=2) | ||
681 | { | ||
682 | hInfo->channel_position[i] = FRONT_CHANNEL_LEFT; | ||
683 | hInfo->channel_position[i+1] = FRONT_CHANNEL_RIGHT; | ||
684 | } | ||
685 | for (i = ch1; i < ch; i+=2) | ||
686 | { | ||
687 | hInfo->channel_position[i] = BACK_CHANNEL_LEFT; | ||
688 | hInfo->channel_position[i+1] = BACK_CHANNEL_RIGHT; | ||
689 | } | ||
690 | } | ||
691 | } | ||
692 | hInfo->num_lfe_channels = hDecoder->has_lfe; | ||
693 | for (i = ch; i < hDecoder->fr_channels; i++) | ||
694 | { | ||
695 | hInfo->channel_position[i] = LFE_CHANNEL; | ||
696 | } | ||
697 | } | ||
698 | break; | ||
699 | } | ||
700 | } | ||
701 | } | ||
702 | |||
703 | void* NEAACDECAPI NeAACDecDecode(NeAACDecHandle hDecoder, | ||
704 | NeAACDecFrameInfo *hInfo, | ||
705 | uint8_t *buffer, uint32_t buffer_size) | ||
706 | { | ||
707 | return aac_frame_decode(hDecoder, hInfo, buffer, buffer_size, NULL, 0); | ||
708 | } | ||
709 | |||
710 | void* NEAACDECAPI NeAACDecDecode2(NeAACDecHandle hDecoder, | ||
711 | NeAACDecFrameInfo *hInfo, | ||
712 | uint8_t *buffer, uint32_t buffer_size, | ||
713 | void **sample_buffer, uint32_t sample_buffer_size) | ||
714 | { | ||
715 | if ((sample_buffer == NULL) || (sample_buffer_size == 0)) | ||
716 | { | ||
717 | hInfo->error = 27; | ||
718 | return NULL; | ||
719 | } | ||
720 | |||
721 | return aac_frame_decode(hDecoder, hInfo, buffer, buffer_size, | ||
722 | sample_buffer, sample_buffer_size); | ||
723 | } | ||
724 | |||
725 | static void* aac_frame_decode(NeAACDecHandle hDecoder, NeAACDecFrameInfo *hInfo, | ||
726 | uint8_t *buffer, uint32_t buffer_size, | ||
727 | void **sample_buffer2, uint32_t sample_buffer_size) | ||
728 | { | ||
729 | uint8_t channels = 0; | ||
730 | uint8_t output_channels = 0; | ||
731 | bitfile ld; | ||
732 | uint32_t bitsconsumed; | ||
733 | uint16_t frame_len; | ||
734 | void *sample_buffer; | ||
735 | |||
736 | #ifdef PROFILE | ||
737 | int64_t count = faad_get_ts(); | ||
738 | #endif | ||
739 | |||
740 | /* safety checks */ | ||
741 | if ((hDecoder == NULL) || (hInfo == NULL) || (buffer == NULL)) | ||
742 | { | ||
743 | return NULL; | ||
744 | } | ||
745 | |||
746 | #if 0 | ||
747 | printf("%d\n", buffer_size*8); | ||
748 | #endif | ||
749 | |||
750 | frame_len = hDecoder->frameLength; | ||
751 | |||
752 | |||
753 | memset(hInfo, 0, sizeof(NeAACDecFrameInfo)); | ||
754 | memset(hDecoder->internal_channel, 0, MAX_CHANNELS*sizeof(hDecoder->internal_channel[0])); | ||
755 | |||
756 | /* initialize the bitstream */ | ||
757 | faad_initbits(&ld, buffer, buffer_size); | ||
758 | |||
759 | #if 0 | ||
760 | { | ||
761 | int i; | ||
762 | for (i = 0; i < ((buffer_size+3)>>2); i++) | ||
763 | { | ||
764 | uint8_t *buf; | ||
765 | uint32_t temp = 0; | ||
766 | buf = faad_getbitbuffer(&ld, 32); | ||
767 | //temp = getdword((void*)buf); | ||
768 | temp = *((uint32_t*)buf); | ||
769 | printf("0x%.8X\n", temp); | ||
770 | free(buf); | ||
771 | } | ||
772 | faad_endbits(&ld); | ||
773 | faad_initbits(&ld, buffer, buffer_size); | ||
774 | } | ||
775 | #endif | ||
776 | |||
777 | #ifdef DRM | ||
778 | if (hDecoder->object_type == DRM_ER_LC) | ||
779 | { | ||
780 | /* We do not support stereo right now */ | ||
781 | if (0) //(hDecoder->channelConfiguration == 2) | ||
782 | { | ||
783 | hInfo->error = 8; // Throw CRC error | ||
784 | goto error; | ||
785 | } | ||
786 | |||
787 | faad_getbits(&ld, 8 | ||
788 | DEBUGVAR(1,1,"NeAACDecDecode(): skip CRC")); | ||
789 | } | ||
790 | #endif | ||
791 | |||
792 | if (hDecoder->adts_header_present) | ||
793 | { | ||
794 | adts_header adts; | ||
795 | |||
796 | adts.old_format = hDecoder->config.useOldADTSFormat; | ||
797 | if ((hInfo->error = adts_frame(&adts, &ld)) > 0) | ||
798 | goto error; | ||
799 | |||
800 | /* MPEG2 does byte_alignment() here, | ||
801 | * but ADTS header is always multiple of 8 bits in MPEG2 | ||
802 | * so not needed to actually do it. | ||
803 | */ | ||
804 | } | ||
805 | |||
806 | #ifdef ANALYSIS | ||
807 | dbg_count = 0; | ||
808 | #endif | ||
809 | |||
810 | /* decode the complete bitstream */ | ||
811 | #ifdef SCALABLE_DEC | ||
812 | if ((hDecoder->object_type == 6) || (hDecoder->object_type == DRM_ER_LC)) | ||
813 | { | ||
814 | aac_scalable_main_element(hDecoder, hInfo, &ld, &hDecoder->pce, hDecoder->drc); | ||
815 | } else { | ||
816 | #endif | ||
817 | raw_data_block(hDecoder, hInfo, &ld, &hDecoder->pce, hDecoder->drc); | ||
818 | #ifdef SCALABLE_DEC | ||
819 | } | ||
820 | #endif | ||
821 | |||
822 | channels = hDecoder->fr_channels; | ||
823 | |||
824 | if (hInfo->error > 0) | ||
825 | goto error; | ||
826 | |||
827 | /* safety check */ | ||
828 | if (channels == 0 || channels > MAX_CHANNELS) | ||
829 | { | ||
830 | /* invalid number of channels */ | ||
831 | hInfo->error = 12; | ||
832 | goto error; | ||
833 | } | ||
834 | |||
835 | /* no more bit reading after this */ | ||
836 | bitsconsumed = faad_get_processed_bits(&ld); | ||
837 | hInfo->bytesconsumed = bit2byte(bitsconsumed); | ||
838 | if (ld.error) | ||
839 | { | ||
840 | hInfo->error = 14; | ||
841 | goto error; | ||
842 | } | ||
843 | faad_endbits(&ld); | ||
844 | |||
845 | |||
846 | if (!hDecoder->adts_header_present && !hDecoder->adif_header_present) | ||
847 | { | ||
848 | if (hDecoder->channelConfiguration == 0) | ||
849 | hDecoder->channelConfiguration = channels; | ||
850 | |||
851 | if (channels == 8) /* 7.1 */ | ||
852 | hDecoder->channelConfiguration = 7; | ||
853 | if (channels == 7) /* not a standard channelConfiguration */ | ||
854 | hDecoder->channelConfiguration = 0; | ||
855 | } | ||
856 | |||
857 | if ((channels == 5 || channels == 6) && hDecoder->config.downMatrix) | ||
858 | { | ||
859 | hDecoder->downMatrix = 1; | ||
860 | output_channels = 2; | ||
861 | } else { | ||
862 | output_channels = channels; | ||
863 | } | ||
864 | |||
865 | #if (defined(PS_DEC) || defined(DRM_PS)) | ||
866 | hDecoder->upMatrix = 0; | ||
867 | /* check if we have a mono file */ | ||
868 | if (output_channels == 1) | ||
869 | { | ||
870 | /* upMatrix to 2 channels for implicit signalling of PS */ | ||
871 | hDecoder->upMatrix = 1; | ||
872 | output_channels = 2; | ||
873 | } | ||
874 | #endif | ||
875 | |||
876 | /* Make a channel configuration based on either a PCE or a channelConfiguration */ | ||
877 | create_channel_config(hDecoder, hInfo); | ||
878 | |||
879 | /* number of samples in this frame */ | ||
880 | hInfo->samples = frame_len*output_channels; | ||
881 | /* number of channels in this frame */ | ||
882 | hInfo->channels = output_channels; | ||
883 | /* samplerate */ | ||
884 | hInfo->samplerate = get_sample_rate(hDecoder->sf_index); | ||
885 | /* object type */ | ||
886 | hInfo->object_type = hDecoder->object_type; | ||
887 | /* sbr */ | ||
888 | hInfo->sbr = NO_SBR; | ||
889 | /* header type */ | ||
890 | hInfo->header_type = RAW; | ||
891 | if (hDecoder->adif_header_present) | ||
892 | hInfo->header_type = ADIF; | ||
893 | if (hDecoder->adts_header_present) | ||
894 | hInfo->header_type = ADTS; | ||
895 | #if (defined(PS_DEC) || defined(DRM_PS)) | ||
896 | hInfo->ps = hDecoder->ps_used_global; | ||
897 | #endif | ||
898 | |||
899 | /* check if frame has channel elements */ | ||
900 | if (channels == 0) | ||
901 | { | ||
902 | hDecoder->frame++; | ||
903 | return NULL; | ||
904 | } | ||
905 | |||
906 | /* allocate the buffer for the final samples */ | ||
907 | if ((hDecoder->sample_buffer == NULL) || | ||
908 | (hDecoder->alloced_channels != output_channels)) | ||
909 | { | ||
910 | static const uint8_t str[] = { sizeof(int16_t), sizeof(int32_t), sizeof(int32_t), | ||
911 | sizeof(float32_t), sizeof(double), sizeof(int16_t), sizeof(int16_t), | ||
912 | sizeof(int16_t), sizeof(int16_t), 0, 0, 0 | ||
913 | }; | ||
914 | uint8_t stride = str[hDecoder->config.outputFormat-1]; | ||
915 | #ifdef SBR_DEC | ||
916 | if (((hDecoder->sbr_present_flag == 1)&&(!hDecoder->downSampledSBR)) || (hDecoder->forceUpSampling == 1)) | ||
917 | { | ||
918 | stride = 2 * stride; | ||
919 | } | ||
920 | #endif | ||
921 | /* check if we want to use internal sample_buffer */ | ||
922 | if (sample_buffer_size == 0) | ||
923 | { | ||
924 | if (hDecoder->sample_buffer) | ||
925 | faad_free(hDecoder->sample_buffer); | ||
926 | hDecoder->sample_buffer = NULL; | ||
927 | hDecoder->sample_buffer = faad_malloc(frame_len*output_channels*stride); | ||
928 | } else if (sample_buffer_size < frame_len*output_channels*stride) { | ||
929 | /* provided sample buffer is not big enough */ | ||
930 | hInfo->error = 27; | ||
931 | return NULL; | ||
932 | } | ||
933 | hDecoder->alloced_channels = output_channels; | ||
934 | } | ||
935 | |||
936 | if (sample_buffer_size == 0) | ||
937 | { | ||
938 | sample_buffer = hDecoder->sample_buffer; | ||
939 | } else { | ||
940 | sample_buffer = *sample_buffer2; | ||
941 | } | ||
942 | |||
943 | #ifdef SBR_DEC | ||
944 | if ((hDecoder->sbr_present_flag == 1) || (hDecoder->forceUpSampling == 1)) | ||
945 | { | ||
946 | uint8_t ele; | ||
947 | |||
948 | /* this data is different when SBR is used or when the data is upsampled */ | ||
949 | if (!hDecoder->downSampledSBR) | ||
950 | { | ||
951 | frame_len *= 2; | ||
952 | hInfo->samples *= 2; | ||
953 | hInfo->samplerate *= 2; | ||
954 | } | ||
955 | |||
956 | /* check if every element was provided with SBR data */ | ||
957 | for (ele = 0; ele < hDecoder->fr_ch_ele; ele++) | ||
958 | { | ||
959 | if (hDecoder->sbr[ele] == NULL) | ||
960 | { | ||
961 | hInfo->error = 25; | ||
962 | goto error; | ||
963 | } | ||
964 | } | ||
965 | |||
966 | /* sbr */ | ||
967 | if (hDecoder->sbr_present_flag == 1) | ||
968 | { | ||
969 | hInfo->object_type = HE_AAC; | ||
970 | hInfo->sbr = SBR_UPSAMPLED; | ||
971 | } else { | ||
972 | hInfo->sbr = NO_SBR_UPSAMPLED; | ||
973 | } | ||
974 | if (hDecoder->downSampledSBR) | ||
975 | { | ||
976 | hInfo->sbr = SBR_DOWNSAMPLED; | ||
977 | } | ||
978 | } | ||
979 | #endif | ||
980 | |||
981 | sample_buffer = output_to_PCM(hDecoder, hDecoder->time_out, sample_buffer, | ||
982 | output_channels, frame_len, hDecoder->config.outputFormat); | ||
983 | |||
984 | |||
985 | hDecoder->postSeekResetFlag = 0; | ||
986 | |||
987 | hDecoder->frame++; | ||
988 | #ifdef LD_DEC | ||
989 | if (hDecoder->object_type != LD) | ||
990 | { | ||
991 | #endif | ||
992 | if (hDecoder->frame <= 1) | ||
993 | hInfo->samples = 0; | ||
994 | #ifdef LD_DEC | ||
995 | } else { | ||
996 | /* LD encoders will give lower delay */ | ||
997 | if (hDecoder->frame <= 0) | ||
998 | hInfo->samples = 0; | ||
999 | } | ||
1000 | #endif | ||
1001 | |||
1002 | /* cleanup */ | ||
1003 | #ifdef ANALYSIS | ||
1004 | fflush(stdout); | ||
1005 | #endif | ||
1006 | |||
1007 | #ifdef PROFILE | ||
1008 | count = faad_get_ts() - count; | ||
1009 | hDecoder->cycles += count; | ||
1010 | #endif | ||
1011 | |||
1012 | return sample_buffer; | ||
1013 | |||
1014 | error: | ||
1015 | |||
1016 | faad_endbits(&ld); | ||
1017 | |||
1018 | /* cleanup */ | ||
1019 | #ifdef ANALYSIS | ||
1020 | fflush(stdout); | ||
1021 | #endif | ||
1022 | |||
1023 | return NULL; | ||
1024 | } | ||