static gint64 xmms_faad_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err) { xmms_faad_data_t *data; gint64 ret = -1; g_return_val_if_fail (whence == XMMS_XFORM_SEEK_SET, -1); g_return_val_if_fail (xform, -1); data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, -1); /* Seeking only supported on MP4 AAC right now */ if (data->filetype == FAAD_TYPE_MP4) { gint64 location; /* Seek to some time before samples, to take care of decoder delay */ location = samples - xmms_faad_get_framesize_upper_bound (xform); if (location < 0) { location = 0; } location = xmms_xform_seek (xform, location, whence, err); if (location >= 0) { data->buffer_length = 0; g_string_erase (data->outbuf, 0, -1); NeAACDecPostSeekReset (data->decoder, -1); ret = location; } } return ret; }
static gint64 xmms_faad_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err) { xmms_faad_data_t *data; gint64 ret = -1; g_return_val_if_fail (whence == XMMS_XFORM_SEEK_SET, -1); g_return_val_if_fail (xform, -1); data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, FALSE); /* Seeking only supported on MP4 AAC right now */ if (data->filetype == FAAD_TYPE_MP4) { ret = xmms_xform_seek (xform, samples, whence, err); if (ret >= 0) { NeAACDecPostSeekReset (data->decoder, -1); data->buffer_length = 0; g_string_erase (data->outbuf, 0, -1); } } return ret; }
CAMLprim value ocaml_faad_post_seek_reset(value _dh) { CAMLparam1(_dh); NeAACDecHandle dh = Dec_val(_dh); NeAACDecPostSeekReset(dh,0); CAMLreturn(Val_unit); }
void SoundSourceM4A::restartDecoding(MP4SampleId sampleBlockId) { DEBUG_ASSERT(MP4_INVALID_SAMPLE_ID != sampleBlockId); NeAACDecPostSeekReset(m_hDecoder, sampleBlockId); m_curSampleBlockId = sampleBlockId; m_curFrameIndex = getFrameIndexForSampleBlockId(m_curSampleBlockId); // Discard input buffer m_inputBufferLength = 0; // Discard previously decoded sample data m_sampleBuffer.reset(); }
void SoundSourceM4A::restartDecoding(MP4SampleId sampleBlockId) { DEBUG_ASSERT(MP4_INVALID_SAMPLE_ID != sampleBlockId); NeAACDecPostSeekReset(m_hDecoder, sampleBlockId); m_curSampleBlockId = sampleBlockId; m_curFrameIndex = AudioSource::getMinFrameIndex() + (sampleBlockId - kSampleBlockIdMin) * m_framesPerSampleBlock; // Discard input buffer m_inputBufferLength = 0; // Discard previously decoded sample data m_sampleBuffer.reset(); }
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; const gchar *mime; 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; /* XXX: Because of decoder delay the first frame is bad (as is the first * frame after seek). Frame 0 gets automatically discarded by libfaad2 (but * not the first frame after seek). However frame 0 is included in gapless * and durations calculations... So we cheat and tell libfaad2 we're feeding * it frame 1. */ NeAACDecPostSeekReset (data->decoder, 1); /* FIXME: 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. */ xmms_error_reset (&error); if (xmms_faad_read_some (xform, &error) <= 0) { XMMS_DBG ("First read from faad decoder failed!"); return FALSE; } if (xmms_faad_gapless_try (xform)) { mime = "audio/x-uncut-pcm"; } else { mime = "audio/pcm"; } xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, mime, 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; }
void DecoderAAC::seek(qint64 pos) { input()->seek(pos * input()->size() / m_totalTime); NeAACDecPostSeekReset (data()->handle, 0); m_input_at = 0; }
/* 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; }
/* 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; }