static gboolean xmms_mp4_gapless_try_itunsmpb (xmms_xform_t *xform) { xmms_mp4_data_t *data; char *val; gint len; guint64 duration, startsamples, stopsamples; g_return_val_if_fail (xform, FALSE); data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, FALSE); len = mp4ff_meta_find_by_name(data->mp4ff, "iTunSMPB", &val); if (!len) { return FALSE; } duration = mp4ff_get_track_duration (data->mp4ff, data->track); if (!xmms_mp4_gapless_itunsmpb_parse (val, len, duration, &startsamples, &stopsamples)) { return FALSE; } return xmms_mp4_gapless_set (xform, startsamples, stopsamples); }
static void mp4_getSongTitle(char *filename, char **title, int *len) { FILE* mp4file; (*title) = NULL; (*len) = -1; if((mp4file = fopen(filename, "rb"))){ mp4_get_file_type(mp4file); fseek(mp4file, 0, SEEK_SET); if(mp4cfg.file_type == FILE_MP4){ mp4ff_callback_t* mp4cb; mp4ff_t* infile; gint mp4track; mp4cb = getMP4FF_cb(mp4file); if ((infile = mp4ff_open_read_metaonly(mp4cb)) && ((mp4track = getAACTrack(infile)) >= 0)){ (*title) = getMP4title(infile, filename); double track_duration = mp4ff_get_track_duration(infile, mp4track); unsigned long time_scale = mp4ff_time_scale(infile, mp4track); unsigned long length = (track_duration * 1000 / time_scale); (*len) = length; } if(infile) mp4ff_close(infile); if(mp4cb) g_free(mp4cb); } else{ // Check AAC ID3 tag... } fclose(mp4file); } }
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; }
int64_t mp4ff_get_track_duration_use_offsets(const mp4ff_t *f, const int32_t track) { int64_t duration = mp4ff_get_track_duration(f,track); if (duration!=-1) { int64_t offset = mp4ff_get_sample_offset(f,track,0); if (offset > duration) duration = 0; else duration -= offset; } return duration; }
static gboolean xmms_mp4_gapless_try_legacy (xmms_xform_t *xform) { xmms_mp4_data_t *data; guint64 startsamples, stopsamples; g_return_val_if_fail (xform, FALSE); data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, FALSE); startsamples = mp4ff_get_sample_offset (data->mp4ff, data->track, 0); stopsamples = mp4ff_get_track_duration (data->mp4ff, data->track); return xmms_mp4_gapless_set (xform, startsamples, stopsamples); }
static void xmms_mp4_get_mediainfo (xmms_xform_t *xform) { xmms_mp4_data_t *data; const gchar *metakey; glong temp; gint i, num_items; g_return_if_fail (xform); data = xmms_xform_private_data_get (xform); g_return_if_fail (data); if ((temp = mp4ff_get_sample_rate (data->mp4ff, data->track)) > 0) { glong srate = temp; if ((temp = mp4ff_get_track_duration (data->mp4ff, data->track)) >= 0) { glong msec = ((gint64) temp) * 1000 / srate; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, xmms_xform_metadata_set_int (xform, metakey, msec); } } if ((temp = mp4ff_get_avg_bitrate (data->mp4ff, data->track)) >= 0) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE; xmms_xform_metadata_set_int (xform, metakey, temp); } num_items = mp4ff_meta_get_num_items (data->mp4ff); for (i = 0; i < num_items; i++) { gchar *key, *value; guint length; length = mp4ff_meta_get_by_index (data->mp4ff, i, &key, &value); if (length > 0) { if (!xmms_xform_metadata_mapper_match (xform, key, value, length)) { /* iTunSMPB should be handled in xmms_mp4_gapless_try */ if (0 != g_ascii_strcasecmp (key, "iTunSMPB")) { XMMS_DBG ("Unhandled tag '%s' = '%s'", key, value); } } g_free (key); g_free (value); } } }
// 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; }
// 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; }