forked from len0rd/rockbox
Added comments, Replay Gain, and resume/bookmarks for FLAC.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7253 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
773c28e489
commit
b301b43825
8 changed files with 304 additions and 175 deletions
|
@ -20,6 +20,8 @@
|
|||
#include "codec.h"
|
||||
|
||||
#include <codecs/libFLAC/include/FLAC/seekable_stream_decoder.h>
|
||||
#include <codecs/libFLAC/include/FLAC/format.h>
|
||||
#include <codecs/libFLAC/include/FLAC/metadata.h>
|
||||
#include "playback.h"
|
||||
#include "lib/codeclib.h"
|
||||
#include "dsp.h"
|
||||
|
@ -30,6 +32,10 @@
|
|||
static struct codec_api* rb;
|
||||
static uint32_t samplesdone;
|
||||
|
||||
static FLAC__StreamMetadata *stream_info;
|
||||
static FLAC__StreamMetadata *seek_table;
|
||||
unsigned int metadata_length;
|
||||
|
||||
/* Called when the FLAC decoder needs some FLAC data to decode */
|
||||
FLAC__SeekableStreamDecoderReadStatus flac_read_handler(const FLAC__SeekableStreamDecoder *dec,
|
||||
FLAC__byte buffer[], unsigned *bytes, void *data)
|
||||
|
@ -49,9 +55,9 @@ static unsigned char pcmbuf[FLAC_MAX_SUPPORTED_BLOCKSIZE*FLAC_MAX_SUPPORTED_CHAN
|
|||
|
||||
/* Called when the FLAC decoder has some decoded PCM data to write */
|
||||
FLAC__StreamDecoderWriteStatus flac_write_handler(const FLAC__SeekableStreamDecoder *dec,
|
||||
const FLAC__Frame *frame,
|
||||
const FLAC__int32 * const buf[],
|
||||
void *data)
|
||||
const FLAC__Frame *frame,
|
||||
const FLAC__int32 * const buf[],
|
||||
void *data)
|
||||
{
|
||||
struct codec_api* ci = (struct codec_api*)data;
|
||||
(void)dec;
|
||||
|
@ -92,10 +98,23 @@ FLAC__StreamDecoderWriteStatus flac_write_handler(const FLAC__SeekableStreamDeco
|
|||
void flac_metadata_handler(const FLAC__SeekableStreamDecoder *dec,
|
||||
const FLAC__StreamMetadata *meta, void *data)
|
||||
{
|
||||
/* Ignore metadata for now... */
|
||||
(void)dec;
|
||||
(void)meta;
|
||||
(void)data;
|
||||
/* Ignore metadata for now... */
|
||||
(void)dec;
|
||||
(void)data;
|
||||
|
||||
metadata_length += meta->length;
|
||||
|
||||
if ( meta->type == FLAC__METADATA_TYPE_STREAMINFO ) {
|
||||
stream_info = FLAC__metadata_object_clone( meta );
|
||||
if ( stream_info == NULL ) {
|
||||
//return CODEC_ERROR;
|
||||
}
|
||||
} else if ( meta->type == FLAC__METADATA_TYPE_SEEKTABLE ) {
|
||||
seek_table = FLAC__metadata_object_clone( meta );
|
||||
if ( seek_table == NULL ) {
|
||||
//return CODEC_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -111,47 +130,47 @@ FLAC__SeekableStreamDecoderSeekStatus flac_seek_handler (const FLAC__SeekableStr
|
|||
FLAC__uint64 absolute_byte_offset,
|
||||
void *client_data)
|
||||
{
|
||||
(void)decoder;
|
||||
struct codec_api* ci = (struct codec_api*)client_data;
|
||||
(void)decoder;
|
||||
struct codec_api* ci = (struct codec_api*)client_data;
|
||||
|
||||
if (ci->seek_buffer(absolute_byte_offset)) {
|
||||
if (ci->seek_buffer(absolute_byte_offset)) {
|
||||
return(FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK);
|
||||
} else {
|
||||
} else {
|
||||
return(FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FLAC__SeekableStreamDecoderTellStatus flac_tell_handler (const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__uint64 *absolute_byte_offset, void *client_data)
|
||||
{
|
||||
struct codec_api* ci = (struct codec_api*)client_data;
|
||||
struct codec_api* ci = (struct codec_api*)client_data;
|
||||
|
||||
(void)decoder;
|
||||
*absolute_byte_offset=ci->curpos;
|
||||
return(FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK);
|
||||
(void)decoder;
|
||||
*absolute_byte_offset=ci->curpos;
|
||||
return(FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK);
|
||||
}
|
||||
|
||||
FLAC__SeekableStreamDecoderLengthStatus flac_length_handler (const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__uint64 *stream_length, void *client_data)
|
||||
{
|
||||
struct codec_api* ci = (struct codec_api*)client_data;
|
||||
struct codec_api* ci = (struct codec_api*)client_data;
|
||||
|
||||
(void)decoder;
|
||||
*stream_length=ci->filesize;
|
||||
return(FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK);
|
||||
(void)decoder;
|
||||
*stream_length=ci->filesize;
|
||||
return(FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK);
|
||||
}
|
||||
|
||||
FLAC__bool flac_eof_handler (const FLAC__SeekableStreamDecoder *decoder,
|
||||
void *client_data)
|
||||
{
|
||||
struct codec_api* ci = (struct codec_api*)client_data;
|
||||
struct codec_api* ci = (struct codec_api*)client_data;
|
||||
|
||||
(void)decoder;
|
||||
if (ci->curpos >= ci->filesize) {
|
||||
(void)decoder;
|
||||
if (ci->curpos >= ci->filesize) {
|
||||
return(true);
|
||||
} else {
|
||||
} else {
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SIMULATOR
|
||||
|
@ -160,104 +179,193 @@ extern char iramstart[];
|
|||
extern char iramend[];
|
||||
#endif
|
||||
|
||||
FLAC__uint64 find_sample_number(size_t offset)
|
||||
{
|
||||
FLAC__StreamMetadata_SeekPoint *points;
|
||||
FLAC__uint64 prev_sample, next_sample;
|
||||
size_t prev_offset, next_offset;
|
||||
int percent;
|
||||
|
||||
if ( offset >= (rb->id3->filesize - metadata_length)) {
|
||||
return stream_info->data.stream_info.total_samples;
|
||||
}
|
||||
|
||||
prev_offset = 0;
|
||||
prev_sample = 0;
|
||||
next_offset = rb->id3->filesize - metadata_length;
|
||||
next_sample = stream_info->data.stream_info.total_samples;
|
||||
|
||||
if ( seek_table ) {
|
||||
int left, right, middle;
|
||||
|
||||
middle = 0; /* Silence compiler warnings */
|
||||
points = seek_table->data.seek_table.points;
|
||||
left = 0;
|
||||
right = seek_table->data.seek_table.num_points - 1;
|
||||
|
||||
/* Do a binary search to find the matching seek point */
|
||||
while ( left <= right ) {
|
||||
middle = (left + right) / 2;
|
||||
|
||||
if ( (FLAC__uint64)offset < points[middle].stream_offset ) {
|
||||
right = middle - 1;
|
||||
} else if ( (FLAC__uint64)offset > points[middle].stream_offset ) {
|
||||
left = middle + 1;
|
||||
} else {
|
||||
return points[middle].sample_number;
|
||||
}
|
||||
}
|
||||
|
||||
/* Didn't find a matching seek point, so get the sample numbers of the
|
||||
* seek points to the left and right of offset to make our guess more
|
||||
* accurate. Accuracy depends on how close these sample numbers are to
|
||||
* each other.
|
||||
*/
|
||||
if ( (unsigned)left >= seek_table->data.seek_table.num_points ) {
|
||||
prev_offset = points[middle].stream_offset;
|
||||
prev_sample = points[middle].sample_number;
|
||||
} else if ( right < 0 ) {
|
||||
next_offset = points[middle].stream_offset;
|
||||
next_sample = points[middle].sample_number;
|
||||
} else {
|
||||
middle--;
|
||||
prev_offset = points[middle].stream_offset;
|
||||
prev_sample = points[middle].sample_number;
|
||||
next_offset = points[middle+1].stream_offset;
|
||||
next_sample = points[middle+1].sample_number;
|
||||
}
|
||||
}
|
||||
|
||||
/* Either there's no seek table or we didn't find our seek point, so now we
|
||||
* have to guess.
|
||||
*/
|
||||
percent = ((offset - prev_offset) * 100) / (next_offset - prev_offset);
|
||||
return (FLAC__uint64)(percent * (next_sample - prev_sample) / 100 + prev_sample);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Generic codec initialisation */
|
||||
TEST_CODEC_API(api);
|
||||
/* Generic codec initialisation */
|
||||
TEST_CODEC_API(api);
|
||||
|
||||
/* if you are using a global api pointer, don't forget to copy it!
|
||||
otherwise you will get lovely "I04: IllInstr" errors... :-) */
|
||||
rb = api;
|
||||
/* if you are using a global api pointer, don't forget to copy it!
|
||||
otherwise you will get lovely "I04: IllInstr" errors... :-) */
|
||||
rb = api;
|
||||
|
||||
#ifndef SIMULATOR
|
||||
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
|
||||
rb->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*128));
|
||||
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(DSP_DITHER, (bool *)false);
|
||||
ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED);
|
||||
ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16));
|
||||
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:
|
||||
next_track:
|
||||
|
||||
if (codec_init(api)) {
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
metadata_length = 0;
|
||||
seek_table = NULL;
|
||||
stream_info = NULL;
|
||||
|
||||
while (!rb->taginfo_ready)
|
||||
if (codec_init(api)) {
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
while (!rb->taginfo_ready)
|
||||
rb->yield();
|
||||
|
||||
if (rb->id3->frequency != NATIVE_FREQUENCY) {
|
||||
rb->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency));
|
||||
rb->configure(CODEC_DSP_ENABLE, (bool *)true);
|
||||
} else {
|
||||
rb->configure(CODEC_DSP_ENABLE, (bool *)false);
|
||||
}
|
||||
rb->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency));
|
||||
codec_set_replaygain(ci->id3);
|
||||
|
||||
/* Create a decoder instance */
|
||||
/* Create a decoder instance */
|
||||
|
||||
flacDecoder=FLAC__seekable_stream_decoder_new();
|
||||
flacDecoder=FLAC__seekable_stream_decoder_new();
|
||||
|
||||
/* Set up the decoder and the callback functions - this must be done before init */
|
||||
/* 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(flacDecoder, FLAC__METADATA_TYPE_STREAMINFO);
|
||||
/* 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);
|
||||
/* 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);
|
||||
|
||||
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) {
|
||||
rb->yield();
|
||||
if (ci->stop_codec || ci->reload_codec) {
|
||||
break;
|
||||
/* QUESTION: What do we do when the init fails? */
|
||||
if (FLAC__seekable_stream_decoder_init(flacDecoder)) {
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
if (ci->seek_time) {
|
||||
int sample_loc;
|
||||
/* The first thing to do is to parse the metadata */
|
||||
FLAC__seekable_stream_decoder_process_until_end_of_metadata(flacDecoder);
|
||||
|
||||
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));
|
||||
if ( ci->id3->offset && stream_info ) {
|
||||
FLAC__uint64 sample;
|
||||
|
||||
sample = find_sample_number( 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) {
|
||||
rb->yield();
|
||||
if (ci->stop_codec || ci->reload_codec) {
|
||||
break;
|
||||
}
|
||||
ci->seek_time = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
FLAC__seekable_stream_decoder_process_single(flacDecoder);
|
||||
}
|
||||
/* Flush the libFLAC buffers */
|
||||
FLAC__seekable_stream_decoder_finish(flacDecoder);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (ci->request_next_track())
|
||||
goto next_track;
|
||||
|
||||
return CODEC_OK;
|
||||
return CODEC_OK;
|
||||
}
|
||||
|
|
|
@ -70,6 +70,31 @@ void* codec_realloc(void* ptr, size_t size)
|
|||
return(x);
|
||||
}
|
||||
|
||||
size_t strlen(const char *s)
|
||||
{
|
||||
return(local_rb->strlen(s));
|
||||
}
|
||||
|
||||
char *strcpy(char *dest, const char *src)
|
||||
{
|
||||
return(local_rb->strcpy(dest,src));
|
||||
}
|
||||
|
||||
char *strcat(char *dest, const char *src)
|
||||
{
|
||||
return(local_rb->strcat(dest,src));
|
||||
}
|
||||
|
||||
int strcmp(const char *s1, const char *s2)
|
||||
{
|
||||
return(local_rb->strcmp(s1,s2));
|
||||
}
|
||||
|
||||
int strncasecmp(const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
return(local_rb->strncasecmp(s1,s2,n));
|
||||
}
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
return(local_rb->memcpy(dest,src,n));
|
||||
|
|
|
@ -49,6 +49,12 @@ void* codec_calloc(size_t nmemb, size_t size);
|
|||
void* codec_alloca(size_t size);
|
||||
void* codec_realloc(void* ptr, size_t size);
|
||||
void codec_free(void* ptr);
|
||||
size_t strlen(const char *s);
|
||||
char *strcpy(char *dest, const char *src);
|
||||
char *strcat(char *dest, const char *src);
|
||||
int strcmp(const char *, const char *);
|
||||
int strcasecmp(const char *, const char *);
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n);
|
||||
void *memset(void *s, int c, size_t n);
|
||||
int memcmp(const void *s1, const void *s2, size_t n);
|
||||
|
|
|
@ -8,6 +8,7 @@ format.c
|
|||
lpc.c
|
||||
md5.c
|
||||
memory.c
|
||||
metadata_object.c
|
||||
seekable_stream_decoder.c
|
||||
stream_decoder.c
|
||||
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
|
||||
|
|
|
@ -295,7 +295,7 @@ extern FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[];
|
|||
* \retval FLAC__Metadata_SimpleIterator*
|
||||
* \c NULL if there was an error allocating memory, else the new instance.
|
||||
*/
|
||||
FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new();
|
||||
FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void);
|
||||
|
||||
/** Free an iterator instance. Deletes the object pointed to by \a iterator.
|
||||
*
|
||||
|
@ -652,7 +652,7 @@ extern FLAC_API const char * const FLAC__Metadata_ChainStatusString[];
|
|||
* \retval FLAC__Metadata_Chain*
|
||||
* \c NULL if there was an error allocating memory, else the new instance.
|
||||
*/
|
||||
FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new();
|
||||
FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void);
|
||||
|
||||
/** Free a chain instance. Deletes the object pointed to by \a chain.
|
||||
*
|
||||
|
@ -899,7 +899,7 @@ FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain);
|
|||
* \retval FLAC__Metadata_Iterator*
|
||||
* \c NULL if there was an error allocating memory, else the new instance.
|
||||
*/
|
||||
FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new();
|
||||
FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void);
|
||||
|
||||
/** Free an iterator instance. Deletes the object pointed to by \a iterator.
|
||||
*
|
||||
|
@ -1621,7 +1621,7 @@ FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__S
|
|||
* \retval FLAC__StreamMetadata_CueSheet_Track*
|
||||
* \c NULL if there was an error allocating memory, else the new instance.
|
||||
*/
|
||||
FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new();
|
||||
FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void);
|
||||
|
||||
/** Create a copy of an existing CUESHEET track object.
|
||||
*
|
||||
|
|
|
@ -33,21 +33,6 @@ static struct codec_api* rb;
|
|||
|
||||
int errno;
|
||||
|
||||
size_t strlen(const char *s)
|
||||
{
|
||||
return(rb->strlen(s));
|
||||
}
|
||||
|
||||
char *strcpy(char *dest, const char *src)
|
||||
{
|
||||
return(rb->strcpy(dest,src));
|
||||
}
|
||||
|
||||
char *strcat(char *dest, const char *src)
|
||||
{
|
||||
return(rb->strcat(dest,src));
|
||||
}
|
||||
|
||||
size_t read_handler(void *ptr, size_t size, size_t nmemb, void *datasource)
|
||||
{
|
||||
(void)datasource;
|
||||
|
|
127
apps/metadata.c
127
apps/metadata.c
|
@ -92,7 +92,7 @@ const long wavpack_sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000,
|
|||
|
||||
static bool get_apetag_info (struct mp3entry *entry, int fd);
|
||||
|
||||
static bool get_vorbis_comments (struct mp3entry *entry, int fd);
|
||||
static bool get_vorbis_comments (struct mp3entry *entry, size_t bytes_remaining, int fd);
|
||||
|
||||
static void little_endian_to_native (void *data, char *format);
|
||||
|
||||
|
@ -104,6 +104,9 @@ bool get_metadata(struct track_info* track, int fd, const char* trackname,
|
|||
unsigned char* buf;
|
||||
int i,j,eof;
|
||||
int rc;
|
||||
int segments; /* for Vorbis*/
|
||||
size_t bytes_remaining = 0; /* for Vorbis */
|
||||
|
||||
|
||||
/* Load codec specific track tag information. */
|
||||
switch (track->id3.codectype) {
|
||||
|
@ -215,7 +218,10 @@ bool get_metadata(struct track_info* track, int fd, const char* trackname,
|
|||
} else if ((buf[0]&0x7f)==4) { /* 4 is the VORBIS_COMMENT block */
|
||||
|
||||
/* The next i bytes of the file contain the VORBIS COMMENTS - just skip them for now. */
|
||||
lseek(fd, i, SEEK_CUR);
|
||||
//lseek(fd, i, SEEK_CUR);
|
||||
if (!get_vorbis_comments(&(track->id3), i, fd)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (buf[0]&0x80) { /* If we have reached the last metadata block, abort. */
|
||||
|
@ -272,12 +278,61 @@ bool get_metadata(struct track_info* track, int fd, const char* trackname,
|
|||
track->id3.frequency=buf[40]|(buf[41]<<8)|(buf[42]<<16)|(buf[43]<<24);
|
||||
channels=buf[39];
|
||||
|
||||
if ( !get_vorbis_comments(&(track->id3), fd) ) {
|
||||
/* Comments are in second Ogg page */
|
||||
if ( lseek(fd, 58, SEEK_SET) < 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Minimum header length for Ogg pages is 27 */
|
||||
if (read(fd, buf, 27) < 27) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(buf,"OggS",4)!=0) {
|
||||
logf("1: Not an Ogg Vorbis file");
|
||||
return(false);
|
||||
}
|
||||
|
||||
segments=buf[26];
|
||||
/* read in segment table */
|
||||
if (read(fd, buf, segments) < segments) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The second packet in a vorbis stream is the comment packet. It *may*
|
||||
* extend beyond the second page, but usually does not. Here we find the
|
||||
* length of the comment packet (or the rest of the page if the comment
|
||||
* packet extends to the third page).
|
||||
*/
|
||||
for (i = 0; i < segments; i++) {
|
||||
bytes_remaining += buf[i];
|
||||
/* The last segment of a packet is always < 255 bytes */
|
||||
if (buf[i] < 255) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now read in packet header (type and id string) */
|
||||
if(read(fd, buf, 7) < 7) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The first byte of a packet is the packet type; comment packets are
|
||||
* type 3.
|
||||
*/
|
||||
if ((buf[0] != 3) || (memcmp(buf + 1,"vorbis",6)!=0)) {
|
||||
logf("Not a vorbis comment packet");
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes_remaining -= 7;
|
||||
|
||||
if ( !get_vorbis_comments(&(track->id3), bytes_remaining, fd) ) {
|
||||
logf("get_vorbis_comments failed");
|
||||
return(false);
|
||||
}
|
||||
|
||||
/* Set id3 genre to something bogus, otherwise vorbis tracks
|
||||
/* Set id3v1 genre to 255 (effectively 'none'), otherwise vorbis tracks
|
||||
* without genre tags will show up as 'Blues'
|
||||
*/
|
||||
track->id3.genre=255;
|
||||
|
@ -780,7 +835,7 @@ static void UTF8ToAnsi (unsigned char *pUTF8)
|
|||
* Additionally, vorbis comments *may* take up more than one Ogg page, and this
|
||||
* only looks at the first page of comments.
|
||||
*/
|
||||
static bool get_vorbis_comments (struct mp3entry *entry, int fd)
|
||||
static bool get_vorbis_comments (struct mp3entry *entry, size_t bytes_remaining, int fd)
|
||||
{
|
||||
int vendor_length;
|
||||
int comment_count;
|
||||
|
@ -790,58 +845,6 @@ static bool get_vorbis_comments (struct mp3entry *entry, int fd)
|
|||
int buffer_remaining = sizeof(entry->id3v2buf) + sizeof(entry->id3v1buf);
|
||||
char *buffer = entry->id3v2buf;
|
||||
char **p = NULL;
|
||||
int segments;
|
||||
int packet_remaining = 0;
|
||||
|
||||
/* Comments are in second Ogg page */
|
||||
if ( lseek(fd, 58, SEEK_SET) < 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Minimum header length for Ogg pages is 27 */
|
||||
if (read(fd, temp, 27) < 27) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(temp,"OggS",4)!=0) {
|
||||
logf("1: Not an Ogg Vorbis file");
|
||||
return(false);
|
||||
}
|
||||
|
||||
segments=temp[26];
|
||||
/* read in segment table */
|
||||
if (read(fd, temp, segments) < segments) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The second packet in a vorbis stream is the comment packet. It *may*
|
||||
* extend beyond the second page, but usually does not. Here we find the
|
||||
* length of the comment packet (or the rest of the page if the comment
|
||||
* packet extends to the third page).
|
||||
*/
|
||||
for (i = 0; i < segments; i++) {
|
||||
packet_remaining += temp[i];
|
||||
/* The last segment of a packet is always < 255 bytes */
|
||||
if (temp[i] < 255) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now read in packet header (type and id string) */
|
||||
if(read(fd, temp, 7) < 7) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The first byte of a packet is the packet type; comment packets are
|
||||
* type 3.
|
||||
*/
|
||||
if ((temp[0] != 3) || (memcmp(temp + 1,"vorbis",6)!=0)) {
|
||||
logf("Not a vorbis comment packet");
|
||||
return false;
|
||||
}
|
||||
|
||||
packet_remaining -= 7;
|
||||
|
||||
|
||||
/* We've read in all header info, now start reading comments */
|
||||
|
||||
|
@ -855,8 +858,8 @@ static bool get_vorbis_comments (struct mp3entry *entry, int fd)
|
|||
return false;
|
||||
}
|
||||
little_endian_to_native(&comment_count, "L");
|
||||
packet_remaining -= (vendor_length + 8);
|
||||
if ( packet_remaining <= 0 ) {
|
||||
bytes_remaining -= (vendor_length + 8);
|
||||
if ( bytes_remaining <= 0 ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -870,8 +873,8 @@ static bool get_vorbis_comments (struct mp3entry *entry, int fd)
|
|||
little_endian_to_native(&comment_length, "L");
|
||||
|
||||
/* Quit if we've passed the end of the page */
|
||||
packet_remaining -= (comment_length + 4);
|
||||
if ( packet_remaining <= 0 ) {
|
||||
bytes_remaining -= (comment_length + 4);
|
||||
if ( bytes_remaining <= 0 ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -929,6 +932,6 @@ static bool get_vorbis_comments (struct mp3entry *entry, int fd)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -887,6 +887,7 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
|
|||
tracks[track_widx].start_pos = offset;
|
||||
break;
|
||||
case AFMT_OGG_VORBIS:
|
||||
case AFMT_FLAC:
|
||||
tracks[track_widx].id3.offset = offset;
|
||||
break;
|
||||
}
|
||||
|
@ -1366,7 +1367,7 @@ static void initiate_track_change(int peek_index)
|
|||
if (!paused)
|
||||
pcm_play_pause(true);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Detect if disk is spinning.. */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue