Пример #1
0
/* this is the codec entry point */
enum codec_status codec_start(struct codec_api* api)
{
    struct codec_api* ci = api;
    FLAC__SeekableStreamDecoder* flacDecoder;
    FLAC__uint64 offset;

    TEST_CODEC_API(ci);

#ifndef SIMULATOR
    ci->memcpy(iramstart, iramcopy, iramend-iramstart);
#endif

    ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*10));
    ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
    ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*1024));

    ci->configure(CODEC_DSP_ENABLE, (bool *)true);
    ci->configure(DSP_DITHER, (bool *)false);
    ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED);
    ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16));
  
next_track:
    metadata_length = 0;
    seek_table = NULL;
    stream_info = NULL;

    if (codec_init(api)) {
        return CODEC_ERROR;
    }

    while (!ci->taginfo_ready)
        ci->yield();
    
    ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency));
    codec_set_replaygain(ci->id3);
  
    /* Create a decoder instance */
    flacDecoder = FLAC__seekable_stream_decoder_new();

    /* Set up the decoder and the callback functions - this must be done before init */

    /* The following are required for stream_decoder and higher */
    FLAC__seekable_stream_decoder_set_client_data(flacDecoder,ci);
    FLAC__seekable_stream_decoder_set_write_callback(flacDecoder, flac_write_handler);
    FLAC__seekable_stream_decoder_set_read_callback(flacDecoder, flac_read_handler);
    FLAC__seekable_stream_decoder_set_metadata_callback(flacDecoder, flac_metadata_handler);
    FLAC__seekable_stream_decoder_set_error_callback(flacDecoder, flac_error_handler);
    FLAC__seekable_stream_decoder_set_metadata_respond_all(flacDecoder);

    /* The following are only for the seekable_stream_decoder */
    FLAC__seekable_stream_decoder_set_seek_callback(flacDecoder, flac_seek_handler);
    FLAC__seekable_stream_decoder_set_tell_callback(flacDecoder, flac_tell_handler);
    FLAC__seekable_stream_decoder_set_length_callback(flacDecoder, flac_length_handler);
    FLAC__seekable_stream_decoder_set_eof_callback(flacDecoder, flac_eof_handler);


    /* QUESTION: What do we do when the init fails? */
    if (FLAC__seekable_stream_decoder_init(flacDecoder)) {
        return CODEC_ERROR;
    }

    /* The first thing to do is to parse the metadata */
    FLAC__seekable_stream_decoder_process_until_end_of_metadata(flacDecoder);

    if (ci->id3->offset && stream_info) {
        FLAC__uint64 sample;

        sample = find_sample_number(ci, ci->id3->offset - metadata_length);
        ci->advance_buffer(ci->id3->offset);
        FLAC__seekable_stream_decoder_seek_absolute(flacDecoder, sample);
        FLAC__seekable_stream_decoder_get_decode_position(flacDecoder, &offset);
        ci->set_offset(offset);
        samplesdone = (uint32_t)sample;
        ci->set_elapsed(sample/(ci->id3->frequency/1000));
    } else {
        samplesdone = 0;
        ci->set_elapsed(0);
    }

    /* The main decoder loop */
    while (FLAC__seekable_stream_decoder_get_state(flacDecoder) != FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) {
        ci->yield();
        if (ci->stop_codec || ci->reload_codec) {
            break;
        }

        if (ci->seek_time) {
            int sample_loc;

            sample_loc = ci->seek_time/1000 * ci->id3->frequency;
            if (FLAC__seekable_stream_decoder_seek_absolute(flacDecoder, sample_loc)) {
                samplesdone = sample_loc;
                ci->set_elapsed(samplesdone/(ci->id3->frequency/1000));
            }
            ci->seek_time = 0;
        }

        FLAC__seekable_stream_decoder_process_single(flacDecoder);
        FLAC__seekable_stream_decoder_get_decode_position(flacDecoder, &offset);
        ci->set_offset(offset);
    }

    /* Flush the libFLAC buffers */
    FLAC__seekable_stream_decoder_finish(flacDecoder);

    if (ci->request_next_track()) {
        if (stream_info) {
            FLAC__metadata_object_delete(stream_info);
        }
        if (seek_table) {
            FLAC__metadata_object_delete(seek_table);
        }
        metadata_length = 0;
        goto next_track;
    }

    return CODEC_OK;
}
Пример #2
0
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;
}
Пример #3
0
FLAC_API FLAC__bool FLAC__file_decoder_get_decode_position(const FLAC__FileDecoder *decoder, FLAC__uint64 *position)
{
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	return FLAC__seekable_stream_decoder_get_decode_position(decoder->private_->seekable_stream_decoder, position);
}