FLAC__bool EasyFLAC__flush(EasyFLAC__StreamDecoder *decoder) { if (decoder->is_oggflac) return OggFLAC__stream_decoder_flush(decoder->oggflac); else return FLAC__stream_decoder_flush(decoder->flac); }
int FLAC_plugin__seek(FLAC__StreamDecoder *decoder, stream_data_struct *stream_data) { int pos; FLAC__uint64 target_sample = stream_data->total_samples * stream_data->seek_to / stream_data->length_in_msec; if (stream_data->total_samples > 0 && target_sample >= stream_data->total_samples && target_sample > 0) target_sample = stream_data->total_samples - 1; /* even if the seek fails we have to reset these so that we don't repeat the seek */ stream_data->seek_to = -1; stream_data->eof = false; wide_samples_in_reservoir_ = 0; pos = (int)(target_sample*1000 / stream_data->sample_rate); if (!FLAC__stream_decoder_seek_absolute(decoder, target_sample)) { if(FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_SEEK_ERROR) FLAC__stream_decoder_flush(decoder); pos = -1; } bh_index_last_o = bh_index_last_w = (pos/BITRATE_HIST_SEGMENT_MSEC) % BITRATE_HIST_SIZE; if (!FLAC__stream_decoder_get_decode_position(decoder, &decode_position)) decode_position = 0; return pos; }
SINT SoundSourceFLAC::seekSampleFrame(SINT frameIndex) { DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(isValidFrameIndex(frameIndex)); // Avoid unnecessary seeking // NOTE(uklotzde): Disabling this optimization might reveal rare // seek errors on certain FLAC files were the decoder loses sync! if (m_curFrameIndex == frameIndex) { return m_curFrameIndex; } // Discard decoded sample data before seeking m_sampleBuffer.reset(); // Seek to the new position if (FLAC__stream_decoder_seek_absolute(m_decoder, frameIndex)) { // Set the new position m_curFrameIndex = frameIndex; DEBUG_ASSERT(FLAC__STREAM_DECODER_SEEK_ERROR != FLAC__stream_decoder_get_state(m_decoder)); } else { qWarning() << "Seek error at" << frameIndex << "in" << m_file.fileName(); // Invalidate the current position m_curFrameIndex = getMaxFrameIndex(); if (FLAC__STREAM_DECODER_SEEK_ERROR == FLAC__stream_decoder_get_state(m_decoder)) { // Flush the input stream of the decoder according to the // documentation of FLAC__stream_decoder_seek_absolute() if (!FLAC__stream_decoder_flush(m_decoder)) { qWarning() << "Failed to flush input buffer of the FLAC decoder after seeking in" << m_file.fileName(); // Invalidate the current position... m_curFrameIndex = getMaxFrameIndex(); // ...and abort return m_curFrameIndex; } // Discard previously decoded sample data before decoding // the next block of samples m_sampleBuffer.reset(); // Trigger decoding of the next block to update the current position if (!FLAC__stream_decoder_process_single(m_decoder)) { qWarning() << "Failed to resync FLAC decoder after seeking in" << m_file.fileName(); // Invalidate the current position... m_curFrameIndex = getMaxFrameIndex(); // ...and abort return m_curFrameIndex; } DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); if (m_curFrameIndex < frameIndex) { // Adjust the current position skipSampleFrames(frameIndex - m_curFrameIndex); } } } DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); return m_curFrameIndex; }
static gboolean gst_flac_dec_set_format (GstAudioDecoder * dec, GstCaps * caps) { const GValue *headers; GstFlacDec *flacdec; GstStructure *s; guint i, num; flacdec = GST_FLAC_DEC (dec); GST_LOG_OBJECT (dec, "sink caps: %" GST_PTR_FORMAT, caps); s = gst_caps_get_structure (caps, 0); headers = gst_structure_get_value (s, "streamheader"); if (headers == NULL || !GST_VALUE_HOLDS_ARRAY (headers)) { GST_WARNING_OBJECT (dec, "no 'streamheader' field in input caps, try " "adding a flacparse element upstream"); return FALSE; } if (gst_adapter_available (flacdec->adapter) > 0) { GST_WARNING_OBJECT (dec, "unexpected data left in adapter"); gst_adapter_clear (flacdec->adapter); } num = gst_value_array_get_size (headers); for (i = 0; i < num; ++i) { const GValue *header_val; GstBuffer *header_buf; header_val = gst_value_array_get_value (headers, i); if (header_val == NULL || !GST_VALUE_HOLDS_BUFFER (header_val)) return FALSE; header_buf = g_value_dup_boxed (header_val); GST_INFO_OBJECT (dec, "pushing header buffer of %" G_GSIZE_FORMAT " bytes " "into adapter", gst_buffer_get_size (header_buf)); gst_adapter_push (flacdec->adapter, header_buf); } GST_DEBUG_OBJECT (dec, "Processing headers and metadata"); if (!FLAC__stream_decoder_process_until_end_of_metadata (flacdec->decoder)) { GST_WARNING_OBJECT (dec, "process_until_end_of_metadata failed"); if (FLAC__stream_decoder_get_state (flacdec->decoder) == FLAC__STREAM_DECODER_ABORTED) { GST_WARNING_OBJECT (flacdec, "Read callback caused internal abort"); /* allow recovery */ gst_adapter_clear (flacdec->adapter); FLAC__stream_decoder_flush (flacdec->decoder); gst_flac_dec_handle_decoder_error (flacdec, TRUE); } } GST_INFO_OBJECT (dec, "headers and metadata are now processed"); return TRUE; }
FLAC_API FLAC__bool FLAC__seekable_stream_decoder_flush(FLAC__SeekableStreamDecoder *decoder) { FLAC__ASSERT(0 != decoder); FLAC__ASSERT(0 != decoder->private_); FLAC__ASSERT(0 != decoder->protected_); decoder->private_->do_md5_checking = false; if(!FLAC__stream_decoder_flush(decoder->private_->stream_decoder)) { decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; return false; } decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_OK; return true; }
static void gst_flac_dec_flush (GstAudioDecoder * audio_dec, gboolean hard) { GstFlacDec *dec = GST_FLAC_DEC (audio_dec); if (!hard) { guint available = gst_adapter_available (dec->adapter); if (available > 0) { GST_INFO_OBJECT (dec, "draining, %u bytes left in adapter", available); FLAC__stream_decoder_process_until_end_of_stream (dec->decoder); } } FLAC__stream_decoder_flush (dec->decoder); gst_adapter_clear (dec->adapter); }
FLAC__bool OggFLAC__stream_decoder_flush(OggFLAC__StreamDecoder *decoder) { FLAC__ASSERT(0 != decoder); FLAC__ASSERT(0 != decoder->private_); FLAC__ASSERT(0 != decoder->protected_); (void)ogg_sync_clear(&decoder->private_->ogg.sync_state); if(!FLAC__stream_decoder_flush(decoder->private_->FLAC_stream_decoder)) { decoder->protected_->state = OggFLAC__STREAM_DECODER_FLAC_STREAM_DECODER_ERROR; return false; } decoder->protected_->state = OggFLAC__STREAM_DECODER_OK; return true; }
double FlacDecoder::SetPosition(double seconds) { FLAC__uint64 seekToSample = (FLAC__uint64)((double) this->sampleRate * seconds); if (FLAC__stream_decoder_seek_absolute(this->decoder, seekToSample)) { return seconds; } if (FLAC__stream_decoder_get_state(this->decoder) == FLAC__STREAM_DECODER_SEEK_ERROR) { if (FLAC__stream_decoder_flush(this->decoder)) { if (FLAC__stream_decoder_seek_absolute(this->decoder, seekToSample)) { return seconds; } } } return -1; }
/* read mode: * 0 - no read after seek * 1 - read 2 frames * 2 - read until end */ static FLAC__bool seek_barrage(FLAC__bool is_ogg, const char *filename, off_t filesize, unsigned count, FLAC__int64 total_samples, unsigned read_mode) { FLAC__StreamDecoder *decoder; DecoderClientData decoder_client_data; unsigned i; long int n; decoder_client_data.got_data = false; decoder_client_data.total_samples = 0; decoder_client_data.quiet = false; decoder_client_data.ignore_errors = false; decoder_client_data.error_occurred = false; printf("\n+++ seek test: FLAC__StreamDecoder (%s FLAC, read_mode=%u)\n\n", is_ogg? "Ogg":"native", read_mode); decoder = FLAC__stream_decoder_new(); if(0 == decoder) return die_("FLAC__stream_decoder_new() FAILED, returned NULL\n"); if(is_ogg) { if(FLAC__stream_decoder_init_ogg_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &decoder_client_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) return die_s_("FLAC__stream_decoder_init_file() FAILED", decoder); } else { if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &decoder_client_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) return die_s_("FLAC__stream_decoder_init_file() FAILED", decoder); } if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) return die_s_("FLAC__stream_decoder_process_until_end_of_metadata() FAILED", decoder); if(!is_ogg) { /* not necessary to do this for Ogg because of its seeking method */ /* process until end of stream to make sure we can still seek in that state */ decoder_client_data.quiet = true; if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) return die_s_("FLAC__stream_decoder_process_until_end_of_stream() FAILED", decoder); decoder_client_data.quiet = false; printf("stream decoder state is %s\n", FLAC__stream_decoder_get_resolved_state_string(decoder)); if(FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_END_OF_STREAM) return die_s_("expected FLAC__STREAM_DECODER_END_OF_STREAM", decoder); } #ifdef _MSC_VER printf("file's total_samples is %I64u\n", decoder_client_data.total_samples); #else printf("file's total_samples is %llu\n", (unsigned long long)decoder_client_data.total_samples); #endif #if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__ if (decoder_client_data.total_samples > (FLAC__uint64)RAND_MAX) { printf("ERROR: must be total_samples < %u\n", (unsigned)RAND_MAX); return false; } #endif n = (long int)decoder_client_data.total_samples; if(n == 0 && total_samples >= 0) n = (long int)total_samples; /* if we don't have a total samples count, just guess based on the file size */ /* @@@ for is_ogg we should get it from last page's granulepos */ if(n == 0) { /* 8 would imply no compression, 9 guarantees that we will get some samples off the end of the stream to test that case */ n = 9 * filesize / (decoder_client_data.channels * decoder_client_data.bits_per_sample); #if !defined _MSC_VER && !defined __MINGW32__ if(n > RAND_MAX) n = RAND_MAX; #endif } printf("Begin seek barrage, count=%u\n", count); for (i = 0; !stop_signal_ && (count == 0 || i < count); i++) { FLAC__uint64 pos; /* for the first 10, seek to the first 10 samples */ if (n >= 10 && i < 10) { pos = i; } /* for the second 10, seek to the last 10 samples */ else if (n >= 10 && i < 20) { pos = n - 1 - (i-10); } /* for the third 10, seek past the end and make sure we fail properly as expected */ else if (i < 30) { pos = n + (i-20); } else { #if !defined _MSC_VER && !defined __MINGW32__ pos = (FLAC__uint64)(random() % n); #else /* RAND_MAX is only 32767 in my MSVC */ pos = (FLAC__uint64)((rand()<<15|rand()) % n); #endif } #ifdef _MSC_VER printf("seek(%I64u)... ", pos); #else printf("seek(%llu)... ", (unsigned long long)pos); #endif fflush(stdout); if(!FLAC__stream_decoder_seek_absolute(decoder, pos)) { if(pos >= (FLAC__uint64)n) printf("seek past end failed as expected... "); else if(decoder_client_data.total_samples == 0 && total_samples <= 0) printf("seek failed, assuming it was past EOF... "); else return die_s_("FLAC__stream_decoder_seek_absolute() FAILED", decoder); if(!FLAC__stream_decoder_flush(decoder)) return die_s_("FLAC__stream_decoder_flush() FAILED", decoder); } else if(read_mode == 1) { printf("decode_frame... "); fflush(stdout); if(!FLAC__stream_decoder_process_single(decoder)) return die_s_("FLAC__stream_decoder_process_single() FAILED", decoder); printf("decode_frame... "); fflush(stdout); if(!FLAC__stream_decoder_process_single(decoder)) return die_s_("FLAC__stream_decoder_process_single() FAILED", decoder); } else if(read_mode == 2) { printf("decode_all... "); fflush(stdout); decoder_client_data.quiet = true; if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) return die_s_("FLAC__stream_decoder_process_until_end_of_stream() FAILED", decoder); decoder_client_data.quiet = false; } printf("OK\n"); fflush(stdout); } if(FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_UNINITIALIZED) { if(!FLAC__stream_decoder_finish(decoder)) return die_s_("FLAC__stream_decoder_finish() FAILED", decoder); } FLAC__stream_decoder_delete(decoder); printf("\nPASSED!\n"); return true; }
static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg) { FLAC__StreamDecoder *decoder; FLAC__StreamDecoderInitStatus init_status; FLAC__StreamDecoderState state; StreamDecoderClientData decoder_client_data; FLAC__bool expect; decoder_client_data.layer = layer; printf("\n+++ libFLAC unit test: FLAC__StreamDecoder (layer: %s, format: %s)\n\n", LayerString[layer], is_ogg? "Ogg FLAC" : "FLAC"); printf("testing FLAC__stream_decoder_new()... "); decoder = FLAC__stream_decoder_new(); if(0 == decoder) { printf("FAILED, returned NULL\n"); return false; } printf("OK\n"); printf("testing FLAC__stream_decoder_delete()... "); FLAC__stream_decoder_delete(decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_new()... "); decoder = FLAC__stream_decoder_new(); if(0 == decoder) { printf("FAILED, returned NULL\n"); return false; } printf("OK\n"); switch(layer) { case LAYER_STREAM: case LAYER_SEEKABLE_STREAM: printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0) : FLAC__stream_decoder_init_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; case LAYER_FILE: printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_FILE(decoder, stdin, 0, 0, 0, 0) : FLAC__stream_decoder_init_FILE(decoder, stdin, 0, 0, 0, 0); break; case LAYER_FILENAME: printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0) : FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0); break; default: die_("internal error 003"); return false; } if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS) return die_s_(0, decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_delete()... "); FLAC__stream_decoder_delete(decoder); printf("OK\n"); num_expected_ = 0; expected_metadata_sequence_[num_expected_++] = &streaminfo_; printf("testing FLAC__stream_decoder_new()... "); decoder = FLAC__stream_decoder_new(); if(0 == decoder) { printf("FAILED, returned NULL\n"); return false; } printf("OK\n"); if(is_ogg) { printf("testing FLAC__stream_decoder_set_ogg_serial_number()... "); if(!FLAC__stream_decoder_set_ogg_serial_number(decoder, file_utils__ogg_serial_number)) return die_s_("returned false", decoder); printf("OK\n"); } printf("testing FLAC__stream_decoder_set_md5_checking()... "); if(!FLAC__stream_decoder_set_md5_checking(decoder, true)) return die_s_("returned false", decoder); printf("OK\n"); if(layer < LAYER_FILENAME) { printf("opening %sFLAC file... ", is_ogg? "Ogg ":""); decoder_client_data.file = fopen(flacfilename(is_ogg), "rb"); if(0 == decoder_client_data.file) { printf("ERROR (%s)\n", strerror(errno)); return false; } printf("OK\n"); } switch(layer) { case LAYER_STREAM: printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); break; case LAYER_SEEKABLE_STREAM: printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); break; case LAYER_FILE: printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : FLAC__stream_decoder_init_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); break; case LAYER_FILENAME: printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); break; default: die_("internal error 009"); return false; } if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) return die_s_(0, decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_get_state()... "); state = FLAC__stream_decoder_get_state(decoder); printf("returned state = %u (%s)... OK\n", state, FLAC__StreamDecoderStateString[state]); decoder_client_data.current_metadata_number = 0; decoder_client_data.ignore_errors = false; decoder_client_data.error_occurred = false; printf("testing FLAC__stream_decoder_get_md5_checking()... "); if(!FLAC__stream_decoder_get_md5_checking(decoder)) { printf("FAILED, returned false, expected true\n"); return false; } printf("OK\n"); printf("testing FLAC__stream_decoder_process_until_end_of_metadata()... "); if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_process_single()... "); if(!FLAC__stream_decoder_process_single(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_skip_single_frame()... "); if(!FLAC__stream_decoder_skip_single_frame(decoder)) return die_s_("returned false", decoder); printf("OK\n"); if(layer < LAYER_FILE) { printf("testing FLAC__stream_decoder_flush()... "); if(!FLAC__stream_decoder_flush(decoder)) return die_s_("returned false", decoder); printf("OK\n"); decoder_client_data.ignore_errors = true; printf("testing FLAC__stream_decoder_process_single()... "); if(!FLAC__stream_decoder_process_single(decoder)) return die_s_("returned false", decoder); printf("OK\n"); decoder_client_data.ignore_errors = false; } expect = (layer != LAYER_STREAM); printf("testing FLAC__stream_decoder_seek_absolute()... "); if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect) return die_s_(expect? "returned false" : "returned true", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_process_until_end_of_stream()... "); if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) return die_s_("returned false", decoder); printf("OK\n"); expect = (layer != LAYER_STREAM); printf("testing FLAC__stream_decoder_seek_absolute()... "); if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect) return die_s_(expect? "returned false" : "returned true", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_get_channels()... "); { unsigned channels = FLAC__stream_decoder_get_channels(decoder); if(channels != streaminfo_.data.stream_info.channels) { printf("FAILED, returned %u, expected %u\n", channels, streaminfo_.data.stream_info.channels); return false; } } printf("OK\n"); printf("testing FLAC__stream_decoder_get_bits_per_sample()... "); { unsigned bits_per_sample = FLAC__stream_decoder_get_bits_per_sample(decoder); if(bits_per_sample != streaminfo_.data.stream_info.bits_per_sample) { printf("FAILED, returned %u, expected %u\n", bits_per_sample, streaminfo_.data.stream_info.bits_per_sample); return false; } } printf("OK\n"); printf("testing FLAC__stream_decoder_get_sample_rate()... "); { unsigned sample_rate = FLAC__stream_decoder_get_sample_rate(decoder); if(sample_rate != streaminfo_.data.stream_info.sample_rate) { printf("FAILED, returned %u, expected %u\n", sample_rate, streaminfo_.data.stream_info.sample_rate); return false; } } printf("OK\n"); printf("testing FLAC__stream_decoder_get_blocksize()... "); { unsigned blocksize = FLAC__stream_decoder_get_blocksize(decoder); /* value could be anything since we're at the last block, so accept any reasonable answer */ printf("returned %u... %s\n", blocksize, blocksize>0? "OK" : "FAILED"); if(blocksize == 0) return false; } printf("testing FLAC__stream_decoder_get_channel_assignment()... "); { FLAC__ChannelAssignment ca = FLAC__stream_decoder_get_channel_assignment(decoder); printf("returned %u (%s)... OK\n", (unsigned)ca, FLAC__ChannelAssignmentString[ca]); } if(layer < LAYER_FILE) { printf("testing FLAC__stream_decoder_reset()... "); if(!FLAC__stream_decoder_reset(decoder)) { state = FLAC__stream_decoder_get_state(decoder); printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__StreamDecoderStateString[state]); return false; } printf("OK\n"); if(layer == LAYER_STREAM) { /* after a reset() we have to rewind the input ourselves */ printf("rewinding input... "); if(fseeko(decoder_client_data.file, 0, SEEK_SET) < 0) { printf("FAILED, errno = %d\n", errno); return false; } printf("OK\n"); } decoder_client_data.current_metadata_number = 0; printf("testing FLAC__stream_decoder_process_until_end_of_stream()... "); if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) return die_s_("returned false", decoder); printf("OK\n"); } printf("testing FLAC__stream_decoder_finish()... "); if(!FLAC__stream_decoder_finish(decoder)) return die_s_("returned false", decoder); printf("OK\n"); /* * respond all */ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) return die_s_("returned false", decoder); printf("OK\n"); num_expected_ = 0; if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */ expected_metadata_sequence_[num_expected_++] = &streaminfo_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected
SINT SoundSourceFLAC::seekSampleFrame(SINT frameIndex) { DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(isValidFrameIndex(frameIndex)); // Seek to the new position SINT seekFrameIndex = frameIndex; int retryCount = 0; // NOTE(uklotzde): This loop avoids unnecessary seek operations. // If the file is decoded from the beginning to the end during // continuous playback no seek operations are necessary. This // may hide rare seek errors that we have observed in some "flaky" // FLAC files. The retry strategy implemented by this loop tries // to solve these issues when randomly seeking through such a file. while ((seekFrameIndex != m_curFrameIndex) && (retryCount <= kSeekErrorMaxRetryCount)){ // Discard decoded sample data before seeking m_sampleBuffer.reset(); // Invalidate the current position m_curFrameIndex = getMaxFrameIndex(); if (FLAC__stream_decoder_seek_absolute(m_decoder, seekFrameIndex)) { // Success: Set the new position m_curFrameIndex = seekFrameIndex; DEBUG_ASSERT(FLAC__STREAM_DECODER_SEEK_ERROR != FLAC__stream_decoder_get_state(m_decoder)); } else { // Failure qWarning() << "Seek error at" << seekFrameIndex << "in" << m_file.fileName(); if (FLAC__STREAM_DECODER_SEEK_ERROR == FLAC__stream_decoder_get_state(m_decoder)) { // Flush the input stream of the decoder according to the // documentation of FLAC__stream_decoder_seek_absolute() if (!FLAC__stream_decoder_flush(m_decoder)) { qWarning() << "Failed to flush input buffer of the FLAC decoder after seek failure in" << m_file.fileName(); // Invalidate the current position again... m_curFrameIndex = getMaxFrameIndex(); // ...and abort return m_curFrameIndex; } } if (getMinFrameIndex() < seekFrameIndex) { // The next seek position should start at a preceding sample block. // By subtracting max. blocksize from the current seek position it // is guaranteed that the targeted sample blocks of subsequent seek // operations will differ. DEBUG_ASSERT(0 < m_maxBlocksize); seekFrameIndex -= m_maxBlocksize; if (seekFrameIndex < getMinFrameIndex()) { seekFrameIndex = getMinFrameIndex(); } } else { // We have already reached the beginning of the file // and cannot move the seek position backward any // further! break; // exit loop } } } while (m_curFrameIndex != seekFrameIndex); DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); if (frameIndex > m_curFrameIndex) { // Adjust the current position skipSampleFrames(frameIndex - m_curFrameIndex); } return m_curFrameIndex; }
static playbackstatus MV_GetNextFLACBlock ( VoiceNode *voice ) { flac_data * fd = (flac_data *) voice->extra; FLAC__StreamDecoderState decode_state; // FLAC__bool decode_status; voice->Playing = TRUE; if ((FLAC__uint64)(uintptr_t)voice->LoopEnd > 0 && fd->sample_pos >= (FLAC__uint64)(uintptr_t)voice->LoopEnd) if (!FLAC__stream_decoder_seek_absolute(fd->stream, (FLAC__uint64)(uintptr_t)voice->LoopStart)) MV_Printf("MV_GetNextFLACBlock FLAC__stream_decoder_seek_absolute: LOOP_START %ul, LOOP_END %ul\n", (FLAC__uint64)(uintptr_t)voice->LoopStart, (FLAC__uint64)(uintptr_t)voice->LoopEnd); /*decode_status =*/ FLAC__stream_decoder_process_single(fd->stream); decode_state = FLAC__stream_decoder_get_state(fd->stream); /* if (!decode_status) { MV_Printf("MV_GetNextFLACBlock: %s\n", FLAC__StreamDecoderStateString[decode_state]); voice->Playing = FALSE; return NoMoreData; } */ if (decode_state == FLAC__STREAM_DECODER_SEEK_ERROR) { FLAC__stream_decoder_flush(fd->stream); decode_state = FLAC__stream_decoder_get_state(fd->stream); } if (decode_state == FLAC__STREAM_DECODER_END_OF_STREAM) { if (voice->LoopSize > 0) { if (!FLAC__stream_decoder_seek_absolute(fd->stream, (FLAC__uint64)(uintptr_t)voice->LoopStart)) MV_Printf("MV_GetNextFLACBlock FLAC__stream_decoder_seek_absolute: LOOP_START %ul\n", (FLAC__uint64)(uintptr_t)voice->LoopStart); } else { voice->Playing = FALSE; return NoMoreData; } } #if 0 // unnecessary: duplicated in write_flac_stream() voice->channels = FLAC__stream_decoder_get_channels(fd->stream); voice->bits = FLAC__stream_decoder_get_bits_per_sample(fd->stream); voice->SamplingRate = FLAC__stream_decoder_get_sample_rate(fd->stream); // CODEDUP multivoc.c MV_SetVoicePitch voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) / MV_MixRate; voice->FixedPointBufferSize = ( voice->RateScale * MV_MIXBUFFERSIZE ) - voice->RateScale; MV_SetVoiceMixMode( voice ); #endif return KeepPlaying; }
static bool_t flac_play (const char * filename, VFSFile * file) { if (!file) return FALSE; void * play_buffer = NULL; bool_t error = FALSE; info->fd = file; if (read_metadata(decoder, info) == FALSE) { FLACNG_ERROR("Could not prepare file for playing!\n"); error = TRUE; goto ERR_NO_CLOSE; } play_buffer = g_malloc (BUFFER_SIZE_BYTE); if (! aud_input_open_audio (SAMPLE_FMT (info->bits_per_sample), info->sample_rate, info->channels)) { error = TRUE; goto ERR_NO_CLOSE; } aud_input_set_bitrate(info->bitrate); while (FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_END_OF_STREAM) { if (aud_input_check_stop ()) break; int seek_value = aud_input_check_seek (); if (seek_value >= 0) FLAC__stream_decoder_seek_absolute (decoder, (int64_t) seek_value * info->sample_rate / 1000); /* Try to decode a single frame of audio */ if (FLAC__stream_decoder_process_single(decoder) == FALSE) { FLACNG_ERROR("Error while decoding!\n"); error = TRUE; break; } squeeze_audio(info->output_buffer, play_buffer, info->buffer_used, info->bits_per_sample); aud_input_write_audio(play_buffer, info->buffer_used * SAMPLE_SIZE(info->bits_per_sample)); reset_info(info); } ERR_NO_CLOSE: g_free (play_buffer); reset_info(info); if (FLAC__stream_decoder_flush(decoder) == FALSE) FLACNG_ERROR("Could not flush decoder state!\n"); return ! error; }
static GstFlowReturn gst_flac_dec_handle_frame (GstAudioDecoder * audio_dec, GstBuffer * buf) { GstFlacDec *dec; dec = GST_FLAC_DEC (audio_dec); /* drain remaining data? */ if (G_UNLIKELY (buf == NULL)) { gst_flac_dec_flush (audio_dec, FALSE); return GST_FLOW_OK; } GST_LOG_OBJECT (dec, "frame: ts %" GST_TIME_FORMAT ", flags 0x%04x, " "%" G_GSIZE_FORMAT " bytes", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_FLAGS (buf), gst_buffer_get_size (buf)); /* drop any in-stream headers, we've processed those in set_format already */ if (G_UNLIKELY (!dec->got_headers)) { gboolean got_audio_frame; GstMapInfo map; /* check if this is a flac audio frame (rather than a header or junk) */ gst_buffer_map (buf, &map, GST_MAP_READ); got_audio_frame = gst_flac_dec_scan_got_frame (dec, map.data, map.size); gst_buffer_unmap (buf, &map); if (!got_audio_frame) { GST_INFO_OBJECT (dec, "dropping in-stream header, %" G_GSIZE_FORMAT " " "bytes", map.size); gst_audio_decoder_finish_frame (audio_dec, NULL, 1); return GST_FLOW_OK; } GST_INFO_OBJECT (dec, "first audio frame, got all in-stream headers now"); dec->got_headers = TRUE; } gst_adapter_push (dec->adapter, gst_buffer_ref (buf)); buf = NULL; dec->last_flow = GST_FLOW_OK; /* framed - there should always be enough data to decode something */ GST_LOG_OBJECT (dec, "%" G_GSIZE_FORMAT " bytes available", gst_adapter_available (dec->adapter)); if (!FLAC__stream_decoder_process_single (dec->decoder)) { GST_INFO_OBJECT (dec, "process_single failed"); if (FLAC__stream_decoder_get_state (dec->decoder) == FLAC__STREAM_DECODER_ABORTED) { GST_WARNING_OBJECT (dec, "Read callback caused internal abort"); /* allow recovery */ gst_adapter_clear (dec->adapter); FLAC__stream_decoder_flush (dec->decoder); gst_flac_dec_handle_decoder_error (dec, TRUE); } } return dec->last_flow; }
FLAC__bool seek_to_absolute_sample_(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample) { FLAC__uint64 first_frame_offset, lower_bound, upper_bound; FLAC__int64 pos = -1, last_pos = -1; int i, lower_seek_point = -1, upper_seek_point = -1; unsigned approx_bytes_per_frame; FLAC__uint64 last_frame_sample = FLAC__U64L(0xffffffffffffffff); FLAC__bool needs_seek; const FLAC__uint64 total_samples = decoder->private_->stream_info.total_samples; const unsigned min_blocksize = decoder->private_->stream_info.min_blocksize; const unsigned max_blocksize = decoder->private_->stream_info.max_blocksize; const unsigned max_framesize = decoder->private_->stream_info.max_framesize; const unsigned channels = FLAC__seekable_stream_decoder_get_channels(decoder); const unsigned bps = FLAC__seekable_stream_decoder_get_bits_per_sample(decoder); /* we are just guessing here, but we want to guess high, not low */ if(max_framesize > 0) { approx_bytes_per_frame = max_framesize; } /* * Check if it's a known fixed-blocksize stream. Note that though * the spec doesn't allow zeroes in the STREAMINFO block, we may * never get a STREAMINFO block when decoding so the value of * min_blocksize might be zero. */ else if(min_blocksize == max_blocksize && min_blocksize > 0) { /* note there are no () around 'bps/8' to keep precision up since it's an integer calulation */ approx_bytes_per_frame = min_blocksize * channels * bps/8 + 64; } else approx_bytes_per_frame = 4608 * channels * bps/8 + 64; /* * The decode position is currently at the first frame since we * rewound and processed metadata. */ if(!FLAC__seekable_stream_decoder_get_decode_position(decoder, &first_frame_offset)) { decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; return false; } /* * First, we set an upper and lower bound on where in the * stream we will search. For now we assume the worst case * scenario, which is our best guess at the beginning of * the first and last frames. */ lower_bound = first_frame_offset; /* calc the upper_bound, beyond which we never want to seek */ if(max_framesize > 0) upper_bound = stream_length - (max_framesize + 128 + 2); /* 128 for a possible ID3V1 tag, 2 for indexing differences */ else upper_bound = stream_length - ((channels * bps * FLAC__MAX_BLOCK_SIZE) / 8 + 128 + 2); /* * Now we refine the bounds if we have a seektable with * suitable points. Note that according to the spec they * must be ordered by ascending sample number. */ if(0 != decoder->private_->seek_table) { /* find the closest seek point <= target_sample, if it exists */ for(i = (int)decoder->private_->seek_table->num_points - 1; i >= 0; i--) { if(decoder->private_->seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && decoder->private_->seek_table->points[i].sample_number <= target_sample) break; } if(i >= 0) { /* i.e. we found a suitable seek point... */ lower_bound = first_frame_offset + decoder->private_->seek_table->points[i].stream_offset; lower_seek_point = i; } /* find the closest seek point > target_sample, if it exists */ for(i = 0; i < (int)decoder->private_->seek_table->num_points; i++) { if(decoder->private_->seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && decoder->private_->seek_table->points[i].sample_number > target_sample) break; } if(i < (int)decoder->private_->seek_table->num_points) { /* i.e. we found a suitable seek point... */ upper_bound = first_frame_offset + decoder->private_->seek_table->points[i].stream_offset; upper_seek_point = i; } } /* * Now guess at where within those bounds our target * sample will be. */ if(lower_seek_point >= 0) { /* first see if our sample is within a few frames of the lower seekpoint */ if(decoder->private_->seek_table->points[lower_seek_point].sample_number <= target_sample && target_sample < decoder->private_->seek_table->points[lower_seek_point].sample_number + (decoder->private_->seek_table->points[lower_seek_point].frame_samples * 4)) { pos = (FLAC__int64)lower_bound; } else if(upper_seek_point >= 0) { const FLAC__uint64 target_offset = target_sample - decoder->private_->seek_table->points[lower_seek_point].sample_number; const FLAC__uint64 range_samples = decoder->private_->seek_table->points[upper_seek_point].sample_number - decoder->private_->seek_table->points[lower_seek_point].sample_number; const FLAC__uint64 range_bytes = upper_bound - lower_bound; #if defined _MSC_VER || defined __MINGW32__ /* with VC++ you have to spoon feed it the casting */ pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)(FLAC__int64)target_offset / (double)(FLAC__int64)range_samples * (double)(FLAC__int64)(range_bytes-1)) - approx_bytes_per_frame; #else pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)target_offset / (double)range_samples * (double)(range_bytes-1)) - approx_bytes_per_frame; #endif } } /* * If there's no seek table, we need to use the metadata (if we * have it) and the filelength to estimate the position of the * frame with the correct sample. */ if(pos < 0 && total_samples > 0) { #if defined _MSC_VER || defined __MINGW32__ /* with VC++ you have to spoon feed it the casting */ pos = (FLAC__int64)first_frame_offset + (FLAC__int64)((double)(FLAC__int64)target_sample / (double)(FLAC__int64)total_samples * (double)(FLAC__int64)(stream_length-first_frame_offset-1)) - approx_bytes_per_frame; #else pos = (FLAC__int64)first_frame_offset + (FLAC__int64)((double)target_sample / (double)total_samples * (double)(stream_length-first_frame_offset-1)) - approx_bytes_per_frame; #endif } /* * If there's no seek table and total_samples is unknown, we * don't even bother trying to figure out a target, we just use * our current position. */ if(pos < 0) { FLAC__uint64 upos; if(decoder->private_->tell_callback(decoder, &upos, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK) { decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; return false; } pos = (FLAC__int64)upos; needs_seek = false; } else needs_seek = true; /* clip the position to the bounds, lower bound takes precedence */ if(pos >= (FLAC__int64)upper_bound) { pos = (FLAC__int64)upper_bound-1; needs_seek = true; } if(pos < (FLAC__int64)lower_bound) { pos = (FLAC__int64)lower_bound; needs_seek = true; } decoder->private_->target_sample = target_sample; while(1) { if(needs_seek) { if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK) { decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; return false; } if(!FLAC__stream_decoder_flush(decoder->private_->stream_decoder)) { decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; return false; } } /* Now we need to get a frame. It is possible for our seek * to land in the middle of audio data that looks exactly like * a frame header from a future version of an encoder. When * that happens, FLAC__stream_decoder_process_single() will * return false and the state will be * FLAC__STREAM_DECODER_UNPARSEABLE_STREAM. But there is a * remote possibility that it is properly synced at such a * "future-codec frame", so to make sure, we wait to see * several "unparseable" errors in a row before bailing out. */ { unsigned unparseable_count; FLAC__bool got_a_frame = false; for (unparseable_count = 0; !got_a_frame && unparseable_count < 10; unparseable_count++) { if(FLAC__stream_decoder_process_single(decoder->private_->stream_decoder)) got_a_frame = true; else if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_UNPARSEABLE_STREAM) /* try again. we don't want to flush the decoder since that clears the bitbuffer */ decoder->private_->stream_decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; else /* it's a real error */ break; } if (!got_a_frame) { decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; return false; } } /* our write callback will change the state when it gets to the target frame */ if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING) { break; } else { /* we need to narrow the search */ const FLAC__uint64 this_frame_sample = decoder->private_->last_frame.header.number.sample_number; FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); if(this_frame_sample == last_frame_sample && pos < last_pos) { /* our last move backwards wasn't big enough, double it */ pos -= (last_pos - pos); needs_seek = true; } else { if(target_sample < this_frame_sample) { last_pos = pos; approx_bytes_per_frame = decoder->private_->last_frame.header.blocksize * channels * bps/8 + 64; pos -= approx_bytes_per_frame; needs_seek = true; } else { /* target_sample >= this_frame_sample + this frame's blocksize */ FLAC__uint64 upos; if(decoder->private_->tell_callback(decoder, &upos, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK) { decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; return false; } last_pos = pos; pos = (FLAC__int64)upos; pos -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder->private_->stream_decoder); needs_seek = false; /* * if we haven't hit the target frame yet and our position hasn't changed, * it means we're at the end of the stream and the seek target does not exist. */ if(last_pos == pos) { decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; return false; } } } if(pos < (FLAC__int64)lower_bound) pos = (FLAC__int64)lower_bound; last_frame_sample = this_frame_sample; } } return true; }
ReadableSampleFrames SoundSourceFLAC::readSampleFramesClamped( WritableSampleFrames writableSampleFrames) { const SINT firstFrameIndex = writableSampleFrames.frameIndexRange().start(); if (m_curFrameIndex != firstFrameIndex) { // Seek to the new position SINT seekFrameIndex = firstFrameIndex; int retryCount = 0; // NOTE(uklotzde): This loop avoids unnecessary seek operations. // If the file is decoded from the beginning to the end during // continuous playback no seek operations are necessary. This // may hide rare seek errors that we have observed in some "flaky" // FLAC files. The retry strategy implemented by this loop tries // to solve these issues when randomly seeking through such a file. while ((seekFrameIndex != m_curFrameIndex) && (retryCount <= kSeekErrorMaxRetryCount)) { // Discard decoded sample data before seeking m_sampleBuffer.clear(); invalidateCurFrameIndex(); if (FLAC__stream_decoder_seek_absolute(m_decoder, seekFrameIndex)) { // Success: Set the new position m_curFrameIndex = seekFrameIndex; DEBUG_ASSERT(FLAC__STREAM_DECODER_SEEK_ERROR != FLAC__stream_decoder_get_state(m_decoder)); } else { // Failure kLogger.warning() << "Seek error at" << seekFrameIndex << "in file" << m_file.fileName(); if (FLAC__STREAM_DECODER_SEEK_ERROR == FLAC__stream_decoder_get_state(m_decoder)) { // Flush the input stream of the decoder according to the // documentation of FLAC__stream_decoder_seek_absolute() if (!FLAC__stream_decoder_flush(m_decoder)) { kLogger.warning() << "Failed to flush input buffer of the FLAC decoder after seek failure" << "in file" << m_file.fileName(); invalidateCurFrameIndex(); // ...and abort return ReadableSampleFrames( IndexRange::between( m_curFrameIndex, m_curFrameIndex)); } } if (frameIndexMin() < seekFrameIndex) { // The next seek position should start at a preceding sample block. // By subtracting max. blocksize from the current seek position it // is guaranteed that the targeted sample blocks of subsequent seek // operations will differ. DEBUG_ASSERT(0 < m_maxBlocksize); seekFrameIndex -= m_maxBlocksize; if (seekFrameIndex < frameIndexMin()) { seekFrameIndex = frameIndexMin(); } } else { // We have already reached the beginning of the file // and cannot move the seek position backwards any // further! break; // exit loop } } } // Decoding starts before the actual target position DEBUG_ASSERT(m_curFrameIndex <= firstFrameIndex); const auto precedingFrames = IndexRange::between(m_curFrameIndex, firstFrameIndex); if (!precedingFrames.empty() && (precedingFrames != readSampleFramesClamped(WritableSampleFrames(precedingFrames)).frameIndexRange())) { kLogger.warning() << "Failed to skip preceding frames" << precedingFrames; // Abort return ReadableSampleFrames( IndexRange::between( m_curFrameIndex, m_curFrameIndex)); } } DEBUG_ASSERT(m_curFrameIndex == firstFrameIndex); const SINT numberOfSamplesTotal = frames2samples(writableSampleFrames.frameLength()); SINT numberOfSamplesRemaining = numberOfSamplesTotal; SINT outputSampleOffset = 0; while (0 < numberOfSamplesRemaining) { // If our buffer from libflac is empty (either because we explicitly cleared // it or because we've simply used all the samples), ask for a new buffer if (m_sampleBuffer.empty()) { // Save the current frame index const SINT curFrameIndexBeforeProcessing = m_curFrameIndex; // Documentation of FLAC__stream_decoder_process_single(): // "Depending on what was decoded, the metadata or write callback // will be called with the decoded metadata block or audio frame." // See also: https://xiph.org/flac/api/group__flac__stream__decoder.html#ga9d6df4a39892c05955122cf7f987f856 if (!FLAC__stream_decoder_process_single(m_decoder)) { kLogger.warning() << "Failed to decode FLAC file" << m_file.fileName(); break; // abort } // After decoding we might first need to skip some samples if the // decoder complained that it has lost sync for some malformed(?) // files if (m_curFrameIndex != curFrameIndexBeforeProcessing) { if (m_curFrameIndex < curFrameIndexBeforeProcessing) { kLogger.warning() << "Trying to adjust frame index" << m_curFrameIndex << "<" << curFrameIndexBeforeProcessing << "while decoding FLAC file" << m_file.fileName(); const auto skipFrames = IndexRange::between(m_curFrameIndex, curFrameIndexBeforeProcessing); if (skipFrames != readSampleFramesClamped(WritableSampleFrames(skipFrames)).frameIndexRange()) { kLogger.warning() << "Failed to skip sample frames" << skipFrames << "while decoding FLAC file" << m_file.fileName(); break; // abort } } else { kLogger.warning() << "Unexpected frame index" << m_curFrameIndex << ">" << curFrameIndexBeforeProcessing << "while decoding FLAC file" << m_file.fileName(); break; // abort } } DEBUG_ASSERT(curFrameIndexBeforeProcessing == m_curFrameIndex); } if (m_sampleBuffer.empty()) { break; // EOF } const SINT numberOfSamplesRead = std::min(m_sampleBuffer.readableLength(), numberOfSamplesRemaining); const SampleBuffer::ReadableSlice readableSlice( m_sampleBuffer.shrinkForReading(numberOfSamplesRead)); DEBUG_ASSERT(readableSlice.length() == numberOfSamplesRead); if (writableSampleFrames.writableData()) { SampleUtil::copy( writableSampleFrames.writableData(outputSampleOffset), readableSlice.data(), readableSlice.length()); outputSampleOffset += numberOfSamplesRead; } m_curFrameIndex += samples2frames(numberOfSamplesRead); numberOfSamplesRemaining -= numberOfSamplesRead; } DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfSamplesTotal >= numberOfSamplesRemaining); const SINT numberOfSamples = numberOfSamplesTotal - numberOfSamplesRemaining; return ReadableSampleFrames( IndexRange::forward(firstFrameIndex, samples2frames(numberOfSamples)), SampleBuffer::ReadableSlice( writableSampleFrames.writableData(), std::min(writableSampleFrames.writableLength(), numberOfSamples))); }
void *play_loop_(void *arg) { unsigned written_time_last = 0, bh_index_last_w = 0, bh_index_last_o = BITRATE_HIST_SIZE, blocksize = 1; FLAC__uint64 decode_position_last = 0, decode_position_frame_last = 0, decode_position_frame = 0; (void)arg; while(stream_data_.is_playing) { if(!stream_data_.eof) { while(sample_buffer_last_ - sample_buffer_first_ < SAMPLES_PER_WRITE) { unsigned s; s = sample_buffer_last_ - sample_buffer_first_; if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_END_OF_STREAM) { stream_data_.eof = true; break; } else if(!FLAC__stream_decoder_process_single(decoder_)) { /*@@@ this should probably be a dialog */ fprintf(stderr, "libxmms-flac: READ ERROR processing frame\n"); stream_data_.eof = true; break; } blocksize = sample_buffer_last_ - sample_buffer_first_ - s; decode_position_frame_last = decode_position_frame; if(stream_data_.is_http_source || !FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame)) decode_position_frame = 0; } if(sample_buffer_last_ - sample_buffer_first_ > 0) { const unsigned n = min(sample_buffer_last_ - sample_buffer_first_, SAMPLES_PER_WRITE); int bytes = n * stream_data_.channels * stream_data_.sample_format_bytes_per_sample; FLAC__byte *sample_buffer_start = sample_buffer_ + sample_buffer_first_ * stream_data_.channels * stream_data_.sample_format_bytes_per_sample; unsigned written_time, bh_index_w; FLAC__uint64 decode_position; sample_buffer_first_ += n; flac_ip.add_vis_pcm(flac_ip.output->written_time(), stream_data_.sample_format, stream_data_.channels, bytes, sample_buffer_start); while(flac_ip.output->buffer_free() < (int)bytes && stream_data_.is_playing && stream_data_.seek_to_in_sec == -1) xmms_usleep(10000); if(stream_data_.is_playing && stream_data_.seek_to_in_sec == -1) flac_ip.output->write_audio(sample_buffer_start, bytes); /* compute current bitrate */ written_time = flac_ip.output->written_time(); bh_index_w = written_time / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; if(bh_index_w != bh_index_last_w) { bh_index_last_w = bh_index_w; decode_position = decode_position_frame - (double)(sample_buffer_last_ - sample_buffer_first_) * (double)(decode_position_frame - decode_position_frame_last) / (double)blocksize; bitrate_history_[(bh_index_w + BITRATE_HIST_SIZE - 1) % BITRATE_HIST_SIZE] = decode_position > decode_position_last && written_time > written_time_last ? 8000 * (decode_position - decode_position_last) / (written_time - written_time_last) : stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample; decode_position_last = decode_position; written_time_last = written_time; } } else { stream_data_.eof = true; xmms_usleep(10000); } } else xmms_usleep(10000); if(!stream_data_.is_http_source && stream_data_.seek_to_in_sec != -1) { const double distance = (double)stream_data_.seek_to_in_sec * 1000.0 / (double)stream_data_.length_in_msec; FLAC__uint64 target_sample = (FLAC__uint64)(distance * (double)stream_data_.total_samples); if(stream_data_.total_samples > 0 && target_sample >= stream_data_.total_samples) target_sample = stream_data_.total_samples - 1; if(FLAC__stream_decoder_seek_absolute(decoder_, target_sample)) { flac_ip.output->flush(stream_data_.seek_to_in_sec * 1000); bh_index_last_w = bh_index_last_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; if(!FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame)) decode_position_frame = 0; stream_data_.eof = false; sample_buffer_first_ = sample_buffer_last_ = 0; } else if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_SEEK_ERROR) { /*@@@ this should probably be a dialog */ fprintf(stderr, "libxmms-flac: SEEK ERROR\n"); FLAC__stream_decoder_flush(decoder_); stream_data_.eof = false; sample_buffer_first_ = sample_buffer_last_ = 0; } stream_data_.seek_to_in_sec = -1; } else { /* display the right bitrate from history */ unsigned bh_index_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; if(bh_index_o != bh_index_last_o && bh_index_o != bh_index_last_w && bh_index_o != (bh_index_last_w + 1) % BITRATE_HIST_SIZE) { bh_index_last_o = bh_index_o; flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, bitrate_history_[bh_index_o], stream_data_.sample_rate, stream_data_.channels); } } } safe_decoder_finish_(decoder_); /* are these two calls necessary? */ flac_ip.output->buffer_free(); flac_ip.output->buffer_free(); g_free(stream_data_.title); pthread_exit(NULL); return 0; /* to silence the compiler warning about not returning a value */ }