diff options
-rw-r--r-- | deadbeef.h | 10 | ||||
-rw-r--r-- | plugins.c | 9 | ||||
-rw-r--r-- | plugins/mpgmad/mpgmad.c | 8 | ||||
-rw-r--r-- | plugins/vfs_curl/vfs_curl.c | 94 | ||||
-rw-r--r-- | vfs.c | 8 | ||||
-rw-r--r-- | vfs.h | 5 | ||||
-rw-r--r-- | vfs_stdio.c | 12 |
7 files changed, 118 insertions, 28 deletions
@@ -188,9 +188,10 @@ typedef struct { DB_FILE* (*fopen) (const char *fname); void (*fclose) (DB_FILE *f); size_t (*fread) (void *ptr, size_t size, size_t nmemb, DB_FILE *stream); - int (*fseek) (DB_FILE *stream, long offset, int whence); - long (*ftell) (DB_FILE *stream); + int (*fseek) (DB_FILE *stream, int64_t offset, int whence); + int64_t (*ftell) (DB_FILE *stream); void (*rewind) (DB_FILE *stream); + int64_t (*fgetlength) (DB_FILE *stream); } DB_functions_t; // base plugin interface @@ -323,9 +324,10 @@ typedef struct DB_vfs_s { DB_FILE* (*open) (const char *fname); void (*close) (DB_FILE *f); size_t (*read) (void *ptr, size_t size, size_t nmemb, DB_FILE *stream); - int (*seek) (DB_FILE *stream, long offset, int whence); - long (*tell) (DB_FILE *stream); + int (*seek) (DB_FILE *stream, int64_t offset, int whence); + int64_t (*tell) (DB_FILE *stream); void (*rewind) (DB_FILE *stream); + int64_t (*getlength)(DB_FILE *stream); const char **scheme_names; // NULL-terminated list of supported schemes, e.g. {"http", "ftp", NULL} unsigned streaming : 1; } DB_vfs_t; @@ -85,7 +85,7 @@ static DB_functions_t deadbeef_api = { // metainfo .pl_add_meta = (void (*) (DB_playItem_t *, const char *, const char *))pl_add_meta, .pl_find_meta = (const char *(*) (DB_playItem_t *, const char *))pl_find_meta, - .pl_delete_all_meta = (void (*) (playItem_t *it))pl_delete_all_meta, + .pl_delete_all_meta = (void (*) (DB_playItem_t *it))pl_delete_all_meta, // cuesheet support .pl_insert_cue_from_buffer = (DB_playItem_t *(*) (DB_playItem_t *after, const char *fname, const uint8_t *buffer, int buffersize, struct DB_decoder_s *decoder, const char *ftype, int numsamples, int samplerate))pl_insert_cue_from_buffer, .pl_insert_cue = (DB_playItem_t *(*)(DB_playItem_t *, const char *, struct DB_decoder_s *, const char *ftype, int numsamples, int samplerate))pl_insert_cue, @@ -95,9 +95,9 @@ static DB_functions_t deadbeef_api = { .volume_set_amp = plug_volume_set_amp, .volume_get_amp = volume_get_amp, // junk reading - .junk_read_id3v1 = (int (*)(DB_playItem_t *it, FILE *fp))junk_read_id3v1, - .junk_read_id3v2 = (int (*)(DB_playItem_t *it, FILE *fp))junk_read_id3v2, - .junk_read_ape = (int (*)(DB_playItem_t *it, FILE *fp))junk_read_ape, + .junk_read_id3v1 = (int (*)(DB_playItem_t *it, DB_FILE *fp))junk_read_id3v1, + .junk_read_id3v2 = (int (*)(DB_playItem_t *it, DB_FILE *fp))junk_read_id3v2, + .junk_read_ape = (int (*)(DB_playItem_t *it, DB_FILE *fp))junk_read_ape, .junk_get_leading_size = junk_get_leading_size, // vfs .fopen = vfs_fopen, @@ -106,6 +106,7 @@ static DB_functions_t deadbeef_api = { .fseek = vfs_fseek, .ftell = vfs_ftell, .rewind = vfs_rewind, + .fgetlength = vfs_fgetlength, }; DB_functions_t *deadbeef = &deadbeef_api; diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c index fe73b17f..4be6540b 100644 --- a/plugins/mpgmad/mpgmad.c +++ b/plugins/mpgmad/mpgmad.c @@ -434,6 +434,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { if (sample == 0) { // xing header failed, calculate based on file size trace ("xing header failed\n"); +#if 0 if (buffer->file->vfs->streaming) { // set infinite lenght buffer->duration = -1; @@ -441,8 +442,11 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { buffer->samplerate = samplerate; return 0; } - deadbeef->fseek (buffer->file, 0, SEEK_END); - int sz = deadbeef->ftell (buffer->file) - buffer->startoffset - buffer->endoffset; +#endif + + //deadbeef->fseek (buffer->file, 0, SEEK_END); + //int sz = deadbeef->ftell (buffer->file) - buffer->startoffset - buffer->endoffset; + int sz = deadbeef->fgetlength (buffer->file) - buffer->startoffset - buffer->endoffset; int nframes = sz / packetlength; buffer->duration = nframes * samples_per_frame / samplerate; buffer->totalsamples = nframes * samples_per_frame; diff --git a/plugins/vfs_curl/vfs_curl.c b/plugins/vfs_curl/vfs_curl.c index c4f527b6..f2a417b7 100644 --- a/plugins/vfs_curl/vfs_curl.c +++ b/plugins/vfs_curl/vfs_curl.c @@ -35,21 +35,23 @@ static DB_functions_t *deadbeef; #define BUFFER_MASK 0xffff #define STATUS_INITIAL 0 -#define STATUS_READING 1 -#define STATUS_FINISHED 2 -#define STATUS_ABORTED 3 -#define STATUS_SEEK 4 +#define STATUS_STARTING 1 +#define STATUS_READING 2 +#define STATUS_FINISHED 3 +#define STATUS_ABORTED 4 +#define STATUS_SEEK 5 typedef struct { DB_vfs_t *vfs; - uint8_t buffer[BUFFER_SIZE]; - int pos; // position in stream; use "& BUFFER_MASK" to make it index into ringbuffer - int remaining; // remaining bytes in buffer read from stream - int skipbytes; - int status; char *url; + uint8_t buffer[BUFFER_SIZE]; + int64_t pos; // position in stream; use "& BUFFER_MASK" to make it index into ringbuffer + int64_t length; + int32_t remaining; // remaining bytes in buffer read from stream + int32_t skipbytes; intptr_t tid; // thread id which does http requests intptr_t mutex; + uint8_t status; } HTTP_FILE; static DB_vfs_t plugin; @@ -103,11 +105,51 @@ http_curl_write (void *ptr, size_t size, size_t nmemb, void *stream) { return nmemb * size - avail; } +static size_t +http_size_request_handler (void *ptr, size_t size, size_t nmemb, void *stream) { + assert (stream); + HTTP_FILE *fp = (HTTP_FILE *)stream; + // don't copy/allocate mem, just grep for "Content-Length: " + const char *cl = strstr (ptr, "Content-Length: "); + if (cl) { + cl += 16; + fp->length = atoi (cl); + trace ("vfs_curl: file size is %d bytes\n", fp->length); + } +// else { +// trace ("vfs_curl: unable to get file size\n"); +// fp->length = -1; // infinite +// } + return size * nmemb; +} + static void http_thread_func (uintptr_t ctx) { HTTP_FILE *fp = (HTTP_FILE *)ctx; CURL *curl; curl = curl_easy_init (); + fp->length = -1; + fp->status = STATUS_INITIAL; + + // get filesize (once) + int status; + curl_easy_setopt(curl, CURLOPT_URL, fp->url); + curl_easy_setopt(curl, CURLOPT_NOBODY, 1); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10); + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, http_size_request_handler); + curl_easy_setopt (curl, CURLOPT_HEADERDATA, ctx); + status = curl_easy_perform(curl); + if (status != 0) { + trace ("vfs_curl: curl_easy_perform failed while getting filesize, status %d\n", status); + fp->status = STATUS_FINISHED; + fp->tid = 0; + return; + } + + curl_easy_reset (curl); + fp->status = STATUS_STARTING; + for (;;) { curl_easy_setopt (curl, CURLOPT_URL, fp->url); curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1); @@ -116,13 +158,16 @@ http_thread_func (uintptr_t ctx) { curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, http_err); curl_easy_setopt (curl, CURLOPT_BUFFERSIZE, BUFFER_SIZE/2); curl_easy_setopt (curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + // enable up to 10 redirects + curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt (curl, CURLOPT_MAXREDIRS, 10); if (fp->pos > 0) { curl_easy_setopt (curl, CURLOPT_RESUME_FROM, fp->pos); } deadbeef->mutex_lock (fp->mutex); fp->status = STATUS_READING; deadbeef->mutex_unlock (fp->mutex); - int status = curl_easy_perform (curl); + status = curl_easy_perform (curl); trace ("curl: curl_easy_perform status=%d\n", status); deadbeef->mutex_lock (fp->mutex); if (fp->status != STATUS_SEEK) { @@ -138,6 +183,13 @@ http_thread_func (uintptr_t ctx) { deadbeef->mutex_lock (fp->mutex); fp->status = STATUS_FINISHED; deadbeef->mutex_unlock (fp->mutex); + fp->tid = 0; +} + +static void +http_start_streamer (HTTP_FILE *fp) { + fp->mutex = deadbeef->mutex_create (); + fp->tid = deadbeef->thread_start (http_thread_func, (uintptr_t)fp); } static DB_FILE * @@ -176,8 +228,7 @@ http_read (void *ptr, size_t size, size_t nmemb, DB_FILE *stream) { // assert (size * nmemb <= BUFFER_SIZE); // trace ("readpos=%d, readsize=%d\n", fp->pos & BUFFER_SIZE, sz); if (!fp->tid) { - fp->mutex = deadbeef->mutex_create (); - fp->tid = deadbeef->thread_start (http_thread_func, (uintptr_t)fp); + http_start_streamer (fp); } while (fp->status != STATUS_FINISHED && sz > 0) { @@ -223,7 +274,7 @@ http_read (void *ptr, size_t size, size_t nmemb, DB_FILE *stream) { } static int -http_seek (DB_FILE *stream, long offset, int whence) { +http_seek (DB_FILE *stream, int64_t offset, int whence) { trace ("http_seek %x %d\n", offset, whence); if (whence == SEEK_END) { trace ("vfs_curl: can't seek in curl stream relative to EOF\n"); @@ -277,7 +328,7 @@ http_seek (DB_FILE *stream, long offset, int whence) { return -1; } -static long +static int64_t http_tell (DB_FILE *stream) { assert (stream); HTTP_FILE *fp = (HTTP_FILE *)stream; @@ -298,6 +349,20 @@ http_rewind (DB_FILE *stream) { } } +static int64_t +http_getlength (DB_FILE *stream) { + trace ("http_getlength"); + assert (stream); + HTTP_FILE *fp = (HTTP_FILE *)stream; + if (!fp->tid) { + http_start_streamer (fp); + } + while (fp->status == STATUS_INITIAL) { + sleep (3000); + } + return fp->length; +} + static const char *scheme_names[] = { "http://", NULL }; // standard stdio vfs @@ -316,6 +381,7 @@ static DB_vfs_t plugin = { .seek = http_seek, .tell = http_tell, .rewind = http_rewind, + .getlength = http_getlength, .scheme_names = scheme_names, .streaming = 1 }; @@ -61,11 +61,11 @@ vfs_fread (void *ptr, size_t size, size_t nmemb, DB_FILE *stream) { } int -vfs_fseek (DB_FILE *stream, long offset, int whence) { +vfs_fseek (DB_FILE *stream, int64_t offset, int whence) { return stream->vfs->seek (stream, offset, whence); } -long +int64_t vfs_ftell (DB_FILE *stream) { return stream->vfs->tell (stream); } @@ -75,3 +75,7 @@ vfs_rewind (DB_FILE *stream) { stream->vfs->rewind (stream); } +int64_t +vfs_fgetlength (DB_FILE *stream) { + return stream->vfs->getlength (stream); +} @@ -25,8 +25,9 @@ DB_FILE* vfs_fopen (const char *fname); void vfs_fclose (DB_FILE *f); size_t vfs_fread (void *ptr, size_t size, size_t nmemb, DB_FILE *stream); -int vfs_fseek (DB_FILE *stream, long offset, int whence); -long vfs_ftell (DB_FILE *stream); +int vfs_fseek (DB_FILE *stream, int64_t offset, int whence); +int64_t vfs_ftell (DB_FILE *stream); void vfs_rewind (DB_FILE *stream); +int64_t vfs_fgetlength (DB_FILE *stream); #endif // __VFS_H diff --git a/vfs_stdio.c b/vfs_stdio.c index 9d63c141..903f2af0 100644 --- a/vfs_stdio.c +++ b/vfs_stdio.c @@ -77,6 +77,17 @@ stdio_rewind (DB_FILE *stream) { rewind (((STDIO_FILE *)stream)->stream); } +static int64_t +stdio_getlength (DB_FILE *stream) { + assert (stream); + STDIO_FILE *f = (STDIO_FILE *)stream; + size_t pos = ftell (f->stream); + fseek (f->stream, 0, SEEK_END); + size_t sz = ftell (f->stream); + fseek (f->stream, pos, SEEK_SET); + return sz; +} + // standard stdio vfs static DB_vfs_t plugin = { DB_PLUGIN_SET_API_VERSION @@ -93,6 +104,7 @@ static DB_vfs_t plugin = { .seek = stdio_seek, .tell = stdio_tell, .rewind = stdio_rewind, + .getlength = stdio_getlength, .scheme_names = NULL // this is NULL because that's a fallback vfs, used when no other matching vfs plugin found }; |