summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deadbeef.h10
-rw-r--r--plugins.c9
-rw-r--r--plugins/mpgmad/mpgmad.c8
-rw-r--r--plugins/vfs_curl/vfs_curl.c94
-rw-r--r--vfs.c8
-rw-r--r--vfs.h5
-rw-r--r--vfs_stdio.c12
7 files changed, 118 insertions, 28 deletions
diff --git a/deadbeef.h b/deadbeef.h
index 27f79417..9c4f7af4 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -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;
diff --git a/plugins.c b/plugins.c
index be1d9881..641f34ea 100644
--- a/plugins.c
+++ b/plugins.c
@@ -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
};
diff --git a/vfs.c b/vfs.c
index 7f4e8458..53266b5c 100644
--- a/vfs.c
+++ b/vfs.c
@@ -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);
+}
diff --git a/vfs.h b/vfs.h
index 22ca1c25..3090ba1d 100644
--- a/vfs.h
+++ b/vfs.h
@@ -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
};