void SoundFileReaderFlac::seek(Uint64 sampleOffset) { assert(m_decoder); // Reset the callback data (the "write" callback will be called) m_clientData.buffer = NULL; m_clientData.remaining = 0; m_clientData.leftovers.clear(); // FLAC decoder expects absolute sample offset, so we take the channel count out if (sampleOffset < m_clientData.info.sampleCount) { // The "write" callback will populate the leftovers buffer with the first batch of samples from the // seek destination, and since we want that data in this typical case, we don't re-clear it afterward FLAC__stream_decoder_seek_absolute(m_decoder, sampleOffset / m_clientData.info.channelCount); } else { // FLAC decoder can't skip straight to EOF, so we short-seek by one sample and skip the rest FLAC__stream_decoder_seek_absolute(m_decoder, (m_clientData.info.sampleCount / m_clientData.info.channelCount) - 1); FLAC__stream_decoder_skip_single_frame(m_decoder); // This was re-populated during the seek, but we're skipping everything in this, so we need it emptied m_clientData.leftovers.clear(); } }
FLAC_API FLAC__bool FLAC__seekable_stream_decoder_skip_single_frame(FLAC__SeekableStreamDecoder *decoder) { FLAC__bool ret; FLAC__ASSERT(0 != decoder); if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM; if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) return true; FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK); ret = FLAC__stream_decoder_skip_single_frame(decoder->private_->stream_decoder); if(!ret) decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; return ret; }
bool flac_reader_c::parse_file() { FLAC__StreamDecoderState state; flac_block_t block; uint64_t u, old_pos; int result, progress, old_progress; bool ok; m_in->setFilePointer(0); metadata_parsed = false; mxinfo(Y("+-> Parsing the FLAC file. This can take a LONG time.\n")); init_flac_decoder(); result = FLAC__stream_decoder_process_until_end_of_metadata(m_flac_decoder.get()); mxverb(2, boost::format("flac_reader: extract->metadata, result: %1%, mdp: %2%, num blocks: %3%\n") % result % metadata_parsed % blocks.size()); if (!metadata_parsed) mxerror_fn(m_ti.m_fname, Y("No metadata block found. This file is broken.\n")); FLAC__stream_decoder_get_decode_position(m_flac_decoder.get(), &u); block.type = FLAC_BLOCK_TYPE_HEADERS; block.filepos = 0; block.len = u; old_pos = u; blocks.push_back(block); mxverb(2, boost::format("flac_reader: headers: block at %1% with size %2%\n") % block.filepos % block.len); old_progress = -5; ok = FLAC__stream_decoder_skip_single_frame(m_flac_decoder.get()); while (ok) { state = FLAC__stream_decoder_get_state(m_flac_decoder.get()); progress = m_in->getFilePointer() * 100 / m_size; if ((progress - old_progress) >= 5) { mxinfo(boost::format(Y("+-> Pre-parsing FLAC file: %1%%%%2%")) % progress % "\r"); old_progress = progress; } if (FLAC__stream_decoder_get_decode_position(m_flac_decoder.get(), &u) && (u != old_pos)) { block.type = FLAC_BLOCK_TYPE_DATA; block.filepos = old_pos; block.len = u - old_pos; old_pos = u; blocks.push_back(block); mxverb(2, boost::format("flac_reader: skip/decode frame, block at %1% with size %2%\n") % block.filepos % block.len); } if (state > FLAC__STREAM_DECODER_READ_FRAME) break; ok = FLAC__stream_decoder_skip_single_frame(m_flac_decoder.get()); } if (100 != old_progress) mxinfo(Y("+-> Pre-parsing FLAC file: 100%\n")); else mxinfo("\n"); if ((blocks.size() == 0) || (blocks[0].type != FLAC_BLOCK_TYPE_HEADERS)) mxerror(Y("flac_reader: Could not read all header packets.\n")); m_in->setFilePointer(0); blocks[0].len -= 4; blocks[0].filepos = 4; return metadata_parsed; }
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