static void* aacd_faad_init() { void *ret = NeAACDecOpen(); AACD_INFO( "init() FAAD2 capabilities: %d", NeAACDecGetCapabilities()); return ret; }
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; }
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; } }
AACDecoder::AACDecoder(Common::SeekableReadStream *extraData, bool disposeExtraData) { // Open the library _handle = NeAACDecOpen(); // Configure the library to our needs NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(_handle); conf->outputFormat = FAAD_FMT_16BIT; // We only support 16bit audio conf->downMatrix = 1; // Convert from 5.1 to stereo if required NeAACDecSetConfiguration(_handle, conf); // Copy the extra data to a buffer extraData->seek(0); byte *extraDataBuf = new byte[extraData->size()]; extraData->read(extraDataBuf, extraData->size()); // Initialize with our extra data // NOTE: This code assumes the extra data is coming from an MPEG-4 file! int err = NeAACDecInit2(_handle, extraDataBuf, extraData->size(), &_rate, &_channels); delete[] extraDataBuf; if (err < 0) throw Common::Exception("Could not initialize AAC decoder: %s", NeAACDecGetErrorMessage(err)); if (disposeExtraData) delete extraData; }
int aac_init(struct sp* env){ //initialize the aac specific structures struct aac_data* data = malloc(sizeof(struct aac_data)); //allocate private structures int buffer_size = FAAD_MIN_STREAMSIZE*8; //formerly used in the decode call //might not be necessary, it's the minimum amount of data needed to get the decoder to do something //hopefully faad acts like lame and internally buffers input until it can make a frame. //if not we'll need to internally buffer, by holding a buffer_size sized chunk of memory in aac_data //and then filling it int cap = NeAACDecGetCapabilities(); //we should do some bulletproofing here, but we won't now data->hAac = NeAACDecOpen(); //Configure the decoder NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(data->hAac); conf->defObjectType = 2; //aac "MAIN" conf->defSampleRate = 44100; conf->outputFormat = 1; conf->downMatrix = 1; NeAACDecSetConfiguration(data->hAac, conf); //set the stuff // Initialise the library using one of the initialization functions unsigned long samplerate; unsigned char channels; int offset = NeAACDecInit(data->hAac, (unsigned char*)env->input, env->size, &samplerate, &channels); if (offset != 0) { //now how do i tell sp from here that audio data starts at index env->p.offset = offset; //communicate offset return SP_ABORT; //do something to notify of error } //shutup -Wunused-variable... i'll use them eventually (void)buffer_size; (void)cap; env->private_data = data; return SP_OK; }
CAMLprim value ocaml_faad_open(value unit) { CAMLparam0(); CAMLlocal1(ret); NeAACDecHandle dh = NeAACDecOpen(); NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(dh); conf->outputFormat = FAAD_FMT_FLOAT; NeAACDecSetConfiguration(dh, conf); ret = caml_alloc_custom(&faad_dec_ops, sizeof(NeAACDecHandle), 0, 1); Dec_val(ret) = dh; CAMLreturn(ret); }
//--------------------------------------------------------------------------- void File_Aac::libfaad() { #if defined(MEDIAINFO_FAAD_YES) && defined(MEDIAINFO_MPEG4_YES) unsigned long samplerate; unsigned char channels; //Open the library if (hAac==NULL) { hAac = NeAACDecOpen(); // Initialise the library using one of the initialization functions char err = NeAACDecInit2(hAac, (unsigned char *)DecSpecificInfoTag->Buffer, DecSpecificInfoTag->Buffer_Size, &samplerate, &channels); if (err != 0) { // // Handle error // } } //Decode the frame in buffer void* samplebuffer; NeAACDecFrameInfo hInfo; samplebuffer = NeAACDecDecode(hAac, &hInfo, (unsigned char *)Buffer, Buffer_Size); if ((hInfo.error == 0) && (hInfo.samples > 0)) { // // do what you need to do with the decoded samples // } else if (hInfo.error != 0) { // // Some error occurred while decoding this frame // } #else //Filling Stream_Prepare(Stream_General); Fill(Stream_General, 0, General_Format, "AAC"); Stream_Prepare(Stream_Audio); Fill(Stream_Audio, 0, Audio_Format, "AAC"); Fill(Stream_Audio, 0, Audio_Codec, "AAC"); Accept("AAC"); Finish("AAC"); #endif }
/***************************************************************************** * DecodeBlock: *****************************************************************************/ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; if( !pp_block || !*pp_block ) return NULL; p_block = *pp_block; *pp_block = NULL; if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED) ) { Flush( p_dec ); if( p_block->i_flags & (BLOCK_FLAG_CORRUPTED) ) { block_Release( p_block ); return NULL; } } /* Remove ADTS header if we have decoder specific config */ if( p_dec->fmt_in.i_extra && p_block->i_buffer > 7 ) { if( p_block->p_buffer[0] == 0xff && ( p_block->p_buffer[1] & 0xf0 ) == 0xf0 ) /* syncword */ { /* ADTS header present */ size_t i_header_size; /* 7 bytes (+ 2 bytes for crc) */ i_header_size = 7 + ( ( p_block->p_buffer[1] & 0x01 ) ? 0 : 2 ); /* FIXME: multiple blocks per frame */ if( p_block->i_buffer > i_header_size ) { p_block->p_buffer += i_header_size; p_block->i_buffer -= i_header_size; } } } /* Append the block to the temporary buffer */ if( p_sys->i_buffer_size < p_sys->i_buffer + p_block->i_buffer ) { size_t i_buffer_size = p_sys->i_buffer + p_block->i_buffer; uint8_t *p_buffer = realloc( p_sys->p_buffer, i_buffer_size ); if( p_buffer ) { p_sys->i_buffer_size = i_buffer_size; p_sys->p_buffer = p_buffer; } else { p_block->i_buffer = 0; } } if( p_block->i_buffer > 0 ) { memcpy( &p_sys->p_buffer[p_sys->i_buffer], p_block->p_buffer, p_block->i_buffer ); p_sys->i_buffer += p_block->i_buffer; p_block->i_buffer = 0; } if( p_dec->fmt_out.audio.i_rate == 0 && p_dec->fmt_in.i_extra > 0 ) { /* We have a decoder config so init the handle */ unsigned long i_rate; unsigned char i_channels; if( NeAACDecInit2( p_sys->hfaad, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra, &i_rate, &i_channels ) >= 0 ) { p_dec->fmt_out.audio.i_rate = i_rate; p_dec->fmt_out.audio.i_channels = i_channels; p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_guessed[i_channels]; date_Init( &p_sys->date, i_rate, 1 ); } } if( p_dec->fmt_out.audio.i_rate == 0 && p_sys->i_buffer ) { unsigned long i_rate; unsigned char i_channels; /* Init faad with the first frame */ if( NeAACDecInit( p_sys->hfaad, p_sys->p_buffer, p_sys->i_buffer, &i_rate, &i_channels ) < 0 ) { block_Release( p_block ); return NULL; } p_dec->fmt_out.audio.i_rate = i_rate; p_dec->fmt_out.audio.i_channels = i_channels; p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_guessed[i_channels]; date_Init( &p_sys->date, i_rate, 1 ); } if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != date_Get( &p_sys->date ) ) { date_Set( &p_sys->date, p_block->i_pts ); } else if( !date_Get( &p_sys->date ) ) { /* We've just started the stream, wait for the first PTS. */ block_Release( p_block ); p_sys->i_buffer = 0; return NULL; } /* Decode all data */ if( p_sys->i_buffer > 1) { void *samples; NeAACDecFrameInfo frame; block_t *p_out; samples = NeAACDecDecode( p_sys->hfaad, &frame, p_sys->p_buffer, p_sys->i_buffer ); if( frame.error > 0 ) { msg_Warn( p_dec, "%s", NeAACDecGetErrorMessage( frame.error ) ); if( frame.error == 21 || frame.error == 12 ) { /* * Once an "Unexpected channel configuration change" * or a "Invalid number of channels" error * occurs, it will occurs afterwards, and we got no sound. * Reinitialization of the decoder is required. */ unsigned long i_rate; unsigned char i_channels; NeAACDecHandle *hfaad; NeAACDecConfiguration *cfg,*oldcfg; oldcfg = NeAACDecGetCurrentConfiguration( p_sys->hfaad ); hfaad = NeAACDecOpen(); cfg = NeAACDecGetCurrentConfiguration( hfaad ); if( oldcfg->defSampleRate ) cfg->defSampleRate = oldcfg->defSampleRate; cfg->defObjectType = oldcfg->defObjectType; cfg->outputFormat = oldcfg->outputFormat; NeAACDecSetConfiguration( hfaad, cfg ); if( NeAACDecInit( hfaad, p_sys->p_buffer, p_sys->i_buffer, &i_rate,&i_channels ) < 0 ) { /* reinitialization failed */ NeAACDecClose( hfaad ); NeAACDecSetConfiguration( p_sys->hfaad, oldcfg ); } else { NeAACDecClose( p_sys->hfaad ); p_sys->hfaad = hfaad; p_dec->fmt_out.audio.i_rate = i_rate; p_dec->fmt_out.audio.i_channels = i_channels; p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_guessed[i_channels]; date_Init( &p_sys->date, i_rate, 1 ); } } /* Flush the buffer */ p_sys->i_buffer = 0; block_Release( p_block ); return NULL; } if( frame.channels <= 0 || frame.channels > 8 || frame.channels == 7 ) { msg_Warn( p_dec, "invalid channels count: %i", frame.channels ); /* Flush the buffer */ p_sys->i_buffer -= frame.bytesconsumed; if( p_sys->i_buffer > 0 ) { memmove( p_sys->p_buffer,&p_sys->p_buffer[frame.bytesconsumed], p_sys->i_buffer ); } block_Release( p_block ); return NULL; } if( frame.samples <= 0 ) { msg_Warn( p_dec, "decoded zero sample" ); /* Flush the buffer */ p_sys->i_buffer -= frame.bytesconsumed; if( p_sys->i_buffer > 1 ) { memmove( p_sys->p_buffer,&p_sys->p_buffer[frame.bytesconsumed], p_sys->i_buffer ); } else { /* Drop byte of padding */ p_sys->i_buffer = 0; } block_Release( p_block ); return NULL; } /* We decoded a valid frame */ if( p_dec->fmt_out.audio.i_rate != frame.samplerate ) { date_Init( &p_sys->date, frame.samplerate, 1 ); date_Set( &p_sys->date, p_block->i_pts ); } p_block->i_pts = VLC_TS_INVALID; /* PTS is valid only once */ p_dec->fmt_out.audio.i_rate = frame.samplerate; p_dec->fmt_out.audio.i_channels = frame.channels; /* Adjust stream info when dealing with SBR/PS */ bool b_sbr = (frame.sbr == 1) || (frame.sbr == 2); if( p_sys->b_sbr != b_sbr || p_sys->b_ps != frame.ps ) { const char *psz_ext = (b_sbr && frame.ps) ? "SBR+PS" : b_sbr ? "SBR" : "PS"; msg_Dbg( p_dec, "AAC %s (channels: %u, samplerate: %lu)", psz_ext, frame.channels, frame.samplerate ); if( !p_dec->p_description ) p_dec->p_description = vlc_meta_New(); if( p_dec->p_description ) vlc_meta_AddExtra( p_dec->p_description, _("AAC extension"), psz_ext ); p_sys->b_sbr = b_sbr; p_sys->b_ps = frame.ps; } /* Convert frame.channel_position to our own channel values */ p_dec->fmt_out.audio.i_physical_channels = 0; const uint32_t nbChannels = frame.channels; unsigned j; for( unsigned i = 0; i < nbChannels; i++ ) { /* Find the channel code */ for( j = 0; j < MAX_CHANNEL_POSITIONS; j++ ) { if( frame.channel_position[i] == pi_channels_in[j] ) break; } if( j >= MAX_CHANNEL_POSITIONS ) { msg_Warn( p_dec, "unknown channel ordering" ); /* Invent something */ j = i; } /* */ p_sys->pi_channel_positions[i] = pi_channels_out[j]; if( p_dec->fmt_out.audio.i_physical_channels & pi_channels_out[j] ) frame.channels--; /* We loose a duplicated channel */ else p_dec->fmt_out.audio.i_physical_channels |= pi_channels_out[j]; } if ( nbChannels != frame.channels ) { p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_guessed[nbChannels]; } else { p_dec->fmt_out.audio.i_original_channels = p_dec->fmt_out.audio.i_physical_channels; } p_dec->fmt_out.audio.i_channels = nbChannels; if( decoder_UpdateAudioFormat( p_dec ) ) p_out = NULL; else p_out = decoder_NewAudioBuffer( p_dec, frame.samples / nbChannels ); if( p_out == NULL ) { p_sys->i_buffer = 0; block_Release( p_block ); return NULL; } p_out->i_pts = date_Get( &p_sys->date ); p_out->i_length = date_Increment( &p_sys->date, frame.samples / nbChannels ) - p_out->i_pts; DoReordering( (uint32_t *)p_out->p_buffer, samples, frame.samples / nbChannels, nbChannels, p_sys->pi_channel_positions ); p_sys->i_buffer -= frame.bytesconsumed; if( p_sys->i_buffer > 0 ) { memmove( p_sys->p_buffer, &p_sys->p_buffer[frame.bytesconsumed], p_sys->i_buffer ); } block_Release( p_block ); return p_out; } else { /* Drop byte of padding */ p_sys->i_buffer = 0; } block_Release( p_block ); return NULL; }
/***************************************************************************** * OpenDecoder: probe the decoder and return score *****************************************************************************/ static int Open( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t*)p_this; decoder_sys_t *p_sys; NeAACDecConfiguration *cfg; if( p_dec->fmt_in.i_codec != VLC_CODEC_MP4A ) { return VLC_EGENERIC; } /* Allocate the memory needed to store the decoder's structure */ if( ( p_dec->p_sys = p_sys = malloc( sizeof(*p_sys) ) ) == NULL ) return VLC_ENOMEM; /* Open a faad context */ if( ( p_sys->hfaad = NeAACDecOpen() ) == NULL ) { msg_Err( p_dec, "cannot initialize faad" ); free( p_sys ); return VLC_EGENERIC; } /* Misc init */ date_Set( &p_sys->date, 0 ); p_dec->fmt_out.i_cat = AUDIO_ES; p_dec->fmt_out.i_codec = HAVE_FPU ? VLC_CODEC_FL32 : VLC_CODEC_S16N; p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = 0; if( p_dec->fmt_in.i_extra > 0 ) { /* We have a decoder config so init the handle */ unsigned long i_rate; unsigned char i_channels; if( NeAACDecInit2( p_sys->hfaad, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra, &i_rate, &i_channels ) < 0 ) { msg_Err( p_dec, "Failed to initialize faad using extra data" ); NeAACDecClose( p_sys->hfaad ); free( p_sys ); return VLC_EGENERIC; } p_dec->fmt_out.audio.i_rate = i_rate; p_dec->fmt_out.audio.i_channels = i_channels; p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_guessed[i_channels]; date_Init( &p_sys->date, i_rate, 1 ); } else { /* Will be initalised from first frame */ p_dec->fmt_out.audio.i_rate = 0; p_dec->fmt_out.audio.i_channels = 0; } /* Set the faad config */ cfg = NeAACDecGetCurrentConfiguration( p_sys->hfaad ); if( p_dec->fmt_in.audio.i_rate ) cfg->defSampleRate = p_dec->fmt_in.audio.i_rate; cfg->outputFormat = HAVE_FPU ? FAAD_FMT_FLOAT : FAAD_FMT_16BIT; NeAACDecSetConfiguration( p_sys->hfaad, cfg ); /* buffer */ p_sys->i_buffer = p_sys->i_buffer_size = 0; p_sys->p_buffer = NULL; p_sys->b_sbr = p_sys->b_ps = false; p_dec->pf_decode_audio = DecodeBlock; p_dec->pf_flush = Flush; return VLC_SUCCESS; }
int decodeMP4file(char *sndfile, aac_dec_opt *opt) { int track; unsigned long samplerate; unsigned char channels; void *sample_buffer; mp4ff_t *infile; FILE *mp4File; int sampleId, numSamples; audio_file *aufile; NeAACDecHandle hDecoder; NeAACDecFrameInfo frameInfo; unsigned char *buffer; int buffer_size; int first_time = 1; /* initialise the callback structure */ mp4ff_callback_t *mp4cb = malloc(sizeof(mp4ff_callback_t)); mp4File = fopen(opt->filename, "rb"); mp4cb->read = read_callback; mp4cb->seek = seek_callback; mp4cb->user_data = mp4File; infile = mp4ff_open_read(mp4cb); if (!infile) { /* unable to open file */ error_handler("Error opening file: %s\n", opt->filename); return 1; } if ((track = GetAACTrack(infile)) < 0) { error_handler("Unable to find correct AAC sound track in the MP4 file.\n"); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return 1; } buffer = NULL; buffer_size = 0; mp4ff_get_decoder_config(infile, track, &buffer, &buffer_size); hDecoder = NeAACDecOpen(); if(NeAACDecInit2(hDecoder, buffer, buffer_size, &samplerate, &channels) < 0) { /* If some error initializing occured, skip the file */ error_handler("Error initializing decoder library.\n"); NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return 1; } if (buffer) free(buffer); numSamples = mp4ff_num_samples(infile, track); for (sampleId = 0; sampleId < numSamples; sampleId++) { int rc; /* get access unit from MP4 file */ buffer = NULL; buffer_size = 0; rc = mp4ff_read_sample(infile, track, sampleId, &buffer, &buffer_size); if (rc == 0) { error_handler("Reading from MP4 file failed.\n"); NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return 1; } sample_buffer = NeAACDecDecode(hDecoder, &frameInfo, buffer, buffer_size); if (buffer) free(buffer); opt->progress_update((long)numSamples, sampleId); /* open the sound file now that the number of channels are known */ if (first_time && !frameInfo.error) { if(opt->decode_mode == 0) { if (Set_WIN_Params (INVALID_FILEDESC, samplerate, SAMPLE_SIZE, frameInfo.channels) < 0) { error_handler("\nCan't access %s\n", "WAVE OUT"); NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return (0); } } else { aufile = open_audio_file(sndfile, samplerate, frameInfo.channels, opt->output_format, opt->file_type, aacChannelConfig2wavexChannelMask(&frameInfo)); if (aufile == NULL) { NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return 0; } } first_time = 0; } if ((frameInfo.error == 0) && (frameInfo.samples > 0)) { if(opt->decode_mode == 0) WIN_Play_Samples((short*)sample_buffer, frameInfo.channels*frameInfo.samples); else write_audio_file(aufile, sample_buffer, frameInfo.samples, 0); } if (frameInfo.error > 0) { error_handler("Error: %s\n", NeAACDecGetErrorMessage(frameInfo.error)); break; } if(stop_decoding) break; } NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); if(opt->decode_mode == 0) WIN_Audio_close(); else { if (!first_time) close_audio_file(aufile); } return frameInfo.error; }
static gboolean xmms_faad_init (xmms_xform_t *xform) { xmms_faad_data_t *data; xmms_error_t error; NeAACDecConfigurationPtr config; gint bytes_read; gulong samplerate; guchar channels; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_faad_data_t, 1); data->outbuf = g_string_new (NULL); data->buffer_size = FAAD_BUFFER_SIZE; xmms_xform_private_data_set (xform, data); data->decoder = NeAACDecOpen (); config = NeAACDecGetCurrentConfiguration (data->decoder); config->defObjectType = LC; config->defSampleRate = 44100; config->outputFormat = FAAD_FMT_16BIT; config->downMatrix = 0; config->dontUpSampleImplicitSBR = 0; NeAACDecSetConfiguration (data->decoder, config); switch (config->outputFormat) { case FAAD_FMT_16BIT: data->sampleformat = XMMS_SAMPLE_FORMAT_S16; break; case FAAD_FMT_24BIT: /* we don't have 24-bit format to use in xmms2 */ data->sampleformat = XMMS_SAMPLE_FORMAT_S32; break; case FAAD_FMT_32BIT: data->sampleformat = XMMS_SAMPLE_FORMAT_S32; break; case FAAD_FMT_FLOAT: data->sampleformat = XMMS_SAMPLE_FORMAT_FLOAT; break; case FAAD_FMT_DOUBLE: data->sampleformat = XMMS_SAMPLE_FORMAT_DOUBLE; break; } while (data->buffer_length < 8) { xmms_error_reset (&error); bytes_read = xmms_xform_read (xform, (gchar *) data->buffer + data->buffer_length, data->buffer_size - data->buffer_length, &error); data->buffer_length += bytes_read; if (bytes_read < 0) { xmms_log_error ("Error while trying to read data on init"); goto err; } else if (bytes_read == 0) { XMMS_DBG ("Not enough bytes to check the AAC header"); goto err; } } /* which type of file are we dealing with? */ data->filetype = FAAD_TYPE_UNKNOWN; if (xmms_xform_auxdata_has_val (xform, "decoder_config")) { data->filetype = FAAD_TYPE_MP4; } else if (!strncmp ((char *) data->buffer, "ADIF", 4)) { data->filetype = FAAD_TYPE_ADIF; } else { int i; /* ADTS mpeg file can be a stream and start in the middle of a * frame so we need to have extra loop check here */ for (i=0; i<data->buffer_length-1; i++) { if (data->buffer[i] == 0xff && (data->buffer[i+1]&0xf6) == 0xf0) { data->filetype = FAAD_TYPE_ADTS; g_memmove (data->buffer, data->buffer+i, data->buffer_length-i); data->buffer_length -= i; break; } } } if (data->filetype == FAAD_TYPE_ADTS || data->filetype == FAAD_TYPE_ADIF) { bytes_read = NeAACDecInit (data->decoder, data->buffer, data->buffer_length, &samplerate, &channels); } else if (data->filetype == FAAD_TYPE_MP4) { const guchar *tmpbuf; gsize tmpbuflen; guchar *copy; if (!xmms_xform_auxdata_get_bin (xform, "decoder_config", &tmpbuf, &tmpbuflen)) { XMMS_DBG ("AAC decoder config data found but it's wrong type! (something broken?)"); goto err; } copy = g_memdup (tmpbuf, tmpbuflen); bytes_read = NeAACDecInit2 (data->decoder, copy, tmpbuflen, &samplerate, &channels); g_free (copy); } if (bytes_read < 0) { XMMS_DBG ("Error initializing decoder library."); goto err; } /* Get mediainfo and skip the possible header */ xmms_faad_get_mediainfo (xform); g_memmove (data->buffer, data->buffer + bytes_read, data->buffer_length - bytes_read); data->buffer_length -= bytes_read; data->samplerate = samplerate; data->channels = channels; /* Because for HE AAC files some versions of libfaad return the wrong * samplerate in init, we have to do one read and let it decide the * real parameters. After changing sample parameters and format is * supported, this hack should be removed and handled in read instead. */ { gchar tmpbuf[1024]; xmms_error_reset (&error); bytes_read = xmms_faad_read (xform, tmpbuf, 1024, &error); if (bytes_read <= 0) { XMMS_DBG ("First read from faad decoder failed!"); return FALSE; } g_string_prepend_len (data->outbuf, tmpbuf, bytes_read); } xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, data->sampleformat, XMMS_STREAM_TYPE_FMT_CHANNELS, data->channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->samplerate, XMMS_STREAM_TYPE_END); XMMS_DBG ("AAC decoder inited successfully!"); return TRUE; err: g_string_free (data->outbuf, TRUE); g_free (data); return FALSE; }
/* player thread; for every song a new thread is started * @param audioPlayer structure * @return PLAYER_RET_* */ void *BarPlayerThread (void *data) { struct audioPlayer *player = data; char extraHeaders[32]; void *ret = PLAYER_RET_OK; #ifdef ENABLE_FAAD NeAACDecConfigurationPtr conf; #endif WaitressReturn_t wRet = WAITRESS_RET_ERR; /* init handles */ player->waith.data = (void *) player; /* extraHeaders will be initialized later */ player->waith.extraHeaders = extraHeaders; player->buffer = malloc (BAR_PLAYER_BUFSIZE); switch (player->audioFormat) { #ifdef ENABLE_FAAD case PIANO_AF_AACPLUS: player->aacHandle = NeAACDecOpen(); /* set aac conf */ conf = NeAACDecGetCurrentConfiguration(player->aacHandle); conf->outputFormat = FAAD_FMT_16BIT; conf->downMatrix = 1; NeAACDecSetConfiguration(player->aacHandle, conf); player->waith.callback = BarPlayerAACCb; break; #endif /* ENABLE_FAAD */ #ifdef ENABLE_MAD case PIANO_AF_MP3: mad_stream_init (&player->mp3Stream); mad_frame_init (&player->mp3Frame); mad_synth_init (&player->mp3Synth); player->waith.callback = BarPlayerMp3Cb; break; #endif /* ENABLE_MAD */ default: /* FIXME: leaks memory */ BarUiMsg (player->settings, MSG_ERR, "Unsupported audio format!\n"); return PLAYER_RET_OK; break; } player->mode = PLAYER_INITIALIZED; /* This loop should work around song abortions by requesting the * missing part of the song */ do { snprintf (extraHeaders, sizeof (extraHeaders), "Range: bytes=%zu-\r\n", player->bytesReceived); wRet = WaitressFetchCall (&player->waith); } while (wRet == WAITRESS_RET_PARTIAL_FILE || wRet == WAITRESS_RET_TIMEOUT || wRet == WAITRESS_RET_READ_ERR); /* If the song was played all the way through tag it. */ if (wRet == WAITRESS_RET_OK) { BarFlyTag(&player->fly, player->settings); } switch (player->audioFormat) { #ifdef ENABLE_FAAD case PIANO_AF_AACPLUS: NeAACDecClose(player->aacHandle); free (player->sampleSize); break; #endif /* ENABLE_FAAD */ #ifdef ENABLE_MAD case PIANO_AF_MP3: mad_synth_finish (&player->mp3Synth); mad_frame_finish (&player->mp3Frame); mad_stream_finish (&player->mp3Stream); break; #endif /* ENABLE_MAD */ default: /* this should never happen: thread is aborted above */ break; } if (player->aoError) { ret = (void *) PLAYER_RET_ERR; } ao_close(player->audioOutDevice); WaitressFree (&player->waith); free (player->buffer); player->mode = PLAYER_FINISHED_PLAYBACK; return ret; }
// 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; }
bool DecoderAAC::initialize() { m_bitrate = 0; m_totalTime = 0; if (!input()) { qWarning("DecoderAAC: cannot initialize. No input."); return false; } if (!m_input_buf) m_input_buf = new char[AAC_BUFFER_SIZE]; m_input_at = 0; if (!input()->isOpen()) { if (!input()->open(QIODevice::ReadOnly)) { qWarning("DecoderAAC: %s", qPrintable(input()->errorString ())); return false; } } AACFile aac_file(input()); if (!aac_file.isValid()) { qWarning("DecoderAAC: unsupported AAC file"); return false; } //skip id3 tag and partial frame if(aac_file.offset() > 0) { qDebug("DecoderAAC: header offset = %d bytes", aac_file.offset()); char data[aac_file.offset()]; input()->read(data, aac_file.offset()); } m_totalTime = aac_file.length() * 1000; m_bitrate = aac_file.bitrate(); if (!m_data) m_data = new aac_data; data()->handle = NeAACDecOpen(); NeAACDecConfigurationPtr conf; conf = NeAACDecGetCurrentConfiguration(data()->handle); conf->downMatrix = 1; conf->defSampleRate = 44100; conf->dontUpSampleImplicitSBR = 0; conf->defObjectType = LC; conf->outputFormat = FAAD_FMT_16BIT; NeAACDecSetConfiguration(data()->handle, conf); m_input_at = input()->read((char *)m_input_buf, AAC_BUFFER_SIZE); #ifdef FAAD_MODIFIED uint32_t freq = 0; uint8_t chan = 0; #else unsigned long freq = 0; unsigned char chan = 0; #endif int res = NeAACDecInit (data()->handle, (unsigned char*) m_input_buf, m_input_at, &freq, &chan); if (res < 0) { qWarning("DecoderAAC: NeAACDecInit() failed"); return false; } if (!freq || !chan) { qWarning("DecoderAAC: invalid sound parameters"); return false; } memmove(m_input_buf, m_input_buf + res, m_input_at - res); m_input_at -= res; configure(freq, chan, Qmmp::PCM_S16LE); qDebug("DecoderAAC: initialize succes"); return true; }
bool SoundSourceM4A::openDecoder() { DEBUG_ASSERT(m_hDecoder == nullptr); // not already opened m_hDecoder = NeAACDecOpen(); if (m_hDecoder == nullptr) { qWarning() << "Failed to open the AAC decoder!"; return false; } NeAACDecConfigurationPtr pDecoderConfig = NeAACDecGetCurrentConfiguration( m_hDecoder); pDecoderConfig->outputFormat = FAAD_FMT_FLOAT; if ((kChannelCountMono == m_audioSrcCfg.getChannelCount()) || (kChannelCountStereo == m_audioSrcCfg.getChannelCount())) { pDecoderConfig->downMatrix = 1; } else { pDecoderConfig->downMatrix = 0; } pDecoderConfig->defObjectType = LC; if (!NeAACDecSetConfiguration(m_hDecoder, pDecoderConfig)) { qWarning() << "Failed to configure AAC decoder!"; return false; } u_int8_t* configBuffer = nullptr; u_int32_t configBufferSize = 0; if (!MP4GetTrackESConfiguration(m_hFile, m_trackId, &configBuffer, &configBufferSize)) { // Failed to get mpeg-4 audio config... this is ok. // NeAACDecInit2() will simply use default values instead. qWarning() << "Failed to read the MP4 audio configuration." << "Continuing with default values."; } SAMPLERATE_TYPE samplingRate; unsigned char channelCount; if (0 > NeAACDecInit2(m_hDecoder, configBuffer, configBufferSize, &samplingRate, &channelCount)) { free(configBuffer); qWarning() << "Failed to initialize the AAC decoder!"; return false; } else { free(configBuffer); } // Calculate how many sample blocks we need to decode in advance // of a random seek in order to get the recommended number of // prefetch frames m_numberOfPrefetchSampleBlocks = (kNumberOfPrefetchFrames + (m_framesPerSampleBlock - 1)) / m_framesPerSampleBlock; setChannelCount(channelCount); setSamplingRate(samplingRate); setFrameCount(((m_maxSampleBlockId - kSampleBlockIdMin) + 1) * m_framesPerSampleBlock); // Resize temporary buffer for decoded sample data const SINT sampleBufferCapacity = frames2samples(m_framesPerSampleBlock); m_sampleBuffer.resetCapacity(sampleBufferCapacity); // Discard all buffered samples m_inputBufferLength = 0; // Invalidate current position(s) for the following seek operation m_curSampleBlockId = MP4_INVALID_SAMPLE_ID; m_curFrameIndex = getMaxFrameIndex(); // (Re-)Start decoding at the beginning of the file seekSampleFrame(getMinFrameIndex()); return m_curFrameIndex == getMinFrameIndex(); }
/* this is called for each file to process */ enum codec_status codec_run(void) { size_t n; int32_t bread; unsigned int frame_samples; uint32_t s = 0; unsigned char c = 0; long action = CODEC_ACTION_NULL; intptr_t param; unsigned char* buffer; NeAACDecFrameInfo frame_info; NeAACDecHandle decoder; NeAACDecConfigurationPtr conf; /* Clean and initialize decoder structures */ if (codec_init()) { LOGF("FAAD: Codec init error\n"); return CODEC_ERROR; } ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); ci->seek_buffer(ci->id3->first_frame_offset); /* initialise the sound converter */ decoder = NeAACDecOpen(); if (!decoder) { LOGF("FAAD: Decode open error\n"); return CODEC_ERROR; } conf = NeAACDecGetCurrentConfiguration(decoder); conf->outputFormat = FAAD_FMT_24BIT; /* irrelevant, we don't convert */ NeAACDecSetConfiguration(decoder, conf); buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE); bread = NeAACDecInit(decoder, buffer, n, &s, &c); if (bread < 0) { LOGF("FAAD: DecInit: %ld, %d\n", bread, decoder->object_type); return CODEC_ERROR; } ci->advance_buffer(bread); if (ci->id3->offset > ci->id3->first_frame_offset) { /* Resume the desired (byte) position. */ ci->seek_buffer(ci->id3->offset); NeAACDecPostSeekReset(decoder, 0); update_playing_time(); } else if (ci->id3->elapsed) { action = CODEC_ACTION_SEEK_TIME; param = ci->id3->elapsed; } else { ci->set_elapsed(0); ci->set_offset(ci->id3->first_frame_offset); } /* The main decoding loop */ while (1) { if (action == CODEC_ACTION_NULL) action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; /* Deal with any pending seek requests */ if (action == CODEC_ACTION_SEEK_TIME) { /* Seek to the desired time position. */ ci->seek_buffer(ci->id3->first_frame_offset + (uint32_t)((uint64_t)param * ci->id3->bitrate / 8)); ci->set_elapsed((unsigned long)param); NeAACDecPostSeekReset(decoder, 0); ci->seek_complete(); } action = CODEC_ACTION_NULL; /* Request the required number of bytes from the input buffer */ buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE); if (n == 0) /* End of Stream */ break; /* Decode one block - returned samples will be host-endian */ if (NeAACDecDecode(decoder, &frame_info, buffer, n) == NULL || frame_info.error > 0) { LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error)); return CODEC_ERROR; } /* Advance codec buffer (no need to call set_offset because of this) */ ci->advance_buffer(frame_info.bytesconsumed); /* Output the audio */ ci->yield(); frame_samples = frame_info.samples >> 1; ci->pcmbuf_insert(&decoder->time_out[0][0], &decoder->time_out[1][0], frame_samples); /* Update the elapsed-time indicator */ update_playing_time(); } LOGF("AAC: Decoding complete\n"); return CODEC_OK; }
int decoder_aac_open(struct decoder **decoder, const unsigned char *dec_config, size_t dec_config_size, unsigned long *samplerate, unsigned char *channels) { NeAACDecConfigurationPtr config; struct decoder *dec; int ret; /* Alloc structure */ *decoder = malloc(sizeof(struct decoder)); if(*decoder == NULL) return -1; dec = *decoder; /* Init structure */ dec->pcm_buffer = NULL; dec->pcm_length = 0; dec->pcm_remain = 0; /* Initialize faad */ dec->hDec = NeAACDecOpen(); /* Set the default object type and samplerate */ config = NeAACDecGetCurrentConfiguration(dec->hDec); #ifdef USE_FLOAT config->outputFormat = FAAD_FMT_FLOAT; #else config->outputFormat = FAAD_FMT_24BIT; #endif NeAACDecSetConfiguration(dec->hDec, config); /* PCM data remaining in output buffer */ dec->pcm_remain = 0; /* Check if ADTS or ADIF header */ if(dec_config != NULL && ((dec_config[0] == 0xFF && (dec_config[1] & 0xF6) == 0xF0) || memcmp(dec_config, "ADIF", 4) == 0)) { /* Init decoder from frame */ ret = NeAACDecInit(dec->hDec, (unsigned char *) dec_config, dec_config_size, &dec->samplerate, &dec->channels); } else { /* Init decoder */ ret = NeAACDecInit2(dec->hDec, (unsigned char *) dec_config, dec_config_size, &dec->samplerate, &dec->channels); } /* Check init return */ if(ret < 0) { NeAACDecClose(dec->hDec); dec->hDec = NULL; return -1; } /* Retunr samplerate and channels */ if(samplerate != NULL) *samplerate = dec->samplerate; if(channels != NULL) *channels = dec->channels; return 0; }
Result SoundSourceM4A::tryOpen(const AudioSourceConfig& audioSrcCfg) { DEBUG_ASSERT(MP4_INVALID_FILE_HANDLE == m_hFile); // open MP4 file, check for >= ver 1.9.1 // From mp4v2/file.h: // * On Windows, this should be a UTF-8 encoded string. // * On other platforms, it should be an 8-bit encoding that is // * appropriate for the platform, locale, file system, etc. // * (prefer to use UTF-8 when possible). #if MP4V2_PROJECT_version_hex <= 0x00010901 m_hFile = MP4Read(getLocalFileName().toUtf8().constData(), 0); #else m_hFile = MP4Read(getLocalFileName().toUtf8().constData()); #endif if (MP4_INVALID_FILE_HANDLE == m_hFile) { qWarning() << "Failed to open file for reading:" << getUrlString(); return ERR; } m_trackId = findFirstAudioTrackId(m_hFile); if (MP4_INVALID_TRACK_ID == m_trackId) { qWarning() << "No AAC track found:" << getUrlString(); return ERR; } // Read fixed sample duration. If the sample duration is not // fixed (that is, if the number of frames per sample block varies // through the file), the call returns MP4_INVALID_DURATION. We // can't currently handle these. m_framesPerSampleBlock = MP4GetTrackFixedSampleDuration(m_hFile, m_trackId); if (MP4_INVALID_DURATION == m_framesPerSampleBlock) { qWarning() << "Unable to decode tracks with non-fixed sample durations: " << getUrlString(); return ERR; } const MP4SampleId numberOfSamples = MP4GetTrackNumberOfSamples(m_hFile, m_trackId); if (0 >= numberOfSamples) { qWarning() << "Failed to read number of samples from file:" << getUrlString(); return ERR; } m_maxSampleBlockId = kSampleBlockIdMin + (numberOfSamples - 1); // Determine the maximum input size (in bytes) of a // sample block for the selected track. const u_int32_t maxSampleBlockInputSize = MP4GetTrackMaxSampleSize(m_hFile, m_trackId); m_inputBuffer.resize(maxSampleBlockInputSize, 0); DEBUG_ASSERT(nullptr == m_hDecoder); // not already opened m_hDecoder = NeAACDecOpen(); if (!m_hDecoder) { qWarning() << "Failed to open the AAC decoder!"; return ERR; } NeAACDecConfigurationPtr pDecoderConfig = NeAACDecGetCurrentConfiguration( m_hDecoder); pDecoderConfig->outputFormat = FAAD_FMT_FLOAT; if ((kChannelCountMono == audioSrcCfg.channelCountHint) || (kChannelCountStereo == audioSrcCfg.channelCountHint)) { pDecoderConfig->downMatrix = 1; } else { pDecoderConfig->downMatrix = 0; } pDecoderConfig->defObjectType = LC; if (!NeAACDecSetConfiguration(m_hDecoder, pDecoderConfig)) { qWarning() << "Failed to configure AAC decoder!"; return ERR; } u_int8_t* configBuffer = nullptr; u_int32_t configBufferSize = 0; if (!MP4GetTrackESConfiguration(m_hFile, m_trackId, &configBuffer, &configBufferSize)) { /* failed to get mpeg-4 audio config... this is ok. * NeAACDecInit2() will simply use default values instead. */ qWarning() << "Failed to read the MP4 audio configuration." << "Continuing with default values."; } SAMPLERATE_TYPE sampleRate; unsigned char channelCount; if (0 > NeAACDecInit2(m_hDecoder, configBuffer, configBufferSize, &sampleRate, &channelCount)) { free(configBuffer); qWarning() << "Failed to initialize the AAC decoder!"; return ERR; } else { free(configBuffer); } // Calculate how many sample blocks we need to decode in advance // of a random seek in order to get the recommended number of // prefetch frames m_numberOfPrefetchSampleBlocks = (kNumberOfPrefetchFrames + (m_framesPerSampleBlock - 1)) / m_framesPerSampleBlock; setChannelCount(channelCount); setFrameRate(sampleRate); setFrameCount(((m_maxSampleBlockId - kSampleBlockIdMin) + 1) * m_framesPerSampleBlock); // Resize temporary buffer for decoded sample data const SINT sampleBufferCapacity = frames2samples(m_framesPerSampleBlock); m_sampleBuffer.resetCapacity(sampleBufferCapacity); // Invalidate current position to enforce the following // seek operation m_curFrameIndex = getMaxFrameIndex(); // (Re-)Start decoding at the beginning of the file seekSampleFrame(getMinFrameIndex()); return OK; }
static int aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) { aac_info_t *info = (aac_info_t *)_info; deadbeef->pl_lock (); info->file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI")); deadbeef->pl_unlock (); 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; 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; if (!info->file->vfs->is_streaming ()) { trace ("aac_init: mp4ff_open_read %s\n", deadbeef->pl_find_meta (it, ":URI")); info->mp4 = mp4ff_open_read (&info->mp4reader); if (info->mp4) { int ntracks = mp4ff_total_tracks (info->mp4); for (int i = 0; i < ntracks; i++) { if (mp4ff_get_track_type (info->mp4, i) != TRACK_AUDIO) { continue; } int res = mp4_track_get_info (info->mp4, i, &duration, &samplerate, &channels, &totalsamples, &info->mp4framesize); if (res >= 0 && duration > 0) { info->mp4track = i; break; } } trace ("track: %d\n", info->mp4track); if (info->mp4track >= 0) { // prepare decoder int res = mp4_track_get_info (info->mp4, info->mp4track, &duration, &samplerate, &channels, &totalsamples, &info->mp4framesize); if (res != 0) { trace ("aac: mp4_track_get_info(%d) returned error\n", info->mp4track); return -1; } // init mp4 decoding info->mp4samples = mp4ff_num_samples(info->mp4, info->mp4track); info->dec = NeAACDecOpen (); unsigned long srate; unsigned char ch; unsigned char* buff = 0; unsigned int buff_size = 0; mp4AudioSpecificConfig mp4ASC; mp4ff_get_decoder_config (info->mp4, info->mp4track, &buff, &buff_size); if (NeAACDecInit2(info->dec, buff, buff_size, &srate, &ch) < 0) { trace ("NeAACDecInit2 returned error\n"); free (buff); return -1; } if (buff) { free (buff); } trace ("aac: successfully initialized track %d\n", info->mp4track); _info->fmt.samplerate = samplerate; _info->fmt.channels = channels; } else { trace ("aac: track not found in mp4 container\n"); mp4ff_close (info->mp4); info->mp4 = NULL; } } if (!info->mp4) { trace ("aac: looking for raw 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->mp4) { trace ("NeAACDecOpen for raw stream\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; } } if (_info->fmt.channels == 7) { _info->fmt.channels = 8; } trace ("totalsamples: %d, endsample: %d, samples-from-duration: %d, samplerate %d, channels %d\n", totalsamples-1, info->endsample, (int)deadbeef->pl_get_item_duration (it)*44100, _info->fmt.samplerate, _info->fmt.channels); 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; }
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); } }
/* player thread; for every song a new thread is started * @param audioPlayer structure * @return PLAYER_RET_* */ void *BarPlayerThread (void *data) { struct audioPlayer *player = data; char extraHeaders[32]; void *ret = PLAYER_RET_OK; #ifdef ENABLE_FAAD NeAACDecConfigurationPtr conf; #endif WaitressReturn_t wRet = WAITRESS_RET_ERR; /* init handles */ pthread_mutex_init (&player->pauseMutex, NULL); player->waith.data = (void *) player; /* extraHeaders will be initialized later */ player->waith.extraHeaders = extraHeaders; player->buffer = malloc (BAR_PLAYER_BUFSIZE); switch (player->audioFormat) { #ifdef ENABLE_FAAD case PIANO_AF_AACPLUS: player->aacHandle = NeAACDecOpen(); /* set aac conf */ conf = NeAACDecGetCurrentConfiguration(player->aacHandle); conf->outputFormat = FAAD_FMT_16BIT; conf->downMatrix = 1; NeAACDecSetConfiguration(player->aacHandle, conf); player->waith.callback = BarPlayerAACCb; break; #endif /* ENABLE_FAAD */ #ifdef ENABLE_MAD case PIANO_AF_MP3: mad_stream_init (&player->mp3Stream); mad_frame_init (&player->mp3Frame); mad_synth_init (&player->mp3Synth); player->waith.callback = BarPlayerMp3Cb; break; #endif /* ENABLE_MAD */ default: BarUiMsg (player->settings, MSG_ERR, "Unsupported audio format!\n"); ret = (void *) PLAYER_RET_HARDFAIL; goto cleanup; break; } player->mode = PLAYER_INITIALIZED; /* This loop should work around song abortions by requesting the * missing part of the song */ do { snprintf (extraHeaders, sizeof (extraHeaders), "Range: bytes=%zu-\r\n", player->bytesReceived); wRet = WaitressFetchCall (&player->waith); } while (wRet == WAITRESS_RET_PARTIAL_FILE || wRet == WAITRESS_RET_TIMEOUT || wRet == WAITRESS_RET_READ_ERR); switch (player->audioFormat) { #ifdef ENABLE_FAAD case PIANO_AF_AACPLUS: NeAACDecClose(player->aacHandle); free (player->sampleSize); break; #endif /* ENABLE_FAAD */ #ifdef ENABLE_MAD case PIANO_AF_MP3: mad_synth_finish (&player->mp3Synth); mad_frame_finish (&player->mp3Frame); mad_stream_finish (&player->mp3Stream); break; #endif /* ENABLE_MAD */ default: /* this should never happen */ assert (0); break; } if (player->aoError) { ret = (void *) PLAYER_RET_HARDFAIL; } /* Pandora sends broken audio url’s sometimes (“bad request”). ignore them. */ if (wRet != WAITRESS_RET_OK && wRet != WAITRESS_RET_CB_ABORT) { BarUiMsg (player->settings, MSG_ERR, "Cannot access audio file: %s\n", WaitressErrorToStr (wRet)); ret = (void *) PLAYER_RET_SOFTFAIL; } cleanup: ao_close (player->audioOutDevice); WaitressFree (&player->waith); free (player->buffer); player->mode = PLAYER_FINISHED_PLAYBACK; return ret; }
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; }
static int audio_decoder_init( #ifndef WIN32 audio_decoder_operations_t *adec_ops, #endif char *outbuf, int *outlen, char *inbuf, int inlen, long *inbuf_consumed) { unsigned long samplerate; unsigned char channels; int ret; NeAACDecConfigurationPtr config = NULL; char *in_buf; int inbuf_size; in_buf = inbuf; inbuf_size = inlen; int nReadLen=0; FaadContext *gFaadCxt = (FaadContext*)adec_ops->pdecoder; int islatm = 0; if(!in_buf || !inbuf_size ||!outbuf){ audio_codec_print(" input/output buffer null or input len is 0 \n"); } retry: //fixed to LATM aac frame header sync to speed up seek speed #if 1 if(adec_ops->nAudioDecoderType == ACODEC_FMT_AAC_LATM){ islatm = 1; int nSeekNum = AACFindLATMSyncWord(in_buf,inbuf_size); if(nSeekNum == (inbuf_size-2)){ audio_codec_print("[%s]%d bytes data not found latm sync header \n",__FUNCTION__,nSeekNum); } else{ audio_codec_print("[%s]latm seek sync header cost %d,total %d,left %d \n",__FUNCTION__,nSeekNum,inbuf_size,inbuf_size - nSeekNum); } inbuf_size = inbuf_size - nSeekNum; if(inbuf_size < (get_frame_size(gFaadCxt)+FRAME_SIZE_MARGIN)/*AAC_INPUTBUF_SIZE/2*/){ audio_codec_print("[%s]input size %d at least %d ,need more data \n",__FUNCTION__,inbuf_size,(get_frame_size(gFaadCxt)+FRAME_SIZE_MARGIN)); *inbuf_consumed = inlen-inbuf_size; return AAC_ERROR_NO_ENOUGH_DATA; } } #endif gFaadCxt->hDecoder = NeAACDecOpen(); config = NeAACDecGetCurrentConfiguration(gFaadCxt->hDecoder); config->defObjectType = LC; config->outputFormat = FAAD_FMT_16BIT; config->downMatrix = 0x01; config->useOldADTSFormat = 0; //config->dontUpSampleImplicitSBR = 1; NeAACDecSetConfiguration(gFaadCxt->hDecoder, config); if ((ret = NeAACDecInit(gFaadCxt->hDecoder, in_buf,inbuf_size, &samplerate, &channels,islatm)) < 0) { in_buf += RSYNC_SKIP_BYTES; inbuf_size -= RSYNC_SKIP_BYTES; NeAACDecClose(gFaadCxt->hDecoder); gFaadCxt->hDecoder=NULL; if(inbuf_size < 0) inbuf_size = 0; audio_codec_print("init fail,inbuf_size %d \n",inbuf_size); if(inbuf_size < (get_frame_size(gFaadCxt)+FRAME_SIZE_MARGIN)/*AAC_INPUTBUF_SIZE/2*/){ audio_codec_print("input size %d at least %d ,need more data \n",inbuf_size,(get_frame_size(gFaadCxt)+FRAME_SIZE_MARGIN)); *inbuf_consumed = inlen-inbuf_size; return AAC_ERROR_NO_ENOUGH_DATA; } goto retry; } audio_codec_print("init sucess cost %d\n",ret); in_buf += ret; inbuf_size -= ret; *inbuf_consumed = inlen- inbuf_size; NeAACDecStruct* hDecoder = (NeAACDecStruct*)(gFaadCxt->hDecoder); gFaadCxt->init_flag=1; gFaadCxt->gChannels=channels; gFaadCxt->gSampleRate=samplerate; audio_codec_print("[%s] Init OK adif_present :%d adts_present:%d latm_present:%d,sr %d,ch %d\n",__FUNCTION__,hDecoder->adif_header_present,hDecoder->adts_header_present,hDecoder->latm_header_present,samplerate,channels); return 0; }
Result SoundSourceM4A::tryOpen(const AudioSourceConfig& audioSrcCfg) { DEBUG_ASSERT(MP4_INVALID_FILE_HANDLE == m_hFile); /* open MP4 file, check for >= ver 1.9.1 */ #if MP4V2_PROJECT_version_hex <= 0x00010901 m_hFile = MP4Read(getLocalFileNameBytes().constData(), 0); #else m_hFile = MP4Read(getLocalFileNameBytes().constData()); #endif if (MP4_INVALID_FILE_HANDLE == m_hFile) { qWarning() << "Failed to open file for reading:" << getUrlString(); return ERR; } m_trackId = findFirstAudioTrackId(m_hFile); if (MP4_INVALID_TRACK_ID == m_trackId) { qWarning() << "No AAC track found:" << getUrlString(); return ERR; } const MP4SampleId numberOfSamples = MP4GetTrackNumberOfSamples(m_hFile, m_trackId); if (0 >= numberOfSamples) { qWarning() << "Failed to read number of samples from file:" << getUrlString(); return ERR; } m_maxSampleBlockId = kSampleBlockIdMin + (numberOfSamples - 1); // Determine the maximum input size (in bytes) of a // sample block for the selected track. const u_int32_t maxSampleBlockInputSize = MP4GetTrackMaxSampleSize(m_hFile, m_trackId); m_inputBuffer.resize(maxSampleBlockInputSize, 0); DEBUG_ASSERT(NULL == m_hDecoder); // not already opened m_hDecoder = NeAACDecOpen(); if (!m_hDecoder) { qWarning() << "Failed to open the AAC decoder!"; return ERR; } NeAACDecConfigurationPtr pDecoderConfig = NeAACDecGetCurrentConfiguration( m_hDecoder); pDecoderConfig->outputFormat = FAAD_FMT_FLOAT; if ((kChannelCountMono == audioSrcCfg.channelCountHint) || (kChannelCountStereo == audioSrcCfg.channelCountHint)) { pDecoderConfig->downMatrix = 1; } else { pDecoderConfig->downMatrix = 0; } pDecoderConfig->defObjectType = LC; if (!NeAACDecSetConfiguration(m_hDecoder, pDecoderConfig)) { qWarning() << "Failed to configure AAC decoder!"; return ERR; } u_int8_t* configBuffer = NULL; u_int32_t configBufferSize = 0; if (!MP4GetTrackESConfiguration(m_hFile, m_trackId, &configBuffer, &configBufferSize)) { /* failed to get mpeg-4 audio config... this is ok. * NeAACDecInit2() will simply use default values instead. */ qWarning() << "Failed to read the MP4 audio configuration." << "Continuing with default values."; } SAMPLERATE_TYPE sampleRate; unsigned char channelCount; if (0 > NeAACDecInit2(m_hDecoder, configBuffer, configBufferSize, &sampleRate, &channelCount)) { free(configBuffer); qWarning() << "Failed to initialize the AAC decoder!"; return ERR; } else { free(configBuffer); } setChannelCount(channelCount); setFrameRate(sampleRate); setFrameCount(getFrameCountForSampleBlockId(m_maxSampleBlockId)); // Resize temporary buffer for decoded sample data const SINT sampleBufferCapacity = frames2samples(kFramesPerSampleBlock); m_sampleBuffer.resetCapacity(sampleBufferCapacity); // Invalidate current position to enforce the following // seek operation m_curFrameIndex = getMaxFrameIndex(); // (Re-)Start decoding at the beginning of the file seekSampleFrame(getMinFrameIndex()); return OK; }
static void *aac_open_internal (struct io_stream *stream, const char *fname) { struct aac_data *data; NeAACDecConfigurationPtr neaac_cfg; unsigned char channels; unsigned long sample_rate; int n; /* init private struct */ data = xcalloc (1, sizeof *data); data->decoder = NeAACDecOpen(); /* set decoder config */ neaac_cfg = NeAACDecGetCurrentConfiguration(data->decoder); neaac_cfg->outputFormat = FAAD_FMT_16BIT; /* force 16 bit audio */ neaac_cfg->downMatrix = 1; /* 5.1 -> stereo */ neaac_cfg->dontUpSampleImplicitSBR = 0; /* upsample, please! */ NeAACDecSetConfiguration(data->decoder, neaac_cfg); if (stream) data->stream = stream; else { data->stream = io_open (fname, 1); if (!io_ok(data->stream)) { decoder_error (&data->error, ERROR_FATAL, 0, "Can't open AAC file: %s", io_strerror(data->stream)); return data; } } /* find a frame */ if (buffer_fill_frame(data) <= 0) { decoder_error (&data->error, ERROR_FATAL, 0, "Not a valid (or unsupported) AAC file"); return data; } /* in case of a bug, make sure there is at least some data * in the buffer for NeAACDecInit() to work with. */ if (buffer_fill_min(data, 256) <= 0) { decoder_error (&data->error, ERROR_FATAL, 0, "AAC file/stream too short"); return data; } /* init decoder, returns the length of the header (if any) */ channels = (unsigned char)data->channels; sample_rate = data->sample_rate; n = NeAACDecInit (data->decoder, buffer_data(data), buffer_length(data), &sample_rate, &channels); data->channels = channels; data->sample_rate = (int)sample_rate; if (n < 0) { decoder_error (&data->error, ERROR_FATAL, 0, "libfaad can't open this stream"); return data; } logit ("sample rate %dHz, channels %d", data->sample_rate, data->channels); if (!data->sample_rate || !data->channels) { decoder_error (&data->error, ERROR_FATAL, 0, "Invalid AAC sound parameters"); return data; } /* skip the header */ logit ("skipping header (%d bytes)", n); buffer_consume (data, n); /*NeAACDecInitDRM(data->decoder, data->sample_rate, data->channels);*/ data->ok = 1; return data; }
int decodeAACfile(char *sndfile, int def_srate, aac_dec_opt *opt) { int tagsize; unsigned long samplerate; unsigned char channels; void *sample_buffer; FILE *infile; audio_file *aufile; NeAACDecHandle hDecoder; NeAACDecFrameInfo frameInfo; NeAACDecConfigurationPtr config; int first_time = 1; /* declare variables for buffering */ DEC_BUFF_VARS infile = fopen(opt->filename, "rb"); if (infile == NULL) { /* unable to open file */ error_handler("Error opening file: %s\n", opt->filename); return 1; } INIT_BUFF(infile) tagsize = id3v2_tag(buffer); if (tagsize) { UPDATE_BUFF_SKIP(tagsize) } hDecoder = NeAACDecOpen(); /* Set the default object type and samplerate */ /* This is useful for RAW AAC files */ config = NeAACDecGetCurrentConfiguration(hDecoder); if (def_srate) config->defSampleRate = def_srate; config->defObjectType = opt->object_type; config->outputFormat = opt->output_format; NeAACDecSetConfiguration(hDecoder, config); if ((bytesconsumed = NeAACDecInit(hDecoder, buffer, bytes_in_buffer, &samplerate, &channels)) < 0) { /* If some error initializing occured, skip the file */ error_handler("Error initializing decoder library.\n"); END_BUFF NeAACDecClose(hDecoder); fclose(infile); return 1; } buffer_index += bytesconsumed; do { /* update buffer */ UPDATE_BUFF_READ sample_buffer = NeAACDecDecode(hDecoder, &frameInfo, buffer, bytes_in_buffer); /* update buffer indices */ UPDATE_BUFF_IDX(frameInfo) if (frameInfo.error > 0) { error_handler("Error: %s\n", NeAACDecGetErrorMessage(frameInfo.error)); } opt->progress_update((long)fileread, buffer_index); /* open the sound file now that the number of channels are known */ if (first_time && !frameInfo.error) { if(opt->decode_mode == 0) { if (Set_WIN_Params (INVALID_FILEDESC, samplerate, SAMPLE_SIZE, frameInfo.channels) < 0) { error_handler("\nCan't access %s\n", "WAVE OUT"); END_BUFF NeAACDecClose(hDecoder); fclose(infile); return (0); } } else { aufile = open_audio_file(sndfile, samplerate, frameInfo.channels, opt->output_format, opt->file_type, aacChannelConfig2wavexChannelMask(&frameInfo)); if (aufile == NULL) { END_BUFF NeAACDecClose(hDecoder); fclose(infile); return 0; } } first_time = 0; } if ((frameInfo.error == 0) && (frameInfo.samples > 0)) { if(opt->decode_mode == 0) WIN_Play_Samples((short*)sample_buffer, frameInfo.channels*frameInfo.samples); else write_audio_file(aufile, sample_buffer, frameInfo.samples, 0); } if (buffer_index >= fileread) sample_buffer = NULL; /* to make sure it stops now */ if(stop_decoding) break; } while (sample_buffer != NULL); NeAACDecClose(hDecoder); fclose(infile); if(opt->decode_mode == 0) WIN_Audio_close(); else { if (!first_time) close_audio_file(aufile); } END_BUFF return frameInfo.error; }
/* player thread; for every song a new thread is started * @param aacPlayer structure * @return NULL NULL NULL ... */ void *BarPlayerThread (void *data) { struct audioPlayer *player = data; char extraHeaders[25]; void *ret = PLAYER_RET_OK; #ifdef ENABLE_FAAD NeAACDecConfigurationPtr conf; #endif WaitressReturn_t wRet = WAITRESS_RET_ERR; /* init handles */ pthread_mutex_init (&player->pauseMutex, NULL); player->scale = computeReplayGainScale (player->gain); player->waith.data = (void *) player; /* extraHeaders will be initialized later */ player->waith.extraHeaders = extraHeaders; switch (player->audioFormat) { #ifdef ENABLE_FAAD case PIANO_AF_AACPLUS: player->aacHandle = NeAACDecOpen(); /* set aac conf */ conf = NeAACDecGetCurrentConfiguration(player->aacHandle); conf->outputFormat = FAAD_FMT_16BIT; conf->downMatrix = 1; NeAACDecSetConfiguration(player->aacHandle, conf); player->waith.callback = BarPlayerAACCb; break; #endif /* ENABLE_FAAD */ #ifdef ENABLE_MAD case PIANO_AF_MP3: case PIANO_AF_MP3_HI: mad_stream_init (&player->mp3Stream); mad_frame_init (&player->mp3Frame); mad_synth_init (&player->mp3Synth); player->waith.callback = BarPlayerMp3Cb; break; #endif /* ENABLE_MAD */ default: printf("Unsupported audio format!\n"); return PLAYER_RET_OK; break; } player->mode = PLAYER_INITIALIZED; /* This loop should work around song abortions by requesting the * missing part of the song */ do { snprintf (extraHeaders, sizeof (extraHeaders), "Range: bytes=%zu-\r\n", player->bytesReceived); wRet = WaitressFetchCall (&player->waith); } while (wRet == WAITRESS_RET_PARTIAL_FILE || wRet == WAITRESS_RET_TIMEOUT || wRet == WAITRESS_RET_READ_ERR); switch (player->audioFormat) { #ifdef ENABLE_FAAD case PIANO_AF_AACPLUS: NeAACDecClose(player->aacHandle); break; #endif /* ENABLE_FAAD */ #ifdef ENABLE_MAD case PIANO_AF_MP3: case PIANO_AF_MP3_HI: mad_synth_finish (&player->mp3Synth); mad_frame_finish (&player->mp3Frame); mad_stream_finish (&player->mp3Stream); break; #endif /* ENABLE_MAD */ default: /* this should never happen: thread is aborted above */ break; } if (player->aoError) { ret = (void *) PLAYER_RET_ERR; } if (player->audioOutDevice) ao_close(player->audioOutDevice); WaitressFree (&player->waith); #ifdef ENABLE_FAAD if (player->sampleSize != NULL) { free (player->sampleSize); } #endif /* ENABLE_FAAD */ pthread_mutex_destroy (&player->pauseMutex); player->mode = PLAYER_FINISHED_PLAYBACK; return ret; }
DecoderStatus AacDecoder::process(Packet*packet){ FXlong fs = packet->stream_position; FXbool eos = packet->flags&FLAG_EOS; long unsigned int samplerate; FXuchar channels; NeAACDecFrameInfo frame; if (packet->flags&AAC_FLAG_CONFIG) { handle = NeAACDecOpen(); if (NeAACDecInit2(handle,packet->data(),packet->size(),&samplerate,&channels)<0){ packet->unref(); return DecoderError; } return DecoderOk; } else { buffer.append(packet->data(),packet->size()); packet->unref(); if (handle==NULL) { handle = NeAACDecOpen(); long n = NeAACDecInit(handle,buffer.data(),buffer.size(),&samplerate,&channels); if (n<0) return DecoderError; else if (n>0) buffer.readBytes(n); af.set(AP_FORMAT_S16,samplerate,channels); engine->output->post(new ConfigureEvent(af,Codec::AAC)); } } if (buffer.size()<FAAD_MIN_STREAMSIZE*2) { return DecoderOk; } do { if (out==NULL){ out = engine->decoder->get_output_packet(); if (out==NULL) return DecoderInterrupted; out->af = af; out->stream_position = fs; out->stream_length = packet->stream_length; } void * outbuffer = out->ptr(); NeAACDecDecode2(handle,&frame,buffer.data(),buffer.size(),&outbuffer,out->availableFrames()*out->af.framesize()); if (frame.bytesconsumed>0) { buffer.readBytes(frame.bytesconsumed); } if (frame.error > 0) { GM_DEBUG_PRINT("[aac] error %d (%ld): %s\n",frame.error,frame.bytesconsumed,faacDecGetErrorMessage(frame.error)); } if (frame.samples) { fs+=(frame.samples/frame.channels); out->wroteFrames((frame.samples/frame.channels)); if (out->availableFrames()==0) { engine->output->post(out); out=NULL; } } } while(buffer.size()>(2*FAAD_MIN_STREAMSIZE) && frame.bytesconsumed); if (eos) { if (out) { engine->output->post(out); out=NULL; } engine->output->post(new ControlEvent(End,packet->stream)); } return DecoderOk; }
/* this is called for each file to process */ enum codec_status codec_run(void) { /* Note that when dealing with QuickTime/MPEG4 files, terminology is * a bit confusing. Files with sound are split up in chunks, where * each chunk contains one or more samples. Each sample in turn * contains a number of "sound samples" (the kind you refer to with * the sampling frequency). */ size_t n; demux_res_t demux_res; stream_t input_stream; uint32_t sound_samples_done; uint32_t elapsed_time; int file_offset; int framelength; int lead_trim = 0; unsigned int frame_samples; unsigned int i; unsigned char* buffer; NeAACDecFrameInfo frame_info; NeAACDecHandle decoder; int err; uint32_t seek_idx = 0; uint32_t s = 0; uint32_t sbr_fac = 1; unsigned char c = 0; void *ret; intptr_t param; bool empty_first_frame = false; /* Clean and initialize decoder structures */ memset(&demux_res , 0, sizeof(demux_res)); if (codec_init()) { LOGF("FAAD: Codec init error\n"); return CODEC_ERROR; } file_offset = ci->id3->offset; ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); stream_create(&input_stream,ci); ci->seek_buffer(ci->id3->first_frame_offset); /* if qtmovie_read returns successfully, the stream is up to * the movie data, which can be used directly by the decoder */ if (!qtmovie_read(&input_stream, &demux_res)) { LOGF("FAAD: File init error\n"); return CODEC_ERROR; } /* initialise the sound converter */ decoder = NeAACDecOpen(); if (!decoder) { LOGF("FAAD: Decode open error\n"); return CODEC_ERROR; } NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder); conf->outputFormat = FAAD_FMT_24BIT; /* irrelevant, we don't convert */ NeAACDecSetConfiguration(decoder, conf); err = NeAACDecInit2(decoder, demux_res.codecdata, demux_res.codecdata_len, &s, &c); if (err) { LOGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type); return CODEC_ERROR; } #ifdef SBR_DEC /* Check for need of special handling for seek/resume and elapsed time. */ if (ci->id3->needs_upsampling_correction) { sbr_fac = 2; } else { sbr_fac = 1; } #endif i = 0; if (file_offset > 0) { /* Resume the desired (byte) position. Important: When resuming SBR * upsampling files the resulting sound_samples_done must be expanded * by a factor of 2. This is done via using sbr_fac. */ if (m4a_seek_raw(&demux_res, &input_stream, file_offset, &sound_samples_done, (int*) &i)) { sound_samples_done *= sbr_fac; } else { sound_samples_done = 0; } NeAACDecPostSeekReset(decoder, i); } else { sound_samples_done = 0; } elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); ci->set_elapsed(elapsed_time); if (i == 0) { lead_trim = ci->id3->lead_trim; } /* The main decoding loop */ while (i < demux_res.num_sample_byte_sizes) { enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; /* Deal with any pending seek requests */ if (action == CODEC_ACTION_SEEK_TIME) { /* Seek to the desired time position. Important: When seeking in SBR * upsampling files the seek_time must be divided by 2 when calling * m4a_seek and the resulting sound_samples_done must be expanded * by a factor 2. This is done via using sbr_fac. */ if (m4a_seek(&demux_res, &input_stream, (param/10/sbr_fac)*(ci->id3->frequency/100), &sound_samples_done, (int*) &i)) { sound_samples_done *= sbr_fac; elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); ci->set_elapsed(elapsed_time); seek_idx = 0; if (i == 0) { lead_trim = ci->id3->lead_trim; } } NeAACDecPostSeekReset(decoder, i); ci->seek_complete(); } /* There can be gaps between chunks, so skip ahead if needed. It * doesn't seem to happen much, but it probably means that a * "proper" file can have chunks out of order. Why one would want * that an good question (but files with gaps do exist, so who * knows?), so we don't support that - for now, at least. */ file_offset = m4a_check_sample_offset(&demux_res, i, &seek_idx); if (file_offset > ci->curpos) { ci->advance_buffer(file_offset - ci->curpos); } else if (file_offset == 0) { LOGF("AAC: get_sample_offset error\n"); return CODEC_ERROR; } /* Request the required number of bytes from the input buffer */ buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE); /* Decode one block - returned samples will be host-endian */ ret = NeAACDecDecode(decoder, &frame_info, buffer, n); /* NeAACDecDecode may sometimes return NULL without setting error. */ if (ret == NULL || frame_info.error > 0) { LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error)); return CODEC_ERROR; } /* Advance codec buffer (no need to call set_offset because of this) */ ci->advance_buffer(frame_info.bytesconsumed); /* Output the audio */ ci->yield(); frame_samples = frame_info.samples >> 1; if (empty_first_frame) { /* Remove the first frame from lead_trim, under the assumption * that it had the same size as this frame */ empty_first_frame = false; lead_trim -= frame_samples; if (lead_trim < 0) { lead_trim = 0; } } /* Gather number of samples for the decoded frame. */ framelength = frame_samples - lead_trim; if (i == demux_res.num_sample_byte_sizes - 1) { // Size of the last frame const uint32_t sample_duration = (demux_res.num_time_to_samples > 0) ? demux_res.time_to_sample[demux_res.num_time_to_samples - 1].sample_duration : frame_samples; /* Currently limited to at most one frame of tail_trim. * Seems to be enough. */ if (ci->id3->tail_trim == 0 && sample_duration < frame_samples) { /* Subtract lead_trim just in case we decode a file with only * one audio frame with actual data (lead_trim is usually zero * here). */ framelength = sample_duration - lead_trim; } else { framelength -= ci->id3->tail_trim; } } if (framelength > 0) { ci->pcmbuf_insert(&decoder->time_out[0][lead_trim], &decoder->time_out[1][lead_trim], framelength); sound_samples_done += framelength; /* Update the elapsed-time indicator */ elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); ci->set_elapsed(elapsed_time); } if (lead_trim > 0) { /* frame_info.samples can be 0 for frame 0. We still want to * remove it from lead_trim, so do that during frame 1. */ if (0 == i && 0 == frame_info.samples) { empty_first_frame = true; } lead_trim -= frame_samples; if (lead_trim < 0) { lead_trim = 0; } } ++i; } LOGF("AAC: Decoded %lu samples\n", (unsigned long)sound_samples_done); return CODEC_OK; }