summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-09-30 21:11:02 +0200
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-09-30 21:11:02 +0200
commit6bab316f8326089d261bc7e8b034bb875484a0ce (patch)
tree98751acd6136a3647392e88d7b17ff56050d7be9 /plugins
parentfc2689bbd0af9323a366d6fe6b37f613e28fc53f (diff)
mp3 streaming WIP
Diffstat (limited to 'plugins')
-rw-r--r--plugins/mpgmad/mpgmad.c58
-rw-r--r--plugins/vfs_curl/vfs_curl.c114
2 files changed, 132 insertions, 40 deletions
diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c
index 14a277f0..f73fbba5 100644
--- a/plugins/mpgmad/mpgmad.c
+++ b/plugins/mpgmad/mpgmad.c
@@ -353,6 +353,8 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
buffer->startoffset = startoffset;
}
+ trace ("xing magic: %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]);
+
if (!strncmp (xing, magic, 4) || !strncmp (info, magic, 4)) {
trace ("xing/info frame found\n");
// read flags
@@ -431,6 +433,14 @@ 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 (buffer->file->vfs->streaming) {
+ // set infinite lenght
+ buffer->duration = -1;
+ buffer->totalsamples = -1;
+ buffer->samplerate = samplerate;
+ return 0;
+ }
deadbeef->fseek (buffer->file, 0, SEEK_END);
int sz = deadbeef->ftell (buffer->file) - buffer->startoffset - buffer->endoffset;
int nframes = sz / packetlength;
@@ -483,24 +493,37 @@ cmp3_init (DB_playItem_t *it) {
deadbeef->fseek(buffer.file, skip, SEEK_SET);
}
plugin.info.readpos = 0;
- cmp3_scan_stream (&buffer, -1); // scan entire stream, calc duration
- if (it->endsample > 0) {
- buffer.startsample = it->startsample;
- buffer.endsample = it->endsample;
- // that comes from cue, don't calc duration, just seek and play
- plugin.seek_sample (0);
+ if (!buffer.file->vfs->streaming) {
+ cmp3_scan_stream (&buffer, -1); // scan entire stream, calc duration
+ if (it->endsample > 0) {
+ buffer.startsample = it->startsample;
+ buffer.endsample = it->endsample;
+ // that comes from cue, don't calc duration, just seek and play
+ plugin.seek_sample (0);
+ }
+ else {
+ it->duration = buffer.duration;
+ buffer.startsample = 0;
+ buffer.endsample = buffer.totalsamples-1;
+ buffer.skipsamples = buffer.startdelay;
+ buffer.currentsample = buffer.startdelay;
+ deadbeef->fseek (buffer.file, buffer.startoffset, SEEK_SET);
+ }
}
else {
+ int res = cmp3_scan_stream (&buffer, 0);
+ if (res < 0) {
+ plugin.free ();
+ return -1;
+ }
it->duration = buffer.duration;
- buffer.startsample = 0;
- buffer.endsample = buffer.totalsamples-1;
- buffer.skipsamples = buffer.startdelay;
- buffer.currentsample = buffer.startdelay;
- deadbeef->fseek (buffer.file, buffer.startoffset, SEEK_SET);
+ buffer.endsample = buffer.totalsamples - 1;
+ buffer.skipsamples = 0;
+ buffer.currentsample = 0;
}
if (buffer.samplerate == 0) {
trace ("bad mpeg file: %f\n", it->fname);
- deadbeef->fclose (buffer.file);
+ plugin.free ();
return -1;
}
plugin.info.bps = buffer.bitspersample;
@@ -836,6 +859,17 @@ cmp3_insert (DB_playItem_t *after, const char *fname) {
if (!fp) {
return NULL;
}
+ if (fp->vfs->streaming) {
+ DB_playItem_t *it = deadbeef->pl_item_alloc ();
+ it->decoder = &plugin;
+ it->fname = strdup (fname);
+ deadbeef->fclose (fp);
+ deadbeef->pl_add_meta (it, "title", NULL);
+ it->duration = -1;
+ it->filetype = filetypes[0];
+ after = deadbeef->pl_insert_item (after, it);
+ return after;
+ }
buffer_t buffer;
memset (&buffer, 0, sizeof (buffer));
buffer.file = fp;
diff --git a/plugins/vfs_curl/vfs_curl.c b/plugins/vfs_curl/vfs_curl.c
index 8ff59d98..238e428d 100644
--- a/plugins/vfs_curl/vfs_curl.c
+++ b/plugins/vfs_curl/vfs_curl.c
@@ -46,6 +46,7 @@ typedef struct {
uint8_t buffer[BUFFER_SIZE*2];
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;
intptr_t tid; // thread id which does http requests
@@ -57,7 +58,8 @@ static DB_vfs_t plugin;
static char http_err[CURL_ERROR_SIZE];
static size_t
-lastfm_curl_write (void *ptr, size_t size, size_t nmemb, void *stream) {
+http_curl_write (void *ptr, size_t size, size_t nmemb, void *stream) {
+ trace ("http_curl_write %d bytes\n", size * nmemb);
HTTP_FILE *fp = (HTTP_FILE *)stream;
int avail = size * nmemb;
for (;;) {
@@ -71,16 +73,21 @@ lastfm_curl_write (void *ptr, size_t size, size_t nmemb, void *stream) {
int sz = BUFFER_SIZE - fp->remaining;
int cp = min (avail, 10000);
if (sz >= cp) {
+ trace ("pos=%d, remaining=%d, avail=%d\n", fp->pos, fp->remaining, avail);
cp = min (avail, sz);
int writepos = (fp->pos + fp->remaining) & BUFFER_MASK;
// copy data
int part1 = BUFFER_SIZE * 2 - writepos;
+ part1 = min (part1, BUFFER_SIZE);
part1 = min (part1, cp);
- int part2 = sz - part1;
+ //trace ("part1=%d\n", part1);
memcpy (fp->buffer+writepos, ptr, part1);
ptr += part1;
avail -= part1;
fp->remaining += part1;
+ int part2 = BUFFER_SIZE - fp->remaining;
+ part2 = min (avail, part2);
+ //trace ("part2=%d\n", part2);
if (part2 > 0) {
memcpy (fp->buffer, ptr, part2);
ptr += part2;
@@ -89,12 +96,13 @@ lastfm_curl_write (void *ptr, size_t size, size_t nmemb, void *stream) {
}
}
deadbeef->mutex_unlock (fp->mutex);
- if (avail >= size*nmemb) {
+ if (avail == 0) {
break;
}
usleep (3000);
}
+ trace ("returning %d\n", nmemb * size - avail);
return nmemb * size - avail;
}
@@ -108,7 +116,7 @@ http_thread_func (uintptr_t ctx) {
fp->remaining = 0;
curl_easy_setopt (curl, CURLOPT_URL, fp->url);
curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1);
- curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, lastfm_curl_write);
+ curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, http_curl_write);
curl_easy_setopt (curl, CURLOPT_WRITEDATA, ctx);
curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, http_err);
curl_easy_setopt (curl, CURLOPT_BUFFERSIZE, BUFFER_SIZE - fp->remaining);
@@ -126,6 +134,7 @@ http_thread_func (uintptr_t ctx) {
static DB_FILE *
http_open (const char *fname) {
+ trace ("http_open\n");
HTTP_FILE *fp = malloc (sizeof (HTTP_FILE));
memset (fp, 0, sizeof (HTTP_FILE));
fp->vfs = &plugin;
@@ -135,6 +144,7 @@ http_open (const char *fname) {
static void
http_close (DB_FILE *stream) {
+ trace ("http_close\n");
assert (stream);
HTTP_FILE *fp = (HTTP_FILE *)stream;
if (fp->tid) {
@@ -148,41 +158,62 @@ http_close (DB_FILE *stream) {
static size_t
http_read (void *ptr, size_t size, size_t nmemb, DB_FILE *stream) {
+ trace ("http_read %d\n", size*nmemb);
assert (stream);
assert (ptr);
- assert (size * nmemb <= BUFFER_SIZE);
+ int sz = size * nmemb;
+// assert (size * nmemb <= BUFFER_SIZE);
HTTP_FILE *fp = (HTTP_FILE *)stream;
if (!fp->tid) {
fp->mutex = deadbeef->mutex_create ();
fp->tid = deadbeef->thread_start (http_thread_func, (uintptr_t)fp);
}
- // wait until data is available
- while (fp->remaining < size * nmemb && fp->status != STATUS_FINISHED) {
- sleep (3000);
- }
- deadbeef->mutex_lock (fp->mutex);
- int sz = size * nmemb;
- int readpos = fp->pos & BUFFER_MASK;
- int part1 = BUFFER_SIZE*2-(fp->pos&BUFFER_MASK);
- part1 = min (part1, sz);
- part1 = min (part1, fp->remaining);
- memcpy (ptr, fp->buffer+readpos, part1);
- fp->remaining -= part1;
- fp->pos += part1;
- sz -= part1;
- if (fp->remaining > 0) {
- int part2 = min (fp->remaining, sz);
- memcpy (((char *)ptr) + part1, fp->buffer, part2);
- fp->remaining -= part2;
- fp->pos += part2;
- sz -= part2;
+ while (fp->status != STATUS_FINISHED && sz > 0)
+ {
+ // wait until data is available
+ while ((fp->remaining == 0 || fp->skipbytes > 0) && fp->status != STATUS_FINISHED) {
+ deadbeef->mutex_lock (fp->mutex);
+ int skip = min (fp->remaining, fp->skipbytes);
+ if (skip > 0) {
+ trace ("skipping %d bytes\n");
+ fp->pos += skip;
+ fp->remaining -= skip;
+ fp->skipbytes -= skip;
+ }
+ deadbeef->mutex_unlock (fp->mutex);
+ usleep (3000);
+ }
+ // trace ("http thread status=%d\n", fp->status);
+ // trace ("buffer remaining: %d\n", fp->remaining);
+ deadbeef->mutex_lock (fp->mutex);
+ int readpos = fp->pos & BUFFER_MASK;
+ int part1 = BUFFER_SIZE*2-(fp->pos&BUFFER_MASK);
+ part1 = min (part1, sz);
+ part1 = min (part1, fp->remaining);
+ memcpy (ptr, fp->buffer+readpos, part1);
+ fp->remaining -= part1;
+ fp->pos += part1;
+ sz -= part1;
+ ptr += part1;
+ if (fp->remaining > 0) {
+ int part2 = min (fp->remaining, sz);
+ memcpy (((char *)ptr) + part1, fp->buffer, part2);
+ fp->remaining -= part2;
+ fp->pos += part2;
+ sz -= part2;
+ ptr += part2;
+ }
+ deadbeef->mutex_unlock (fp->mutex);
}
- deadbeef->mutex_unlock (fp->mutex);
+// if (size * nmemb == 1) {
+// trace ("%02x\n", (unsigned int)*((uint8_t*)ptr));
+// }
return size * nmemb - sz;
}
static int
http_seek (DB_FILE *stream, long offset, int whence) {
+ trace ("http_seek %x %d\n", offset, whence);
assert (stream);
HTTP_FILE *fp = (HTTP_FILE *)stream;
if (!fp->tid) {
@@ -194,8 +225,34 @@ http_seek (DB_FILE *stream, long offset, int whence) {
return -1;
}
}
+ deadbeef->mutex_lock (fp->mutex);
+ if (whence == SEEK_CUR) {
+ whence = SEEK_SET;
+ offset = fp->pos + offset;
+ }
+ if (whence == SEEK_SET) {
+ if (fp->pos == offset) {
+ fp->skipbytes = 0;
+ deadbeef->mutex_unlock (fp->mutex);
+ return 0;
+ }
+ else if (fp->pos < offset) {
+ fp->skipbytes = offset - fp->pos;
+ trace ("will skip %d bytes\n", fp->skipbytes);
+ deadbeef->mutex_unlock (fp->mutex);
+ return 0;
+ }
+ else if (fp->pos-BUFFER_SIZE < offset) {
+ fp->skipbytes = 0;
+ fp->remaining += fp->pos - offset;
+ fp->pos = offset;
+ deadbeef->mutex_unlock (fp->mutex);
+ return 0;
+ }
+ }
// FIXME: can do some limited seeking
- trace ("vfs_curl: seeking not implemented\n");
+ trace ("vfs_curl: can't seek backwards (requested %d->%d)\n", fp->pos, offset);
+ deadbeef->mutex_unlock (fp->mutex);
return -1;
}
@@ -203,11 +260,12 @@ static long
http_tell (DB_FILE *stream) {
assert (stream);
HTTP_FILE *fp = (HTTP_FILE *)stream;
- return fp->pos;
+ return fp->pos + fp->skipbytes;
}
static void
http_rewind (DB_FILE *stream) {
+ trace ("http_rewind\n");
assert (stream);
HTTP_FILE *fp = (HTTP_FILE *)stream;
if (fp->tid) {