shithub: aacdec

Download patch

ref: 4b4241830d669436bff595a1deaa5148f9562d79
parent: c12d8b8c3a448a01865b6b3f15b0452ea67b9a8f
author: menno <menno>
date: Wed Jul 9 07:53:07 EDT 2003

More multichannel support

--- a/frontend/audio.c
+++ b/frontend/audio.c
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: audio.c,v 1.14 2003/07/08 13:45:45 menno Exp $
+** $Id: audio.c,v 1.15 2003/07/09 11:53:07 menno Exp $
 **/
 
 #ifdef _WIN32
@@ -173,6 +173,106 @@
 
     *p++ = (unsigned char)(aufile->bits_per_sample >> 0);
     *p++ = (unsigned char)(aufile->bits_per_sample >> 8);
+
+    *p++ = 'd'; *p++ = 'a'; *p++ = 't'; *p++ = 'a';
+
+    word32 = data_size < MAXWAVESIZE ?
+        (unsigned long)data_size : (unsigned long)MAXWAVESIZE;
+    *p++ = (unsigned char)(word32 >>  0);
+    *p++ = (unsigned char)(word32 >>  8);
+    *p++ = (unsigned char)(word32 >> 16);
+    *p++ = (unsigned char)(word32 >> 24);
+
+    return fwrite(header, sizeof(header), 1, aufile->sndfile);
+}
+
+/* ??????? */
+static int write_wav_extensible_header(audio_file *aufile, long channelMask)
+{
+    unsigned char header[66];
+    unsigned char* p = header;
+    unsigned int bytes = (aufile->bits_per_sample + 7) / 8;
+    float data_size = (float)bytes * aufile->total_samples;
+    unsigned long word32;
+
+    *p++ = 'R'; *p++ = 'I'; *p++ = 'F'; *p++ = 'F';
+
+    word32 = (data_size + (66 - 8) < (float)MAXWAVESIZE) ?
+        (unsigned long)data_size + (66 - 8)  :  (unsigned long)MAXWAVESIZE;
+    *p++ = (unsigned char)(word32 >>  0);
+    *p++ = (unsigned char)(word32 >>  8);
+    *p++ = (unsigned char)(word32 >> 16);
+    *p++ = (unsigned char)(word32 >> 24);
+
+    *p++ = 'W'; *p++ = 'A'; *p++ = 'V'; *p++ = 'E';
+
+    *p++ = 'f'; *p++ = 'm'; *p++ = 't'; *p++ = ' ';
+
+    *p++ = 0x10; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
+
+    /* WAVE_FORMAT_EXTENSIBLE */
+    *p++ = 0xFE; *p++ = 0xFF;
+
+    *p++ = (unsigned char)(aufile->channels >> 0);
+    *p++ = (unsigned char)(aufile->channels >> 8);
+
+    word32 = (unsigned long)(aufile->samplerate + 0.5);
+    *p++ = (unsigned char)(word32 >>  0);
+    *p++ = (unsigned char)(word32 >>  8);
+    *p++ = (unsigned char)(word32 >> 16);
+    *p++ = (unsigned char)(word32 >> 24);
+
+    word32 = aufile->samplerate * bytes * aufile->channels;
+    *p++ = (unsigned char)(word32 >>  0);
+    *p++ = (unsigned char)(word32 >>  8);
+    *p++ = (unsigned char)(word32 >> 16);
+    *p++ = (unsigned char)(word32 >> 24);
+
+    word32 = bytes * aufile->channels;
+    *p++ = (unsigned char)(word32 >>  0);
+    *p++ = (unsigned char)(word32 >>  8);
+
+    *p++ = (unsigned char)(aufile->bits_per_sample >> 0);
+    *p++ = (unsigned char)(aufile->bits_per_sample >> 8);
+
+    /* cbSize */
+    *p++ = (unsigned char)(22);
+    *p++ = (unsigned char)(0);
+
+    /* WAVEFORMATEXTENSIBLE */
+
+    /* wValidBitsPerSample */
+    *p++ = (unsigned char)(aufile->bits_per_sample >> 0);
+    *p++ = (unsigned char)(aufile->bits_per_sample >> 8);
+
+    /* dwChannelMask */
+    word32 = channelMask;
+    *p++ = (unsigned char)(word32 >>  0);
+    *p++ = (unsigned char)(word32 >>  8);
+    *p++ = (unsigned char)(word32 >> 16);
+    *p++ = (unsigned char)(word32 >> 24);
+
+    /* SubFormat */
+    if (aufile->outputFormat == FAAD_FMT_FLOAT)
+    {
+        /* KSDATAFORMAT_SUBTYPE_IEEE_FLOAT: 00000003-0000-0010-8000-00aa00389b71 */
+//        /*??*/ *p++ = 0x00;
+//        /*??*/ *p++ = 0x00;
+        *p++ = 0x03;
+        *p++ = 0x00;
+        *p++ = 0x00; *p++ = 0x00; *p++ = 0x10; *p++ = 0x00; *p++ = 0x80; *p++ = 0x00;
+        *p++ = 0x00; *p++ = 0xaa; *p++ = 0x00; *p++ = 0x38; *p++ = 0x9b; *p++ = 0x71;
+    } else {
+        /* KSDATAFORMAT_SUBTYPE_PCM: 00000001-0000-0010-8000-00aa00389b71 */
+//        /*??*/ *p++ = 0x00;
+//        /*??*/ *p++ = 0x00;
+        *p++ = 0x01;
+        *p++ = 0x00;
+        *p++ = 0x00; *p++ = 0x00; *p++ = 0x10; *p++ = 0x00; *p++ = 0x80; *p++ = 0x00;
+        *p++ = 0x00; *p++ = 0xaa; *p++ = 0x00; *p++ = 0x38; *p++ = 0x9b; *p++ = 0x71;
+    }
+
+    /* end WAVEFORMATEXTENSIBLE */
 
     *p++ = 'd'; *p++ = 'a'; *p++ = 't'; *p++ = 'a';
 
--- a/frontend/main.c
+++ b/frontend/main.c
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: main.c,v 1.38 2003/07/08 13:45:45 menno Exp $
+** $Id: main.c,v 1.39 2003/07/09 11:53:07 menno Exp $
 **/
 
 #ifdef _WIN32
@@ -40,8 +40,8 @@
 #endif
 
 #define MAX_CHANNELS 6 /* make this higher to support files with
-
                           more channels */
+
 /* FAAD file buffering routines */
 typedef struct {
     long bytes_into_buffer;
@@ -141,7 +141,7 @@
         }
     }
 
-    frames_per_sec = (float)samplerate/1024.0;
+    frames_per_sec = (float)samplerate/1024.0f;
     if (frames != 0)
         bytes_per_frame = (float)t_framelength/(float)(frames*1000);
     else
@@ -155,7 +155,49 @@
     return 1;
 }
 
+char *position2string(int position)
+{
+    switch (position)
+    {
+    case FRONT_CHANNEL_CENTER: return "Center front";
+    case FRONT_CHANNEL_LEFT:   return "Left front";
+    case FRONT_CHANNEL_RIGHT:  return "Right front";
+    case SIDE_CHANNEL_LEFT:    return "Left side";
+    case SIDE_CHANNEL_RIGHT:   return "Right side";
+    case BACK_CHANNEL_LEFT:    return "Left back";
+    case BACK_CHANNEL_RIGHT:   return "Right back";
+    case BACK_CHANNEL_CENTER:  return "Center back";
+    case LFE_CHANNEL:          return "LFE";
+    case UNKNOWN_CHANNEL:      return "Unknown";
+    default: return "";
+    }
 
+    return "";
+}
+
+void print_channel_info(faacDecFrameInfo *frameInfo)
+{
+    /* print some channel info */
+    int i;
+
+    printf("  ---------------------\n");
+    if (frameInfo->num_lfe_channels > 0)
+    {
+        printf(" | Config: %2d.%d Ch     |\n", frameInfo->channels-frameInfo->num_lfe_channels, frameInfo->num_lfe_channels);
+    } else {
+        printf(" | Config: %2d Ch       |\n", frameInfo->channels);
+    }
+    printf("  ---------------------\n");
+    printf(" | Ch |    Position    |\n");
+    printf("  ---------------------\n");
+    for (i = 0; i < frameInfo->channels; i++)
+    {
+        printf(" | %.2d | %-14s |\n", i, position2string((int)frameInfo->channel_position[i]));
+    }
+    printf("  ---------------------\n");
+    printf("\n");
+}
+
 /* globals */
 char *progName;
 
@@ -258,7 +300,7 @@
     b.bytes_consumed = 0;
     b.file_offset = 0;
 
-    if (bread != 768*6)
+    if (bread != FAAD_MIN_STREAMSIZE*MAX_CHANNELS)
         b.at_eof = 1;
 
     tagsize = 0;
@@ -312,10 +354,10 @@
         length = (float)fileread;
         if (length != 0)
         {
-            length = ((float)length*8.)/((float)bitrate) + 0.5;
+            length = ((float)length*8.f)/((float)bitrate) + 0.5f;
         }
 
-        bitrate = (int)((float)bitrate/1000.0 + 0.5);
+        bitrate = (int)((float)bitrate/1000.0f + 0.5f);
 
         header_type = 2;
     }
@@ -375,20 +417,13 @@
                 faacDecGetErrorMessage(frameInfo.error));
         }
 
-        percent = min((int)(b.file_offset*100)/fileread, 100);
-        if (percent > old_percent)
-        {
-            old_percent = percent;
-            sprintf(percents, "%d%% decoding %s.", percent, aacfile);
-            fprintf(stderr, "%s\r", percents);
-#ifdef _WIN32
-            SetConsoleTitle(percents);
-#endif
-        }
-
         /* open the sound file now that the number of channels are known */
         if (first_time && !frameInfo.error)
         {
+            /* print some channel info */
+            print_channel_info(&frameInfo);
+
+            /* open output file */
             if (!to_stdout)
             {
                 aufile = open_audio_file(sndfile, frameInfo.samplerate, frameInfo.channels,
@@ -408,6 +443,17 @@
             first_time = 0;
         }
 
+        percent = min((int)(b.file_offset*100)/fileread, 100);
+        if (percent > old_percent)
+        {
+            old_percent = percent;
+            sprintf(percents, "%d%% decoding %s.", percent, aacfile);
+            fprintf(stderr, "%s\r", percents);
+#ifdef _WIN32
+            SetConsoleTitle(percents);
+#endif
+        }
+
         if ((frameInfo.error == 0) && (frameInfo.samples > 0))
         {
             write_audio_file(aufile, sample_buffer, frameInfo.samples);
@@ -591,20 +637,13 @@
 
         if (buffer) free(buffer);
 
-        percent = min((int)(sampleId*100)/numSamples, 100);
-        if (percent > old_percent)
-        {
-            old_percent = percent;
-            sprintf(percents, "%d%% decoding %s.", percent, mp4file);
-            fprintf(stderr, "%s\r", percents);
-#ifdef _WIN32
-            SetConsoleTitle(percents);
-#endif
-        }
-
         /* open the sound file now that the number of channels are known */
         if (first_time && !frameInfo.error)
         {
+            /* print some channel info */
+            print_channel_info(&frameInfo);
+
+            /* open output file */
             if(!to_stdout)
             {
                 aufile = open_audio_file(sndfile, frameInfo.samplerate, frameInfo.channels,
@@ -623,6 +662,17 @@
                 return 0;
             }
             first_time = 0;
+        }
+
+        percent = min((int)(sampleId*100)/numSamples, 100);
+        if (percent > old_percent)
+        {
+            old_percent = percent;
+            sprintf(percents, "%d%% decoding %s.", percent, mp4file);
+            fprintf(stderr, "%s\r", percents);
+#ifdef _WIN32
+            SetConsoleTitle(percents);
+#endif
         }
 
         if ((frameInfo.error == 0) && (frameInfo.samples > 0))
--- a/include/faad.h
+++ b/include/faad.h
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: faad.h,v 1.23 2003/07/08 13:45:45 menno Exp $
+** $Id: faad.h,v 1.24 2003/07/09 11:53:07 menno Exp $
 **/
 
 #ifndef __AACDEC_H__
@@ -83,7 +83,7 @@
 #define BACK_CHANNEL_RIGHT   (7)
 #define BACK_CHANNEL_CENTER  (8)
 #define LFE_CHANNEL          (9)
-#define UNKNOWN_CHANNEL      (10)
+#define UNKNOWN_CHANNEL      (0)
 
 
 /* A decode call can eat up to FAAD_MIN_STREAMSIZE bytes per decoded channel,
--- a/libfaad/bits.h
+++ b/libfaad/bits.h
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: bits.h,v 1.19 2003/07/08 13:45:45 menno Exp $
+** $Id: bits.h,v 1.20 2003/07/09 11:53:07 menno Exp $
 **/
 
 #ifndef __BITS_H__
@@ -162,7 +162,7 @@
         return (uint8_t)faad_getbits(ld, 1 DEBUGVAR(print,var,dbg));
 
     ld->bits_left--;
-    r = (ld->bufa >> ld->bits_left) & 1;
+    r = (uint8_t)((ld->bufa >> ld->bits_left) & 1);
 
     return r;
 }
--- a/libfaad/decoder.c
+++ b/libfaad/decoder.c
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: decoder.c,v 1.59 2003/07/08 13:45:45 menno Exp $
+** $Id: decoder.c,v 1.60 2003/07/09 11:53:07 menno Exp $
 **/
 
 #include "common.h"
@@ -257,11 +257,18 @@
     }
 
     /* decode the audio specific config */
-    rc = AudioSpecificConfig(pBuffer, SizeOfDecoderSpecificInfo, &mp4ASC);
+    rc = AudioSpecificConfig2(pBuffer, SizeOfDecoderSpecificInfo, &mp4ASC,
+        &(hDecoder->pce));
 
     /* copy the relevant info to the decoder handle */
     *samplerate = mp4ASC.samplingFrequency;
-    *channels = mp4ASC.channelsConfiguration;
+    if (mp4ASC.channelsConfiguration)
+    {
+        *channels = mp4ASC.channelsConfiguration;
+    } else {
+        *channels = hDecoder->pce.channels;
+        hDecoder->pce_set = 1;
+    }
     hDecoder->sf_index = mp4ASC.samplingFrequencyIndex;
     hDecoder->object_type = mp4ASC.objectTypeIndex;
     hDecoder->aacSectionDataResilienceFlag = mp4ASC.aacSectionDataResilienceFlag;
@@ -274,7 +281,7 @@
     {
         return rc;
     }
-    hDecoder->channelConfiguration = *channels;
+    hDecoder->channelConfiguration = mp4ASC.channelsConfiguration;
     if (mp4ASC.frameLengthFlag)
         hDecoder->frameLength = 960;
 
@@ -486,6 +493,80 @@
             hInfo->channel_position[7] = LFE_CHANNEL;
             break;
         default: /* channelConfiguration == 0 || channelConfiguration > 7 */
+            {
+                uint8_t i;
+                uint8_t ch = hDecoder->fr_channels - hDecoder->has_lfe;
+                if (ch & 1) /* there's either a center front or a center back channel */
+                {
+                    uint8_t ch1 = (ch-1)/2;
+                    _assert(!(ch1&1));
+                    if (hDecoder->first_syn_ele == ID_SCE)
+                    {
+                        hInfo->num_front_channels = ch1 + 1;
+                        hInfo->num_back_channels = ch1;
+                        hInfo->channel_position[0] = FRONT_CHANNEL_CENTER;
+                        for (i = 1; i <= ch1; i+=2)
+                        {
+                            hInfo->channel_position[i] = FRONT_CHANNEL_LEFT;
+                            hInfo->channel_position[i+1] = FRONT_CHANNEL_RIGHT;
+                        }
+                        for (i = ch1+1; i < ch; i+=2)
+                        {
+                            hInfo->channel_position[i] = BACK_CHANNEL_LEFT;
+                            hInfo->channel_position[i+1] = BACK_CHANNEL_RIGHT;
+                        }
+                    } else {
+                        hInfo->num_front_channels = ch1;
+                        hInfo->num_back_channels = ch1 + 1;
+                        for (i = 0; i < ch1; i+=2)
+                        {
+                            hInfo->channel_position[i] = FRONT_CHANNEL_LEFT;
+                            hInfo->channel_position[i+1] = FRONT_CHANNEL_RIGHT;
+                        }
+                        for (i = ch1; i < ch-1; i+=2)
+                        {
+                            hInfo->channel_position[i] = BACK_CHANNEL_LEFT;
+                            hInfo->channel_position[i+1] = BACK_CHANNEL_RIGHT;
+                        }
+                        hInfo->channel_position[ch-1] = BACK_CHANNEL_CENTER;
+                    }
+                } else {
+                    uint8_t ch1 = (ch)/2;
+                    hInfo->num_front_channels = ch1;
+                    hInfo->num_back_channels = ch1;
+                    if (ch1 & 1)
+                    {
+                        hInfo->channel_position[0] = FRONT_CHANNEL_CENTER;
+                        for (i = 1; i <= ch1; i+=2)
+                        {
+                            hInfo->channel_position[i] = FRONT_CHANNEL_LEFT;
+                            hInfo->channel_position[i+1] = FRONT_CHANNEL_RIGHT;
+                        }
+                        for (i = ch1+1; i < ch-1; i+=2)
+                        {
+                            hInfo->channel_position[i] = BACK_CHANNEL_LEFT;
+                            hInfo->channel_position[i+1] = BACK_CHANNEL_RIGHT;
+                        }
+                        hInfo->channel_position[ch-1] = BACK_CHANNEL_CENTER;
+                    } else {
+                        for (i = 0; i < ch1; i+=2)
+                        {
+                            hInfo->channel_position[i] = FRONT_CHANNEL_LEFT;
+                            hInfo->channel_position[i+1] = FRONT_CHANNEL_RIGHT;
+                        }
+                        for (i = ch1; i < ch; i+=2)
+                        {
+                            hInfo->channel_position[i] = BACK_CHANNEL_LEFT;
+                            hInfo->channel_position[i+1] = BACK_CHANNEL_RIGHT;
+                        }
+                    }
+                }
+                hInfo->num_lfe_channels = hDecoder->has_lfe;
+                for (i = ch; i < hDecoder->fr_channels; i++)
+                {
+                    hInfo->channel_position[i] = LFE_CHANNEL;
+                }
+            }
             break;
         }
     }
--- a/libfaad/decoder.h
+++ b/libfaad/decoder.h
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: decoder.h,v 1.24 2003/07/08 13:45:45 menno Exp $
+** $Id: decoder.h,v 1.25 2003/07/09 11:53:07 menno Exp $
 **/
 
 #ifndef __DECODER_H__
@@ -74,7 +74,7 @@
 #define BACK_CHANNEL_RIGHT   (7)
 #define BACK_CHANNEL_CENTER  (8)
 #define LFE_CHANNEL          (9)
-#define UNKNOWN_CHANNEL      (10)
+#define UNKNOWN_CHANNEL      (0)
 
 int8_t* FAADAPI faacDecGetErrorMessage(uint8_t errcode);
 
--- a/libfaad/mp4.c
+++ b/libfaad/mp4.c
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: mp4.c,v 1.15 2003/06/23 15:21:19 menno Exp $
+** $Id: mp4.c,v 1.16 2003/07/09 11:53:07 menno Exp $
 **/
 
 #include "common.h"
@@ -105,6 +105,14 @@
                                    uint32_t buffer_size,
                                    mp4AudioSpecificConfig *mp4ASC)
 {
+    return AudioSpecificConfig2(pBuffer, buffer_size, mp4ASC, NULL);
+}
+
+int8_t FAADAPI AudioSpecificConfig2(uint8_t *pBuffer,
+                                    uint32_t buffer_size,
+                                    mp4AudioSpecificConfig *mp4ASC,
+                                    program_config *pce)
+{
     bitfile ld;
     int8_t result = 0;
 
@@ -152,11 +160,11 @@
         mp4ASC->objectTypeIndex == 3 || mp4ASC->objectTypeIndex == 4 ||
         mp4ASC->objectTypeIndex == 6 || mp4ASC->objectTypeIndex == 7)
     {
-        result = GASpecificConfig(&ld, mp4ASC);
+        result = GASpecificConfig(&ld, mp4ASC, pce);
 
 #ifdef ERROR_RESILIENCE
     } else if (mp4ASC->objectTypeIndex >= ER_OBJECT_START) { /* ER */
-        result = GASpecificConfig(&ld, mp4ASC);
+        result = GASpecificConfig(&ld, mp4ASC, pce);
         mp4ASC->epConfig = (uint8_t)faad_getbits(&ld, 2
             DEBUGVAR(1,143,"parse_audio_decoder_specific_info(): epConfig"));
 
--- a/libfaad/mp4.h
+++ b/libfaad/mp4.h
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: mp4.h,v 1.7 2003/02/09 20:42:49 menno Exp $
+** $Id: mp4.h,v 1.8 2003/07/09 11:53:07 menno Exp $
 **/
 
 #ifndef __MP4_H__
@@ -31,6 +31,11 @@
 int8_t FAADAPI AudioSpecificConfig(uint8_t *pBuffer,
                                    uint32_t buffer_size,
                                    mp4AudioSpecificConfig *mp4ASC);
+
+int8_t FAADAPI AudioSpecificConfig2(uint8_t *pBuffer,
+                                    uint32_t buffer_size,
+                                    mp4AudioSpecificConfig *mp4ASC,
+                                    program_config *pce);
 
 #ifdef __cplusplus
 }
--- a/libfaad/structs.h
+++ b/libfaad/structs.h
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: structs.h,v 1.7 2003/07/08 13:45:45 menno Exp $
+** $Id: structs.h,v 1.8 2003/07/09 11:53:07 menno Exp $
 **/
 
 #ifndef __STRUCTS_H__
@@ -348,6 +348,9 @@
 
     uint32_t frame;
 
+    uint8_t first_syn_ele;
+    uint8_t last_syn_ele;
+    uint8_t has_lfe;
     uint8_t fr_channels;
     uint8_t fr_ch_ele;
 
--- a/libfaad/syntax.c
+++ b/libfaad/syntax.c
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: syntax.c,v 1.47 2003/07/08 13:45:45 menno Exp $
+** $Id: syntax.c,v 1.48 2003/07/09 11:53:07 menno Exp $
 **/
 
 /*
@@ -43,7 +43,8 @@
 
 
 /* Table 4.4.1 */
-int8_t GASpecificConfig(bitfile *ld, mp4AudioSpecificConfig *mp4ASC)
+int8_t GASpecificConfig(bitfile *ld, mp4AudioSpecificConfig *mp4ASC,
+                        program_config *pce_out)
 {
     program_config pce;
 
@@ -63,10 +64,15 @@
     if (mp4ASC->channelsConfiguration == 0)
     {
         program_config_element(&pce, ld);
-        mp4ASC->channelsConfiguration = pce.channels;
+        //mp4ASC->channelsConfiguration = pce.channels;
 
+        if (pce_out != NULL)
+            memcpy(pce_out, &pce, sizeof(program_config));
+
+        /*
         if (pce.num_valid_cc_elements)
             return -3;
+        */
     }
 
 #ifdef ERROR_RESILIENCE
@@ -256,12 +262,12 @@
     element *ele;
     uint8_t channels = hDecoder->fr_channels;
 
-    if (channels+1 >= MAX_CHANNELS)
+    if (channels+1 > MAX_CHANNELS)
     {
         hInfo->error = 12;
         return NULL;
     }
-    if (hDecoder->fr_ch_ele+1 >= MAX_SYNTAX_ELEMENTS)
+    if (hDecoder->fr_ch_ele+1 > MAX_SYNTAX_ELEMENTS)
     {
         hInfo->error = 13;
         return NULL;
@@ -301,12 +307,12 @@
     element *ele;
     uint8_t channels = hDecoder->fr_channels;
 
-    if (channels+2 >= MAX_CHANNELS)
+    if (channels+2 > MAX_CHANNELS)
     {
         hInfo->error = 12;
         return NULL;
     }
-    if (hDecoder->fr_ch_ele+1 >= MAX_SYNTAX_ELEMENTS)
+    if (hDecoder->fr_ch_ele+1 > MAX_SYNTAX_ELEMENTS)
     {
         hInfo->error = 13;
         return NULL;
@@ -351,6 +357,8 @@
 
     hDecoder->fr_channels = 0;
     hDecoder->fr_ch_ele = 0;
+    hDecoder->first_syn_ele = 25;
+    hDecoder->has_lfe = 0;
 
 #ifdef ERROR_RESILIENCE
     if (hDecoder->object_type < ER_OBJECT_START)
@@ -362,7 +370,8 @@
         {
             switch (id_syn_ele) {
             case ID_SCE:
-            case ID_LFE:
+                if (hDecoder->first_syn_ele == 25) hDecoder->first_syn_ele = id_syn_ele;
+                hDecoder->last_syn_ele = id_syn_ele;
                 elements[ch_ele++] = decode_sce_lfe(hDecoder,
                     hInfo, ld, spec_data, spec_coef, id_syn_ele);
                 if (hInfo->error > 0)
@@ -369,7 +378,16 @@
                     return elements;
                 break;
             case ID_CPE:
+                if (hDecoder->first_syn_ele == 25) hDecoder->first_syn_ele = id_syn_ele;
+                hDecoder->last_syn_ele = id_syn_ele;
                 elements[ch_ele++] = decode_cpe(hDecoder,
+                    hInfo, ld, spec_data, spec_coef, id_syn_ele);
+                if (hInfo->error > 0)
+                    return elements;
+                break;
+            case ID_LFE:
+                hDecoder->has_lfe++;
+                elements[ch_ele++] = decode_sce_lfe(hDecoder,
                     hInfo, ld, spec_data, spec_coef, id_syn_ele);
                 if (hInfo->error > 0)
                     return elements;
--- a/libfaad/syntax.h
+++ b/libfaad/syntax.h
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: syntax.h,v 1.30 2003/07/08 13:45:45 menno Exp $
+** $Id: syntax.h,v 1.31 2003/07/09 11:53:07 menno Exp $
 **/
 
 #ifndef __SYNTAX_H__
@@ -86,7 +86,8 @@
     12000, 11025, 8000
 };
 
-int8_t GASpecificConfig(bitfile *ld, mp4AudioSpecificConfig *mp4ASC);
+int8_t GASpecificConfig(bitfile *ld, mp4AudioSpecificConfig *mp4ASC,
+                        program_config *pce);
 
 uint8_t adts_frame(adts_header *adts, bitfile *ld);
 void get_adif_header(adif_header *adif, bitfile *ld);