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; }
static int xmms_mp4_get_track (xmms_xform_t *xform, mp4ff_t *infile) { glong chans, rate; int i; int numTracks = mp4ff_total_tracks (infile); /* find first suitable audio track */ for (i = 0; i < numTracks; i++) { gint object_type = mp4ff_get_audio_type (infile, i); /* these identifiers are mostly from VLC code */ switch (object_type) { case 0x40: /* MPEG-4 audio */ case 0x66: /* MPEG-2 AAC */ case 0x67: /* MPEG-2 AAC LC */ case 0x68: /* MPEG-2 AAC SSR */ xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/aac", XMMS_STREAM_TYPE_END); return i; case 0x69: /* MPEG-2 audio */ case 0x6B: /* MPEG-1 audio */ continue; case 0xff: /* ALAC */ chans = mp4ff_get_channel_count (infile, i); rate = mp4ff_get_sample_rate (infile, i); if (chans <= 0 || rate <= 0) { XMMS_DBG ("Bad ALAC audio track %d", i); continue; } xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/x-ffmpeg-alac", XMMS_STREAM_TYPE_FMT_SAMPLERATE, (int)rate, XMMS_STREAM_TYPE_FMT_CHANNELS, (int)chans, XMMS_STREAM_TYPE_END); return i; default: continue; } } /* can't decode this */ return -1; }
/* * Input : Filename * Output : 1 if succesful -1 if not */ int mp4_openFile(char * name) { if((sndFile = fopen(name, "rb"))) { mp4cb.user_data = sndFile; if((infile = mp4ff_open_read(&mp4cb))) { if ((track = findAudioTrack(infile)) >= 0) { /* Decoder failed to initialize */ if((decoder = AACInitDecoder())) { /* Decoder should be updated to decode raw blocks in the mp4 */ inf.sampRateCore = mp4ff_get_sample_rate(infile, track); inf.nChans = mp4ff_get_channel_count(infile,track); /* AACSetRawBlockParams will fail if not set */ inf.profile = AAC_PROFILE_LC; samples = mp4ff_num_samples(infile, track); if(!AACSetRawBlockParams(decoder, 0, &inf)) return 0; } } } } return -1; /* sndFile == NULL */ }
// 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 if (mp4track) { *mp4track = -1; } if (*pmp4) { *pmp4 = NULL; } *duration = -1; #ifdef USE_MP4FF 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; for (i = 0; i < ntracks; i++) { unsigned char* buff = 0; unsigned int buff_size = 0; mp4AudioSpecificConfig mp4ASC; mp4ff_get_decoder_config(mp4, i, &buff, &buff_size); if(buff){ int rc = AudioSpecificConfig(buff, buff_size, &mp4ASC); sr = mp4ASC.samplingFrequency; free(buff); if(rc < 0) continue; break; } } if (i != ntracks) { trace ("mp4 track: %d\n", i); if (sr != -1) { *samplerate = sr; } else { *samplerate = mp4ff_get_sample_rate (mp4, i); } *channels = mp4ff_get_channel_count (mp4, i); int samples = mp4ff_num_samples(mp4, i) * 1024; samples = (int64_t)samples * (*samplerate) / mp4ff_time_scale (mp4, i); 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)samples / (*samplerate); if (totalsamples) { *totalsamples = samples; } if (mp4track) { *mp4track = i; } if (!*pmp4) { mp4ff_close (mp4); } return 0; } } #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; }