Skip to content

ogg123: support FLAC seeking for regular files #29

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions ogg123/file_transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ typedef struct file_private_t {
FILE *fp;
data_source_stats_t stats;
int seekable;
long length;
} file_private_t;


Expand All @@ -42,6 +43,37 @@ int file_can_transport (const char *source_string)
return 1; /* The file transport is tested last, so always try it */
}

static long stdio_file_length(FILE *fp) {
int rc;
long len, off;

if (!fp) {
return -1;
}

off = ftell(fp);
if (off < 0) {
return -1;
}

rc = fseek(fp, 0, SEEK_END);
if (rc != 0) {
return -1;
}

len = ftell(fp);
if (len < 0) {
return -1;
}

rc = fseek(fp, off, SEEK_SET);
if (rc != 0) {
return -1;
}

return len;
}

data_source_t* file_open (const char *source_string, ogg123_options_t *ogg123_opts)
{
data_source_t *source;
Expand Down Expand Up @@ -69,8 +101,19 @@ data_source_t* file_open (const char *source_string, ogg123_options_t *ogg123_op
if (strcmp(source_string, "-") == 0) {
private->fp = stdin;
private->seekable = 0;
} else
private->fp = fopen(source_string, "r");
private->length = -1;
} else {
FILE *fp = fopen(source_string, "r");
long len = stdio_file_length(fp);

if (fp && len < 0) {
fclose(fp);
fp = NULL;
}

private->fp = fp;
private->length = len;
}

if (private->fp == NULL) {
free(source->source_string);
Expand Down Expand Up @@ -164,6 +207,11 @@ void file_close (data_source_t *source)
free(source);
}

long file_length (data_source_t *source) {
file_private_t *private = source->private;

return private->length;
}

transport_t file_transport = {
"file",
Expand All @@ -174,5 +222,6 @@ transport_t file_transport = {
&file_seek,
&file_statistics,
&file_tell,
&file_close
&file_close,
&file_length
};
77 changes: 75 additions & 2 deletions ogg123/flac_format.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <limits.h>
#include <math.h>
#include <FLAC/all.h>
#include <ao/ao.h>
Expand Down Expand Up @@ -90,8 +91,12 @@ static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *
static void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
static FLAC__bool eof_callback(const FLAC__StreamDecoder *decoder, void *client_data);
static FLAC__StreamDecoderSeekStatus seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 off, void *client_data);
static FLAC__StreamDecoderTellStatus tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *off, void *client_data);
static FLAC__StreamDecoderLengthStatus length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *len, void *client_data);
#endif


void resize_buffer(flac_private_t *flac, int newchannels, int newsamples);
/*void copy_comments (vorbis_comment *v_comments, FLAC__StreamMetadata_VorbisComment *f_comments);*/
void print_flac_stream_info (decoder_t *decoder);
Expand Down Expand Up @@ -217,9 +222,29 @@ decoder_t* flac_init (data_source_t *source, ogg123_options_t *ogg123_opts,
FLAC__stream_decoder_set_metadata_respond(private->decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
/*FLAC__stream_decoder_init(private->decoder);*/
if(private->is_oggflac)
FLAC__stream_decoder_init_ogg_stream(private->decoder, read_callback, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, eof_callback, write_callback, metadata_callback, error_callback, decoder);
FLAC__stream_decoder_init_ogg_stream(
private->decoder,
read_callback,
seek_callback,
tell_callback,
length_callback,
eof_callback,
write_callback,
metadata_callback,
error_callback,
decoder);
else
FLAC__stream_decoder_init_stream(private->decoder, read_callback, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, eof_callback, write_callback, metadata_callback, error_callback, decoder);
FLAC__stream_decoder_init_stream(
private->decoder,
read_callback,
seek_callback,
tell_callback,
length_callback,
eof_callback,
write_callback,
metadata_callback,
error_callback,
decoder);
#endif

/* Callback will set the total samples and sample rate */
Expand Down Expand Up @@ -358,6 +383,11 @@ int flac_read (decoder_t *decoder, void *ptr, int nbytes, int *eos,

int flac_seek (decoder_t *decoder, double offset, int whence)
{
if (whence == DECODER_SEEK_START) {
flac_private_t *private = decoder->private;
FLAC__uint64 sample = private->rate * offset;
return FLAC__stream_decoder_seek_absolute(private->decoder, sample);
}
return 0; /* No seeking at this time */
}

Expand Down Expand Up @@ -544,6 +574,49 @@ FLAC__bool eof_callback(const FLAC__StreamDecoder *decoder, void *client_data)

return priv->eos;
}

FLAC__StreamDecoderSeekStatus seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 off64, void *client_data)
{
decoder_t *d = client_data;
transport_t *transport = d->source->transport;

if (off64 < LONG_MAX) {
long off = (long) off64;
int rc = transport->seek(d->source, off, SEEK_SET);
if (rc == 0) {
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
}
}
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
}

FLAC__StreamDecoderTellStatus tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *off64, void *client_data)
{
decoder_t *d = client_data;
transport_t *transport = d->source->transport;

long off = transport->tell(d->source);
if (off >= 0) {
*off64 = (unsigned long) off;
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
}

return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
}

FLAC__StreamDecoderLengthStatus length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *len64, void *client_data)
{
decoder_t *d = client_data;
transport_t *transport = d->source->transport;

long len = transport->length(d->source);
if (len >= 0) {
*len64 = (unsigned long) len;
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
}

return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
}
#endif


Expand Down
6 changes: 5 additions & 1 deletion ogg123/http_transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,9 @@ void http_close (data_source_t *source)
free(source);
}

long http_length (data_source_t * source) {
return -1;
}

transport_t http_transport = {
"http",
Expand All @@ -347,7 +350,8 @@ transport_t http_transport = {
&http_seek,
&http_statistics,
&http_tell,
&http_close
&http_close,
&http_length
};

#endif /* HAVE_CURL */
1 change: 1 addition & 0 deletions ogg123/transport.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ typedef struct transport_t {
data_source_stats_t * (* statistics) (data_source_t *source);
long (* tell) (data_source_t *source);
void (* close) (data_source_t *source);
long (* length) (data_source_t *source);
} transport_t;

const transport_t *get_transport_by_name (const char *name);
Expand Down