int GetAACTrack(MP4FileHandle infile) { // find AAC track int i, rc; int numTracks = MP4GetNumberOfTracks(infile, NULL, 0); for (i = 0; i < numTracks; i++) { MP4TrackId trackId = MP4FindTrackId(infile, i, NULL, 0); const char* trackType = MP4GetTrackType(infile, trackId); if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE)) { unsigned char *buff = NULL; unsigned __int32 buff_size = 0; mp4AudioSpecificConfig mp4ASC; MP4GetTrackESConfiguration(infile, trackId, (unsigned __int8 **)&buff, &buff_size); if (buff) { rc = AudioSpecificConfig(buff, buff_size, &mp4ASC); free(buff); if (rc < 0) return -1; return trackId; } } } // can't decode this return -1; }
static int mp4_track_get_info(mp4ff_t *mp4, int track, float *duration, int *samplerate, int *channels, int *totalsamples, int *mp4framesize) { int sr = -1; unsigned char* buff = 0; unsigned int buff_size = 0; mp4AudioSpecificConfig mp4ASC; mp4ff_get_decoder_config(mp4, track, &buff, &buff_size); if (buff) { int rc = AudioSpecificConfig(buff, buff_size, &mp4ASC); sr = mp4ASC.samplingFrequency; if(rc < 0) { free (buff); trace ("aac: AudioSpecificConfig returned result=%d\n", rc); return -1; } } unsigned long srate; unsigned char ch; int samples; // init mp4 decoding NeAACDecHandle dec = NeAACDecOpen (); if (NeAACDecInit2(dec, buff, buff_size, &srate, &ch) < 0) { trace ("NeAACDecInit2 returned error\n"); goto error; } *samplerate = srate; *channels = ch; samples = (int64_t)mp4ff_num_samples(mp4, track); NeAACDecClose (dec); dec = NULL; if (samples <= 0) { goto error; } int i_sample_count = samples; int i_sample; int64_t total_dur = 0; for( i_sample = 0; i_sample < i_sample_count; i_sample++ ) { total_dur += mp4ff_get_sample_duration (mp4, track, i_sample); } if (totalsamples) { *totalsamples = total_dur * (*samplerate) / mp4ff_time_scale (mp4, track); *mp4framesize = (*totalsamples) / i_sample_count; } *duration = total_dur / (float)mp4ff_time_scale (mp4, track); return 0; error: if (dec) { NeAACDecClose (dec); } free (buff); return -1; }
HRESULT CCoreAACDecoder::CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin) { HRESULT hr = CTransformFilter::CompleteConnect(direction, pReceivePin); if(direction == PINDIR_INPUT) { if(m_decHandle) { faacDecClose(m_decHandle); m_decHandle = NULL; } m_decHandle = faacDecOpen(); faacDecConfigurationPtr config; config = faacDecGetCurrentConfiguration(m_decHandle); config->downMatrix = m_DownMatrix; faacDecSetConfiguration(m_decHandle, config); // Initialize the decoder unsigned long SamplesPerSec = 0; unsigned char Channels = 0; if(faacDecInit2(m_decHandle, m_decoderSpecific, m_decoderSpecificLen, &SamplesPerSec, &Channels) < 0) { return E_FAIL; } if(m_DownMatrix) { Channels = 2; // TODO : check with mono } mp4AudioSpecificConfig info; AudioSpecificConfig(m_decoderSpecific,m_decoderSpecificLen,&info); wsprintf(m_ProfileName,"%s%s", ObjectTypesNameTable[info.objectTypeIndex], #if 0 info.sbr_present_flag ? #else false ? #endif "+SBR" : "" ); m_Channels = Channels; m_SamplesPerSec = SamplesPerSec; m_BitsPerSample = 16; // we always decode to the default 16 bits (we could add 24,32,float) m_brCalcFrames = 0; m_brBytesConsumed = 0; m_DecodedFrames = 0; } return hr; }
//--------------------------------------------------------------------------- void File_Aac::Read_Buffer_Continue_AudioSpecificConfig() { File__Analyze::Accept(); //We automaticly trust it BS_Begin(); AudioSpecificConfig(0); //Up to the end of the block BS_End(); Mode=Mode_raw_data_block; //Mode_AudioSpecificConfig only once }
gint getAACTrack (mp4ff_t * infile) { gint i, rc, numTracks = mp4ff_total_tracks (infile); for (i = 0; i < numTracks; i++) { guint8 *buff = NULL; guint32 buff_size = 0; mp4AudioSpecificConfig mp4ASC; mp4ff_get_decoder_config (infile, i, &buff, &buff_size); if (buff != NULL) { rc = AudioSpecificConfig (buff, buff_size, &mp4ASC); free (buff); if (rc < 0) continue; return i; } } return -1; }
int AacPcm::getInfos(MediaInfo *infos) { if(!infos) return 1; if(hDecoder) { SHOW_INFO() return 0; } IsAAC=strcmpi(infos->getFilename()+lstrlen(infos->getFilename())-4,".aac")==0; if(!IsAAC) // MP4 file --------------------------------------------------------------------- { MP4Duration length; unsigned __int32 buffer_size; mp4AudioSpecificConfig mp4ASC; if(!(mp4File=MP4Read(infos->getFilename(), 0))) ERROR_getInfos("Error opening file"); if((track=GetAACTrack(mp4File))<0) ERROR_getInfos(0); //"Unable to find correct AAC sound track"); if(!(hDecoder=faacDecOpen())) ERROR_getInfos("Error initializing decoder library"); MP4GetTrackESConfiguration(mp4File, track, (unsigned __int8 **)&buffer, &buffer_size); if(!buffer) ERROR_getInfos("MP4GetTrackESConfiguration"); AudioSpecificConfig(buffer, buffer_size, &mp4ASC); Channels=mp4ASC.channelsConfiguration; if(faacDecInit2(hDecoder, buffer, buffer_size, &Samplerate, &Channels) < 0) ERROR_getInfos("Error initializing decoder library"); FREE_ARRAY(buffer); length=MP4GetTrackDuration(mp4File, track); len_ms=(DWORD)MP4ConvertFromTrackDuration(mp4File, track, length, MP4_MSECS_TIME_SCALE); file_info.bitrate=MP4GetTrackBitRate(mp4File, track); file_info.version=MP4GetTrackAudioType(mp4File, track)==MP4_MPEG4_AUDIO_TYPE ? 4 : 2; numSamples=MP4GetTrackNumberOfSamples(mp4File, track); sampleId=1; } else // AAC file ------------------------------------------------------------------------------ { DWORD read, tmp; BYTE Channels4Raw=0; if(!(aacFile=fopen(infos->getFilename(),"rb"))) ERROR_getInfos("Error opening file"); // use bufferized stream setvbuf(aacFile,NULL,_IOFBF,32767); // get size of file fseek(aacFile, 0, SEEK_END); src_size=ftell(aacFile); fseek(aacFile, 0, SEEK_SET); if(!(buffer=(BYTE *)malloc(FAAD_STREAMSIZE))) ERROR_getInfos("Memory allocation error: buffer") tmp=src_size<FAAD_STREAMSIZE ? src_size : FAAD_STREAMSIZE; read=fread(buffer, 1, tmp, aacFile); if(read==tmp) { bytes_read=read; bytes_into_buffer=read; } else ERROR_getInfos("Read failed!") if(tagsize=id3v2_tag(buffer)) { if(tagsize>(long)src_size) ERROR_getInfos("Corrupt stream!"); if(tagsize<bytes_into_buffer) { bytes_into_buffer-=tagsize; memcpy(buffer,buffer+tagsize,bytes_into_buffer); } else { bytes_read=tagsize; bytes_into_buffer=0; if(tagsize>bytes_into_buffer) fseek(aacFile, tagsize, SEEK_SET); } if(src_size<bytes_read+FAAD_STREAMSIZE-bytes_into_buffer) tmp=src_size-bytes_read; else tmp=FAAD_STREAMSIZE-bytes_into_buffer; read=fread(buffer+bytes_into_buffer, 1, tmp, aacFile); if(read==tmp) { bytes_read+=read; bytes_into_buffer+=read; } else ERROR_getInfos("Read failed!"); } if(get_AAC_format((char *)infos->getFilename(), &file_info, &seek_table, &seek_table_length, 0)) ERROR_getInfos("get_AAC_format"); IsSeekable=file_info.headertype==ADTS && seek_table && seek_table_length>0; BlockSeeking=!IsSeekable; if(!(hDecoder=faacDecOpen())) ERROR_getInfos("Can't open library"); if(file_info.headertype==RAW) { faacDecConfiguration config; config.defSampleRate=atoi(cfg_samplerate); switch(cfg_profile[1]) { case 'a': config.defObjectType=MAIN; break; case 'o': config.defObjectType=LOW; break; case 'S': config.defObjectType=SSR; break; case 'T': config.defObjectType=LTP; break; } switch(cfg_bps[0]) { case '1': config.outputFormat=FAAD_FMT_16BIT; break; case '2': config.outputFormat=FAAD_FMT_24BIT; break; case '3': config.outputFormat=FAAD_FMT_32BIT; break; case 'F': config.outputFormat=FAAD_FMT_24BIT; break; } faacDecSetConfiguration(hDecoder, &config); if(!FindBitrate) { AacPcm *NewInst; if(!(NewInst=new AacPcm())) ERROR_getInfos("Memory allocation error: NewInst"); NewInst->FindBitrate=TRUE; if(NewInst->getInfos(infos)) ERROR_getInfos(0); Channels4Raw=NewInst->frameInfo.channels; file_info.bitrate=NewInst->file_info.bitrate*Channels4Raw; delete NewInst; } else { DWORD Samples, BytesConsumed; if((bytes_consumed=faacDecInit(hDecoder,buffer,bytes_into_buffer,&Samplerate,&Channels))<0) ERROR_getInfos("Can't init library"); bytes_into_buffer-=bytes_consumed; if(!processData(infos,0,0)) ERROR_getInfos(0); Samples=frameInfo.samples/sizeof(short); BytesConsumed=frameInfo.bytesconsumed; processData(infos,0,0); if(BytesConsumed<frameInfo.bytesconsumed) BytesConsumed=frameInfo.bytesconsumed; file_info.bitrate=(BytesConsumed*8*Samplerate)/Samples; if(!file_info.bitrate) file_info.bitrate=1000; // try to continue decoding return 0; } } if((bytes_consumed=faacDecInit(hDecoder, buffer, bytes_into_buffer, &Samplerate, &Channels))<0) ERROR_getInfos("faacDecInit failed!") bytes_into_buffer-=bytes_consumed; if(Channels4Raw) Channels=Channels4Raw; len_ms=(DWORD)((1000*((float)src_size*8))/file_info.bitrate); } SHOW_INFO(); return 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; }
// 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; }
/** \fn readStreamMuxConfig */ bool ADM_latm2aac::readStreamMuxConfig(getBits &bits) { // streamMuxConfig conf.audioMuxVersion = bits.get(1); if(conf.audioMuxVersion==1) conf.audioMuxVersionA = bits.get(1); if( conf.audioMuxVersionA != 0 ) /* support only A=0 */ { ADM_warning("LATM : versionA!=0, not supported\n"); return false; } if( conf.audioMuxVersion == 1 ) { LatmGetValue(bits); /* taraBufferFullness */ } conf.allStreamsSameTimeFraming=bits.get(1); xdebug("AllSTreamSameTimeFraming =%d\n",conf.allStreamsSameTimeFraming); int numSubFrames=bits.get(6)+1; int numbSubProgram=1+bits.get(4); xdebug("NumSubFrame=%d, numSubProgram=%d\n",numSubFrames,numbSubProgram); if(numSubFrames!=1 || numbSubProgram!=1 ) { ADM_warning("LATM: only supports subframe=1, subprogram=1\n"); return false; } conf.nbLayers=1+bits.get(3); xdebug("NumLayer=%d\n",conf.nbLayers); for(int i=0;i<conf.nbLayers;i++) { bool useSameConfig=false; if(i) useSameConfig=bits.get(1); if(!useSameConfig) { int consumed=0; if(!conf.audioMuxVersion) { // audio specific config if(false==AudioSpecificConfig(bits,consumed)) { ADM_warning("Error reading audioSpecificConfig\n"); return false; } }else { int ascLen=LatmGetValue(bits); //ascLen-=audioSpecicConfig //fillBits(ascLen) if(false==AudioSpecificConfig(bits,consumed)) { ADM_warning("Error reading audioSpecificConfig\n"); return false; } if(consumed>ascLen) { ADM_warning("Too much bits consumed in AudioSpecificConfig (%d/%d)\n",consumed,ascLen); return false; } ascLen-=consumed; while(ascLen) { int r=ascLen; if(r>16) r=16; bits.skip(r); ascLen-=r; } } } // frameLengthType conf.frameLengthType[i]=bits.get(3); xdebug("FrameLengthType=%d\n",conf.frameLengthType[i]); if(conf.frameLengthType[i]!=0) { ADM_error("frameLengthType!=0 not supported (%d)\n",conf.frameLengthType[i]); return false; } bits.get(8); // latmBufferFulless int otherData=bits.get(1); if(otherData) { int otherDataLen=0; if(conf.audioMuxVersion==1) otherDataLen=LatmGetValue(bits); else { while(1) { int esc=bits.get(1); int data=bits.get(8); otherDataLen=(otherDataLen<<8)+data; if(!esc) break; } } } int crc=bits.get(1); if(crc) bits.get(8); } return true; }
/* * Create CAACodec class */ static codec_data_t *aac_codec_create (const char *compressor, int type, int profile, format_list_t *media_fmt, audio_info_t *audio, const uint8_t *userdata, uint32_t userdata_size, audio_vft_t *vft, void *ifptr) { aac_codec_t *aac; aac = (aac_codec_t *)malloc(sizeof(aac_codec_t)); memset(aac, 0, sizeof(aac_codec_t)); aac->m_vft = vft; aac->m_ifptr = ifptr; fmtp_parse_t *fmtp = NULL; // Start setting up FAAC stuff... aac->m_resync_with_header = 1; aac->m_record_sync_time = 1; aac->m_audio_inited = 0; // Use media_fmt to indicate that we're streaming. if (media_fmt != NULL) { // haven't checked for null buffer // This is not necessarilly right - it is, for the most part, but // we should be reading the fmtp statement, and looking at the config. // (like we do below in the userdata section... aac->m_freq = media_fmt->rtpmap->clock_rate; fmtp = parse_fmtp_for_mpeg4(media_fmt->fmt_param, vft->log_msg); if (fmtp != NULL) { userdata = fmtp->config_binary; userdata_size = fmtp->config_binary_len; } } aac->m_info = faacDecOpen(); unsigned long srate; unsigned char chan; if ((userdata == NULL && fmtp == NULL) || (faacDecInit2(aac->m_info, (uint8_t *)userdata, userdata_size, &srate, &chan) < 0)) { if (fmtp != NULL) free_fmtp_parse(fmtp); return NULL; } mp4AudioSpecificConfig mp4ASC; aac->m_output_frame_size = 1024; if (AudioSpecificConfig((unsigned char *)userdata, userdata_size, &mp4ASC)) { if (mp4ASC.frameLengthFlag) { aac->m_output_frame_size = 960; } } aac->m_freq = srate; aac->m_chans = chan; aac->m_faad_inited = 1; aac->m_msec_per_frame = aac->m_output_frame_size; aac->m_msec_per_frame *= M_LLU; aac->m_msec_per_frame /= aac->m_freq; // faad_init_bytestream(&m_info->ld, c_read_byte, c_bookmark, m_bytestream); aa_message(LOG_INFO, aaclib, "Setting freq to %d", aac->m_freq); #if DUMP_OUTPUT_TO_FILE aac->m_outfile = fopen("temp.raw", "w"); #endif if (fmtp != NULL) { free_fmtp_parse(fmtp); } return (codec_data_t *)aac; }
// 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; }