Exemplo n.º 1
0
static gint
xmms_faad_get_framesize (xmms_xform_t *xform) {
	xmms_faad_data_t *data;
	const guchar *tmpbuf;
	gsize tmpbuflen;
	guchar *copy;
	mp4AudioSpecificConfig mp4ASC;

	g_return_val_if_fail (xform, 0);
	data = xmms_xform_private_data_get (xform);
	g_return_val_if_fail (data, 0);

	if (data->filetype != FAAD_TYPE_MP4) {
		return 0;
	}

	if (!xmms_xform_auxdata_get_bin (xform, "decoder_config", &tmpbuf,
	                                 &tmpbuflen)) {
		xmms_log_error ("ERROR: Cannot get AAC decoder config, but filetype is FAAD_TYPE_MP4!");
		return 0;
	}
	copy = g_memdup (tmpbuf, tmpbuflen);
	if ((signed char)NeAACDecAudioSpecificConfig (copy, tmpbuflen, &mp4ASC) < 0) {
		/* FIXME: That function ^^^ returns char. How can it signal errors when
		 * char is unsigned?!
		 */
		g_free (copy);
		XMMS_DBG ("ERROR: Could not get mp4ASC!");
		return 0;
	}
	g_free (copy);

	return ((mp4ASC.frameLengthFlag == 1) ? 960 : 1024)
	       * ((mp4ASC.sbr_present_flag == 1) ? 2 : 1);
}
Exemplo n.º 2
0
int GetAACTrack(mp4ff_t *infile)
{
    /* find AAC track */
    int i, rc;
    int numTracks = mp4ff_total_tracks(infile);

    for (i = 0; i < numTracks; i++)
    {
        unsigned char *buff = NULL;
        int buff_size = 0;
        mp4AudioSpecificConfig mp4ASC;

        mp4ff_get_decoder_config(infile, i, &buff, &buff_size);

        if (buff)
        {
            rc = NeAACDecAudioSpecificConfig(buff, buff_size, &mp4ASC);
            free(buff);

            if (rc < 0)
                continue;
            return i;
        }
    }

    /* can't decode this */
    return -1;
}
Exemplo n.º 3
0
bool TaudioCodecLibFAAD::init(const CMediaType &mt)
{
    dll = new Tdll(dllname, config);
    dll->loadFunction(NeAACDecOpen, "NeAACDecOpen");
    dll->loadFunction(NeAACDecClose, "NeAACDecClose");
    dll->loadFunction(NeAACDecInit2, "NeAACDecInit2");
    dll->loadFunction(NeAACDecAudioSpecificConfig, "NeAACDecAudioSpecificConfig");
    dll->loadFunction(NeAACDecDecode, "NeAACDecDecode");
    dll->loadFunction(NeAACDecGetErrorMessage, "NeAACDecGetErrorMessage");
    dll->loadFunction(NeAACDecGetCurrentConfiguration, "NeAACDecGetCurrentConfiguration");
    dll->loadFunction(NeAACDecSetConfiguration, "NeAACDecSetConfiguration");
    if (dll->ok) {
        m_decHandle = NeAACDecOpen();
        unsigned long SamplesPerSec = 0;
        unsigned char channels = 0;
        Textradata extradata(mt);
        if (NeAACDecInit2(m_decHandle, extradata.data, (unsigned long)extradata.size, &SamplesPerSec, &channels) < 0) {
            return false;
        }
        fmt.freq = SamplesPerSec;
        fmt.setChannels(channels);
        NeAACDecAudioSpecificConfig(extradata.data, (unsigned long)extradata.size, &info);
        NeAACDecConfigurationPtr c = NeAACDecGetCurrentConfiguration(m_decHandle);
        c->outputFormat = FAAD_FMT_FLOAT;
        fmt.sf = TsampleFormat::SF_FLOAT32;
        NeAACDecSetConfiguration(m_decHandle, c);
        inited = true;
        return true;
    } else {
        return false;
    }
}
Exemplo n.º 4
0
CAMLprim value ocaml_faad_mp4_find_aac_track(value m)
{
  CAMLparam1(m);
  mp4_t *mp = Mp4_val(m);

  int i, rc;
  int num_tracks;

  caml_enter_blocking_section();
  num_tracks = mp4ff_total_tracks(mp->ff);
  for (i = 0; i < num_tracks; i++) {
    unsigned char *buff = NULL;
    unsigned int buff_size = 0;
    mp4AudioSpecificConfig mp4ASC;

    mp4ff_get_decoder_config(mp->ff, i, &buff, &buff_size);

    if (buff)
    {
      rc = NeAACDecAudioSpecificConfig(buff, buff_size, &mp4ASC);
      free(buff);
      if (rc < 0)
        continue;
      caml_leave_blocking_section();
      CAMLreturn(Val_int(i));
    }
  }

  caml_leave_blocking_section();
  caml_raise_constant(*caml_named_value("ocaml_faad_exn_failed"));
}
Exemplo n.º 5
0
ReadStatus MP4Reader::parse() {
  mp4AudioSpecificConfig cfg;
  FXuchar* buffer;
  FXuint   size;
  FXint    ntracks;

  FXASSERT(handle==NULL);
  FXASSERT(packet);

  handle = mp4ff_open_read(&callback);
  if (handle==NULL)
    goto error;

  ntracks = mp4ff_total_tracks(handle);
  if (ntracks<=0)
    goto error;

  for (FXint i=0;i<ntracks;i++) {
    if ((mp4ff_get_decoder_config(handle,i,&buffer,&size)==0) && buffer && size) {
      if (NeAACDecAudioSpecificConfig(buffer,size,&cfg)==0) {

        af.set(AP_FORMAT_S16,mp4ff_get_sample_rate(handle,i),mp4ff_get_channel_count(handle,i));
        af.debug();

        if (size>packet->space()) {
          GM_DEBUG_PRINT("MP4 config buffer is too big for decoder packet");
          free(buffer);
          goto error;
          }

        track=i;
        frame=0;
        nframes=mp4ff_num_samples(handle,i);
        stream_length=mp4ff_get_track_duration(handle,i);


        packet->append(buffer,size);
        packet->flags|=AAC_FLAG_CONFIG|AAC_FLAG_FRAME;
        engine->decoder->post(new ConfigureEvent(af,Codec::AAC));

        send_meta();

        engine->decoder->post(packet);

        packet=NULL;
        flags|=FLAG_PARSED;
        free(buffer);
        return ReadOk;
        }
      free(buffer);
      }
    }

error:
  packet->unref();
  return ReadError;
  }
Exemplo n.º 6
0
static int
aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
    aac_info_t *info = (aac_info_t *)_info;

    info->file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
    if (!info->file) {
        return -1;
    }

    // probe
    float duration = -1;
    int samplerate = -1;
    int channels = -1;
    int totalsamples = -1;

    info->junk = deadbeef->junk_get_leading_size (info->file);
    if (!info->file->vfs->is_streaming ()) {
        if (info->junk >= 0) {
            deadbeef->fseek (info->file, info->junk, SEEK_SET);
        }
        else {
            info->junk = 0;
        }
    }
    else {
        deadbeef->fset_track (info->file, it);
    }

    info->mp4track = -1;
#if USE_MP4FF
    info->mp4reader.read = aac_fs_read;
    info->mp4reader.write = NULL;
    info->mp4reader.seek = aac_fs_seek;
    info->mp4reader.truncate = NULL;
    info->mp4reader.user_data = info;
#else
    info->mp4reader.open = aac_fs_open;
    info->mp4reader.seek = aac_fs_seek;
    info->mp4reader.read = aac_fs_read;
    info->mp4reader.write = NULL;
    info->mp4reader.close = aac_fs_close;
#endif

    if (!info->file->vfs->is_streaming ()) {
#ifdef USE_MP4FF
        trace ("aac_init: mp4ff_open_read %s\n", deadbeef->pl_find_meta (it, ":URI"));
        info->mp4file = mp4ff_open_read (&info->mp4reader);
        if (info->mp4file) {
            int ntracks = mp4ff_total_tracks (info->mp4file);
            if (ntracks > 0) {
                trace ("m4a container detected, ntracks=%d\n", ntracks);
                int i = -1;
                unsigned char*  buff = 0;
                unsigned int    buff_size = 0;
                for (i = 0; i < ntracks; i++) {
                    mp4AudioSpecificConfig mp4ASC;
                    mp4ff_get_decoder_config (info->mp4file, i, &buff, &buff_size);
                    if(buff){
                        int rc = AudioSpecificConfig(buff, buff_size, &mp4ASC);
                        if(rc < 0)
                            continue;
                        break;
                    }
                }
                trace ("mp4 probe-buffer size: %d\n", buff_size);

                if (i != ntracks && buff) 
                {
                    trace ("mp4 track: %d\n", i);
                    int samples = mp4ff_num_samples(info->mp4file, i);
                    info->mp4samples = samples;
                    info->mp4track = i;

                    // init mp4 decoding
                    info->dec = NeAACDecOpen ();
                    unsigned long srate;
                    unsigned char ch;
                    if (NeAACDecInit2(info->dec, buff, buff_size, &srate, &ch) < 0) {
                        trace ("NeAACDecInit2 returned error\n");
                        free (buff);
                        return -1;
                    }
                    samplerate = srate;
                    channels = ch;
                    samples = (int64_t)samples * srate / mp4ff_time_scale (info->mp4file, i);
                    totalsamples = samples;
                    NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec);
                    conf->dontUpSampleImplicitSBR = 1;
                    NeAACDecSetConfiguration (info->dec, conf);
                    mp4AudioSpecificConfig mp4ASC;
                    if (NeAACDecAudioSpecificConfig(buff, buff_size, &mp4ASC) >= 0)
                    {
                        info->mp4framesize = 1024;
                        if (mp4ASC.frameLengthFlag == 1) {
                            info->mp4framesize = 960;
                        }
//                        if (mp4ASC.sbr_present_flag == 1) {
//                            info->mp4framesize *= 2;
//                        }
                    }
                    totalsamples *= info->mp4framesize;
                    duration = (float)totalsamples  / samplerate;
                }
                else {
                    mp4ff_close (info->mp4file);
                    info->mp4file = NULL;
                }
                if (buff) {
                    free (buff);
                }
            }
            else {
                mp4ff_close (info->mp4file);
                info->mp4file = NULL;
            }
        }
// {{{ libmp4v2 code
#else
        trace ("aac_init: MP4ReadProvider %s\n", deadbeef->pl_find_meta (it, ":URI"));
        info->mp4file = MP4ReadProvider (deadbeef->pl_find_meta (it, ":URI"), 0, &info->mp4reader);
        info->mp4track = MP4FindTrackId(info->mp4file, 0, "audio", 0);
        trace ("aac_init: MP4FindTrackId returned %d\n", info->mp4track);
        if (info->mp4track >= 0) {
            info->timescale = MP4GetTrackTimeScale(info->mp4file, info->mp4track);

            u_int8_t* pConfig;
            uint32_t configSize = 0;
            bool res = MP4GetTrackESConfiguration(info->mp4file, info->mp4track, &pConfig, &configSize);

            mp4AudioSpecificConfig mp4ASC;
            int rc = AudioSpecificConfig(pConfig, configSize, &mp4ASC);
            if (rc >= 0) {
                _info->samplerate = mp4ASC.samplingFrequency;
                _info->channels = MP4GetTrackAudioChannels (info->mp4file, info->mp4track);
                totalsamples = MP4GetTrackNumberOfSamples (info->mp4file, info->mp4track) * 1024 * _info->channels;

                // init mp4 decoding
                info->dec = NeAACDecOpen ();
                unsigned long srate;
                unsigned char ch;
                if (NeAACDecInit2(info->dec, pConfig, configSize, &srate, &ch) < 0) {
                    trace ("NeAACDecInit2 returned error\n");
                    return -1;
                }
                samplerate = srate;
                channels = ch;
                NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec);
                conf->dontUpSampleImplicitSBR = 1;
                NeAACDecSetConfiguration (info->dec, conf);
                mp4AudioSpecificConfig mp4ASC;
                if (NeAACDecAudioSpecificConfig(pConfig, configSize, &mp4ASC) >= 0)
                {
                    info->mp4framesize = 1024;
                    if (mp4ASC.frameLengthFlag == 1) {
                        info->mp4framesize = 960;
                    }
//                    if (mp4ASC.sbr_present_flag == 1) {
//                        info->mp4framesize *= 2;
//                    }
                }
                //totalsamples *= info->mp4framesize;
                free (pConfig);
                info->maxSampleSize = MP4GetTrackMaxSampleSize(info->mp4file, info->mp4track);
                info->samplebuffer = malloc (info->maxSampleSize);
                info->mp4sample = 1;
            }
            else {
                MP4Close (info->mp4file);
                info->mp4file = NULL;
            }
        }
        else {
            MP4Close (info->mp4file);
            info->mp4file = NULL;
        }
#endif
// }}}
        if (!info->mp4file) {
            trace ("mp4 track not found, looking for aac stream...\n");

            if (info->junk >= 0) {
                deadbeef->fseek (info->file, info->junk, SEEK_SET);
            }
            else {
                deadbeef->rewind (info->file);
            }
            int offs = parse_aac_stream (info->file, &samplerate, &channels, &duration, &totalsamples);
            if (offs == -1) {
                trace ("aac stream not found\n");
                return -1;
            }
            if (offs > info->junk) {
                info->junk = offs;
            }
            if (info->junk >= 0) {
                deadbeef->fseek (info->file, info->junk, SEEK_SET);
            }
            else {
                deadbeef->rewind (info->file);
            }
            trace ("found aac stream (junk: %d, offs: %d)\n", info->junk, offs);
        }

        _info->fmt.channels = channels;
        _info->fmt.samplerate = samplerate;
    }
    else {
        // sync before attempting to init
        int samplerate, channels;
        float duration;
        int offs = parse_aac_stream (info->file, &samplerate, &channels, &duration, NULL);
        if (offs < 0) {
            trace ("aac: parse_aac_stream failed\n");
            return -1;
        }
        if (offs > info->junk) {
            info->junk = offs;
        }
        trace("parse_aac_stream returned %x\n", offs);
        deadbeef->pl_replace_meta (it, "!FILETYPE", "AAC");
    }

//    duration = (float)totalsamples / samplerate;
//    deadbeef->pl_set_item_duration (it, duration);

    _info->fmt.bps = 16;
    _info->plugin = &plugin;

    if (!info->mp4file) {
        //trace ("NeAACDecGetCapabilities\n");
        //unsigned long caps = NeAACDecGetCapabilities();

        trace ("NeAACDecOpen\n");
        info->dec = NeAACDecOpen ();

        trace ("prepare for NeAACDecInit: fread %d from offs %lld\n", AAC_BUFFER_SIZE, deadbeef->ftell (info->file));
        info->remaining = deadbeef->fread (info->buffer, 1, AAC_BUFFER_SIZE, info->file);

        NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec);
//        conf->dontUpSampleImplicitSBR = 1;
        NeAACDecSetConfiguration (info->dec, conf);
        unsigned long srate;
        unsigned char ch;
        trace ("NeAACDecInit (%d bytes)\n", info->remaining);
        int consumed = NeAACDecInit (info->dec, info->buffer, info->remaining, &srate, &ch);
        trace ("NeAACDecInit returned samplerate=%d, channels=%d, consumed: %d\n", (int)srate, (int)ch, consumed);
        if (consumed < 0) {
            trace ("NeAACDecInit returned %d\n", consumed);
            return -1;
        }
        if (consumed > info->remaining) {
            trace ("NeAACDecInit consumed more than available! wtf?\n");
            return -1;
        }
        if (consumed == info->remaining) {
            info->remaining = 0;
        }
        else if (consumed > 0) {
            memmove (info->buffer, info->buffer + consumed, info->remaining - consumed);
            info->remaining -= consumed;
        }
        _info->fmt.channels = ch;
        _info->fmt.samplerate = srate;
    }

    if (!info->file->vfs->is_streaming ()) {
        if (it->endsample > 0) {
            info->startsample = it->startsample;
            info->endsample = it->endsample;
            plugin.seek_sample (_info, 0);
        }
        else {
            info->startsample = 0;
            info->endsample = totalsamples-1;
        }
    }
    trace ("totalsamples: %d, endsample: %d, samples-from-duration: %d\n", totalsamples-1, info->endsample, (int)deadbeef->pl_get_item_duration (it)*44100);

    for (int i = 0; i < _info->fmt.channels; i++) {
        _info->fmt.channelmask |= 1 << i;
    }
    info->noremap = 0;
    info->remap[0] = -1;
    trace ("init success\n");

    return 0;
}
Exemplo n.º 7
0
// returns -1 for error, 0 for mp4, 1 for aac
int
aac_probe (DB_FILE *fp, const char *fname, MP4FILE_CB *cb, float *duration, int *samplerate, int *channels, int *totalsamples, int *mp4track, MP4FILE *pmp4) {
    // try mp4
    trace ("aac_probe: pos=%lld, junk=%d\n", deadbeef->ftell (fp), ((aac_info_t*)cb->user_data)->junk);

    if (mp4track) {
        *mp4track = -1;
    }
    if (*pmp4) {
        *pmp4 = NULL;
    }
    *duration = -1;
#ifdef USE_MP4FF
    trace ("mp4ff_open_read\n");
    mp4ff_t *mp4 = mp4ff_open_read (cb);
#else
    MP4FileHandle mp4 = MP4ReadProvider (fname, 0, cb);
#endif
    if (!mp4) {
        trace ("not an mp4 file\n");
        return -1;
    }
    if (pmp4) {
        *pmp4 = mp4;
    }
#ifdef USE_MP4FF
    int ntracks = mp4ff_total_tracks (mp4);
    if (ntracks > 0) {
        trace ("m4a container detected, ntracks=%d\n", ntracks);
        int i = -1;
        trace ("looking for mp4 data...\n");
        int sr = -1;
        unsigned char*  buff = 0;
        unsigned int    buff_size = 0;
        for (i = 0; i < ntracks; i++) {
            mp4AudioSpecificConfig mp4ASC;
            mp4ff_get_decoder_config(mp4, i, &buff, &buff_size);
            if (buff) {
                int rc = AudioSpecificConfig(buff, buff_size, &mp4ASC);
                sr = mp4ASC.samplingFrequency;
                if(rc < 0) {
                    free (buff);
                    buff = 0;
                    continue;
                }
                break;
            }
        }
        if (i != ntracks && buff) 
        {
            trace ("found audio track (%d)\n", i);
            // init mp4 decoding
            NeAACDecHandle dec = NeAACDecOpen ();
            unsigned long srate;
            unsigned char ch;
            if (NeAACDecInit2(dec, buff, buff_size, &srate, &ch) < 0) {
                trace ("NeAACDecInit2 returned error\n");
                goto error;
            }
            *samplerate = srate;
            *channels = ch;
            int samples = mp4ff_num_samples(mp4, i);
            samples = (int64_t)samples * srate / mp4ff_time_scale (mp4, i);
            int tsamples = samples;
            NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (dec);
            conf->dontUpSampleImplicitSBR = 1;
            NeAACDecSetConfiguration (dec, conf);
            mp4AudioSpecificConfig mp4ASC;
            int mp4framesize;
            if (NeAACDecAudioSpecificConfig(buff, buff_size, &mp4ASC) >= 0)
            {
                mp4framesize = 1024;
                if (mp4ASC.frameLengthFlag == 1) {
                    mp4framesize = 960;
                }
                // commented this out, since it fixes double-duration bug on
                // some mp4 files
                //if (mp4ASC.sbr_present_flag == 1) {
                //    mp4framesize *= 2;
                //}
            }
            else {
                trace ("NeAACDecAudioSpecificConfig failed, can't get mp4framesize\n");
                goto error;
            }
            tsamples *= mp4framesize;

            trace ("mp4 nsamples=%d, samplerate=%d, timescale=%d, duration=%lld\n", samples, *samplerate, mp4ff_time_scale(mp4, i), mp4ff_get_track_duration(mp4, i));
            *duration = (float)tsamples / (*samplerate);
            trace ("mp4 duration: %f (tsamples %d/samplerate %d)\n", *duration, tsamples, *samplerate);
            
            NeAACDecClose (dec);

            if (totalsamples) {
                *totalsamples = tsamples;
            }
            if (mp4track) {
                *mp4track = i;
            }
            if (!*pmp4) {
                mp4ff_close (mp4);
            }
            return 0;
error:
            NeAACDecClose (dec);
            free (buff);
            if (!*pmp4) {
                mp4ff_close (mp4);
            }
            return -1;
        }
        else {
            trace ("audio track not found\n");
            mp4ff_close (mp4);
            mp4 = NULL;
        }
        if (buff) {
            free (buff);
            buff = NULL;
        }

    }
#else
    MP4FileHandle mp4File = mp4;
    MP4TrackId trackId = MP4FindTrackId(mp4File, 0, "audio", 0);
    trace ("trackid: %d\n", trackId);
    uint32_t timeScale = MP4GetTrackTimeScale(mp4File, trackId);
    MP4Duration trackDuration = MP4GetTrackDuration(mp4File, trackId);
    MP4SampleId numSamples = MP4GetTrackNumberOfSamples(mp4File, trackId);
    u_int8_t* pConfig;
    uint32_t configSize = 0;
    bool res = MP4GetTrackESConfiguration(mp4File, trackId, &pConfig, &configSize);
    if (res && pConfig) {
        mp4AudioSpecificConfig mp4ASC;
        int rc = AudioSpecificConfig(pConfig, configSize, &mp4ASC);
        free (pConfig);
        if (rc >= 0) {
            *samplerate = mp4ASC.samplingFrequency;
            *channels = MP4GetTrackAudioChannels (mp4File, trackId);
//            int64_t duration = MP4ConvertFromTrackDuration (mp4File, trackId, trackDuration, timeScale);
            int samples = MP4GetTrackNumberOfSamples (mp4File, trackId) * 1024 * (*channels);
            trace ("mp4 nsamples=%d, timescale=%d, samplerate=%d\n", samples, timeScale, *samplerate);
            *duration = (float)samples / (*samplerate);

            if (totalsamples) {
                *totalsamples = samples;
            }
            if (mp4track) {
                *mp4track = trackId;
            }
            if (!*pmp4) {
                MP4Close (mp4);
            }
            return 0;
        }
    }
#endif
    if (*pmp4) {
        *pmp4 = NULL;
    }

    if (mp4) {
#if USE_MP4FF
        mp4ff_close (mp4);
#else
        MP4Close (mp4);
#endif
        mp4 = NULL;
    }
    trace ("mp4 track not found, looking for aac stream...\n");

    // not an mp4, try raw aac
#if USE_MP4FF
    deadbeef->rewind (fp);
#endif
    if (parse_aac_stream (fp, samplerate, channels, duration, totalsamples) == -1) {
        trace ("aac stream not found\n");
        return -1;
    }
    trace ("found aac stream\n");
    return 1;
}
Exemplo n.º 8
0
static void *mp4Decode(void *args)
{
  FILE*		mp4file;

  pthread_mutex_lock(&mutex);
  seekPosition = -1;
  bPlaying = TRUE;

  if(!(mp4file = fopen(args, "rb"))){
    g_print("MP4!AAC - Can't open file\n");
    g_free(args);
    bPlaying = FALSE;
    pthread_mutex_unlock(&mutex);
    pthread_exit(NULL);

  }
  mp4_get_file_type(mp4file);
  fseek(mp4file, 0, SEEK_SET);
  if(mp4cfg.file_type == FILE_MP4){// We are reading a MP4 file
    mp4ff_callback_t*	mp4cb;
    mp4ff_t*		infile;
    gint		mp4track;

    mp4cb = getMP4FF_cb(mp4file);
    if(!(infile = mp4ff_open_read(mp4cb))){
      g_print("MP4 - Can't open file\n");
      goto end;
    }

    if((mp4track = getAACTrack(infile)) < 0){
      /*
       * TODO: check here for others Audio format.....
       *
      */
      g_print("Unsupported Audio track type\n");
      g_free(args);
      fclose(mp4file);
      bPlaying = FALSE;
      pthread_mutex_unlock(&mutex);
      pthread_exit(NULL);
    }else{
      NeAACDecHandle	decoder;
      unsigned char	*buffer	= NULL;
      guint		bufferSize = 0;
      gulong		samplerate;
      guchar		channels;
      //guint		avgBitrate;
      //MP4Duration	duration;
      int		msDuration;
      int		numSamples;
      int		sampleID = 0;
      unsigned int	framesize;
      mp4AudioSpecificConfig mp4ASC;
      gchar		*xmmstitle;

      decoder = NeAACDecOpen();
      mp4ff_get_decoder_config(infile, mp4track, &buffer, &bufferSize);
      if(NeAACDecInit2(decoder, buffer, bufferSize, &samplerate, &channels)<0){
          goto end;
      }
      if(buffer){
	framesize = 1024;
	if(NeAACDecAudioSpecificConfig(buffer, bufferSize, &mp4ASC) >= 0){
	  if(mp4ASC.frameLengthFlag == 1) framesize = 960;
	  if(mp4ASC.sbr_present_flag == 1) framesize *= 2;
	}
	g_free(buffer);
      }
      if(channels == 0){
	g_print("Number of Channels not supported\n");
	goto end;
      }

      //duration = MP4GetTrackDuration(mp4file, mp4track);
      //msDuration = MP4ConvertFromTrackDuration(mp4file, mp4track,
      //				       duration,MP4_MSECS_TIME_SCALE);

      //msDuration = mp4ff_get_track_duration(infile, mp4track);
      //printf("%d\n", msDuration);

      //numSamples = MP4GetTrackNumberOfSamples(mp4file, mp4track);
      numSamples = mp4ff_num_samples(infile, mp4track);
      {
	float f = 1024.0;
	if(mp4ASC.sbr_present_flag == 1)
	  f = f * 2.0;
	msDuration = ((float)numSamples*(float)(f-1.0)/
		      (float)samplerate)*1000;
      }
      xmmstitle = getMP4title(infile, args);
      mp4_ip.output->open_audio(FMT_S16_NE, samplerate, channels);
      mp4_ip.output->flush(0);
      mp4_ip.set_info(xmmstitle, msDuration, -1, samplerate/1000, channels);
      g_print("MP4 - %d channels @ %ld Hz\n", channels, samplerate);

      while(bPlaying){
	void*			sampleBuffer;
	faacDecFrameInfo	frameInfo;
	gint			rc;

	if(seekPosition!=-1){
	  /*
	  duration = MP4ConvertToTrackDuration(mp4file,
					       mp4track,
					       seekPosition*1000,
					       MP4_MSECS_TIME_SCALE);
	  sampleID = MP4GetSampleIdFromTime(mp4file, mp4track, duration, 0);
          */
          float f = 1024.0;
	  if(mp4ASC.sbr_present_flag == 1)
	    f = f * 2.0;
          sampleID = (float)seekPosition*(float)samplerate/(float)(f-1.0);
	  mp4_ip.output->flush(seekPosition*1000);
	  seekPosition = -1;
	}
	buffer=NULL;
	bufferSize=0;
	rc = mp4ff_read_sample(infile, mp4track, sampleID++,
			       &buffer, &bufferSize);
	//g_print("%d/%d\n", sampleID-1, numSamples);
	if((rc==0) || (buffer== NULL)){
	  g_print("MP4: read error\n");
	  sampleBuffer = NULL;
	  sampleID=0;
	  mp4_ip.output->buffer_free();
            goto end;
	}else{
	  sampleBuffer = NeAACDecDecode(decoder, &frameInfo, buffer, bufferSize);
	  if(frameInfo.error > 0){
	    g_print("MP4: %s\n",
		    faacDecGetErrorMessage(frameInfo.error));
	    goto end;
	  }
	  if(buffer){
	    g_free(buffer); buffer=NULL; bufferSize=0;
	  }
	  while(bPlaying && mp4_ip.output->buffer_free()<frameInfo.samples<<1)
	    xmms_usleep(30000);
	}
	mp4_ip.add_vis_pcm(mp4_ip.output->written_time(),
			   FMT_S16_NE,
			   channels,
			   frameInfo.samples<<1,
			   sampleBuffer);
	mp4_ip.output->write_audio(sampleBuffer, frameInfo.samples<<1);
	if(sampleID >= numSamples){
          break;
	}
      }
      while(bPlaying && mp4_ip.output->buffer_playing() && mp4_ip.output->buffer_free()){
	xmms_usleep(10000);
      }
end:
      mp4_ip.output->close_audio();
      g_free(args);
      NeAACDecClose(decoder);
      if(infile) mp4ff_close(infile);
      if(mp4cb) g_free(mp4cb);
      bPlaying = FALSE;
      fclose(mp4file);
      pthread_mutex_unlock(&mutex);
      pthread_exit(NULL);
    }
  }else{
    // WE ARE READING AN AAC FILE
    FILE		*file = NULL;
    NeAACDecHandle	decoder = 0;
    guchar		*buffer = 0;
    gulong		bufferconsumed = 0;
    gulong		samplerate = 0;
    guchar		channels;
    gulong		buffervalid = 0;
    TitleInput*		input;
    gchar		*temp = g_strdup(args);
    gchar		*ext  = strrchr(temp, '.');
    gchar		*xmmstitle = NULL;
    NeAACDecConfigurationPtr config;

    if((file = fopen(args, "rb")) == 0){
      g_print("AAC: can't find file %s\n", args);
      bPlaying = FALSE;
      pthread_mutex_unlock(&mutex);
      pthread_exit(NULL);
    }
    if((decoder = NeAACDecOpen()) == NULL){
      g_print("AAC: Open Decoder Error\n");
      fclose(file);
      bPlaying = FALSE;
      pthread_mutex_unlock(&mutex);
      pthread_exit(NULL);
    }
    config = NeAACDecGetCurrentConfiguration(decoder);
    config->useOldADTSFormat = 0;
    NeAACDecSetConfiguration(decoder, config);
    if((buffer = g_malloc(BUFFER_SIZE)) == NULL){
      g_print("AAC: error g_malloc\n");
      fclose(file);
      bPlaying = FALSE;
      NeAACDecClose(decoder);
      pthread_mutex_unlock(&mutex);
      pthread_exit(NULL);
    }
    if((buffervalid = fread(buffer, 1, BUFFER_SIZE, file))==0){
      g_print("AAC: Error reading file\n");
      g_free(buffer);
      fclose(file);
      bPlaying = FALSE;
      NeAACDecClose(decoder);
      pthread_mutex_unlock(&mutex);
      pthread_exit(NULL);
    }
    XMMS_NEW_TITLEINPUT(input);
    input->file_name = g_basename(temp);
    input->file_ext = ext ? ext+1 : NULL;
    input->file_path = temp;
    if(!strncmp(buffer, "ID3", 3)){
      gint size = 0;

      fseek(file, 0, SEEK_SET);
      size = (buffer[6]<<21) | (buffer[7]<<14) | (buffer[8]<<7) | buffer[9];
      size+=10;
      fread(buffer, 1, size, file);
      buffervalid = fread(buffer, 1, BUFFER_SIZE, file);
    }
    xmmstitle = xmms_get_titlestring(xmms_get_gentitle_format(), input);
    if(xmmstitle == NULL)
      xmmstitle = g_strdup(input->file_name);
    if(temp) g_free(temp);
    if(input->performer) g_free(input->performer);
    if(input->album_name) g_free(input->album_name);
    if(input->track_name) g_free(input->track_name);
    if(input->genre) g_free(input->genre);
    g_free(input);
    bufferconsumed = NeAACDecInit(decoder,
				 buffer,
				 buffervalid,
				 &samplerate,
				 &channels);
    if(mp4_ip.output->open_audio(FMT_S16_NE,samplerate,channels) == FALSE){
      g_print("AAC: Output Error\n");
      g_free(buffer); buffer=0;
      faacDecClose(decoder);
      fclose(file);
      mp4_ip.output->close_audio();
      /*
      if(positionTable){
	g_free(positionTable); positionTable=0;
      }
      */
      g_free(xmmstitle);
      bPlaying = FALSE;
      pthread_mutex_unlock(&mutex);
      pthread_exit(NULL);
    }
    //if(bSeek){
    //mp4_ip.set_info(xmmstitle, lenght*1000, -1, samplerate, channels);
      //}else{
    mp4_ip.set_info(xmmstitle, -1, -1, samplerate, channels);
      //}
    mp4_ip.output->flush(0);

    while(bPlaying && buffervalid > 0){
      NeAACDecFrameInfo	finfo;
      unsigned long	samplesdecoded;
      char*		sample_buffer = NULL;
      /*
	if(bSeek && seekPosition!=-1){
	fseek(file, positionTable[seekPosition], SEEK_SET);
	bufferconsumed=0;
	buffervalid = fread(buffer, 1, BUFFER_SIZE, file);
	aac_ip.output->flush(seekPosition*1000);
	seekPosition=-1;
	}
      */
      if(bufferconsumed > 0){
	memmove(buffer, &buffer[bufferconsumed], buffervalid-bufferconsumed);
	buffervalid -= bufferconsumed;
	buffervalid += fread(&buffer[buffervalid], 1,
			     BUFFER_SIZE-buffervalid, file);
	bufferconsumed = 0;
      }
      sample_buffer = NeAACDecDecode(decoder, &finfo, buffer, buffervalid);
      if(finfo.error){
	config = NeAACDecGetCurrentConfiguration(decoder);
	if(config->useOldADTSFormat != 1){
	  NeAACDecClose(decoder);
	  decoder = NeAACDecOpen();
	  config = NeAACDecGetCurrentConfiguration(decoder);
	  config->useOldADTSFormat = 1;
	  NeAACDecSetConfiguration(decoder, config);
	  finfo.bytesconsumed=0;
	  finfo.samples = 0;
	  NeAACDecInit(decoder,
		      buffer,
		      buffervalid,
		      &samplerate,
		      &channels);
	}else{
	  g_print("FAAD2 Warning %s\n", NeAACDecGetErrorMessage(finfo.error));
	  buffervalid = 0;
	}
      }
      bufferconsumed += finfo.bytesconsumed;
      samplesdecoded = finfo.samples;
      if((samplesdecoded<=0) && !sample_buffer){
	g_print("AAC: error sample decoding\n");
	continue;
      }
      while(bPlaying && mp4_ip.output->buffer_free() < (samplesdecoded<<1)){
	xmms_usleep(10000);
      }
      mp4_ip.add_vis_pcm(mp4_ip.output->written_time(),
			 FMT_S16_LE, channels,
			 samplesdecoded<<1, sample_buffer);
      mp4_ip.output->write_audio(sample_buffer, samplesdecoded<<1);
    }
    while(bPlaying && mp4_ip.output->buffer_playing()){
      xmms_usleep(10000);
    }
    mp4_ip.output->buffer_free();
    mp4_ip.output->close_audio();
    bPlaying = FALSE;
    g_free(buffer);
    NeAACDecClose(decoder);
    g_free(xmmstitle);
    fclose(file);
    seekPosition = -1;
    /*
    if(positionTable){
      g_free(positionTable); positionTable=0;
    }
    */
    bPlaying = FALSE;
    pthread_mutex_unlock(&mutex);
    pthread_exit(NULL);

  }
}