summaryrefslogtreecommitdiffstats
path: root/stream
diff options
context:
space:
mode:
Diffstat (limited to 'stream')
-rw-r--r--stream/cache.c26
-rw-r--r--stream/stream.c84
-rw-r--r--stream/stream_cdda.c2
-rw-r--r--stream/stream_memory.c37
4 files changed, 100 insertions, 49 deletions
diff --git a/stream/cache.c b/stream/cache.c
index f8304df8b9..4765ddb23a 100644
--- a/stream/cache.c
+++ b/stream/cache.c
@@ -159,11 +159,11 @@ static void cache_drop_contents(struct priv *s)
static void update_speed(struct priv *s)
{
int64_t now = mp_time_us();
- s->speed = 0;
- if (s->speed_start && s->speed_start < now)
+ if (s->speed_start + 1000000 <= now) {
s->speed = s->speed_amount * 1e6 / (now - s->speed_start);
- s->speed_amount = 0;
- s->speed_start = now;
+ s->speed_amount = 0;
+ s->speed_start = now;
+ }
}
// Copy at most dst_size from the cache at the given absolute file position pos.
@@ -232,11 +232,6 @@ static void cache_fill(struct priv *s)
if (mp_cancel_test(s->cache->cancel))
goto done;
- if (!s->speed_start) {
- s->speed_start = mp_time_us();
- s->speed_amount = 0;
- }
-
// number of buffer bytes which should be preserved in backwards direction
int64_t back = MPCLAMP(read - s->min_filepos, 0, s->back_size);
@@ -300,20 +295,12 @@ done: ;
s->eof = len <= 0;
if (!prev_eof && s->eof) {
s->eof_pos = stream_tell(s->stream);
- s->speed_start = 0;
MP_VERBOSE(s, "EOF reached.\n");
}
s->idle = s->eof || !read_attempted;
s->reads++;
- if (s->idle) {
- update_speed(s);
- s->speed_start = 0;
- }
-
- int64_t now = mp_time_us();
- if (s->speed_start && s->speed_start + 1000000 <= now)
- update_speed(s);
+ update_speed(s);
pthread_cond_signal(&s->wakeup);
}
@@ -366,7 +353,6 @@ static int resize_cache(struct priv *s, int64_t size)
s->buffer_size = buffer_size;
s->buffer = buffer;
s->idle = false;
- s->speed_start = 0;
s->eof = false;
//make sure that we won't wait from cache_fill
@@ -661,6 +647,8 @@ int stream_cache_init(stream_t *cache, stream_t *stream,
cache_drop_contents(s);
+ s->speed_start = mp_time_us();
+
s->seek_limit = opts->seek_min * 1024ULL;
s->back_size = opts->back_buffer * 1024ULL;
diff --git a/stream/stream.c b/stream/stream.c
index 1048a8006d..846765f326 100644
--- a/stream/stream.c
+++ b/stream/stream.c
@@ -952,20 +952,15 @@ struct bstr stream_read_file(const char *filename, void *talloc_ctx,
return res;
}
+#ifndef __MINGW32__
struct mp_cancel {
atomic_bool triggered;
-#ifdef __MINGW32__
- HANDLE event;
-#endif
int wakeup_pipe[2];
};
static void cancel_destroy(void *p)
{
struct mp_cancel *c = p;
-#ifdef __MINGW32__
- CloseHandle(c->event);
-#endif
close(c->wakeup_pipe[0]);
close(c->wakeup_pipe[1]);
}
@@ -975,9 +970,6 @@ struct mp_cancel *mp_cancel_new(void *talloc_ctx)
struct mp_cancel *c = talloc_ptrtype(talloc_ctx, c);
talloc_set_destructor(c, cancel_destroy);
*c = (struct mp_cancel){.triggered = ATOMIC_VAR_INIT(false)};
-#ifdef __MINGW32__
- c->event = CreateEventW(NULL, TRUE, FALSE, NULL);
-#endif
mp_make_wakeup_pipe(c->wakeup_pipe);
return c;
}
@@ -986,19 +978,13 @@ struct mp_cancel *mp_cancel_new(void *talloc_ctx)
void mp_cancel_trigger(struct mp_cancel *c)
{
atomic_store(&c->triggered, true);
-#ifdef __MINGW32__
- SetEvent(c->event);
-#endif
- write(c->wakeup_pipe[1], &(char){0}, 1);
+ (void)write(c->wakeup_pipe[1], &(char){0}, 1);
}
// Restore original state. (Allows reusing a mp_cancel.)
void mp_cancel_reset(struct mp_cancel *c)
{
atomic_store(&c->triggered, false);
-#ifdef __MINGW32__
- ResetEvent(c->event);
-#endif
// Flush it fully.
while (1) {
int r = read(c->wakeup_pipe[0], &(char[256]){0}, 256);
@@ -1018,35 +1004,77 @@ bool mp_cancel_test(struct mp_cancel *c)
// Wait until the even is signaled. If the timeout (in seconds) expires, return
// false. timeout==0 polls, timeout<0 waits forever.
-#ifdef __MINGW32__
bool mp_cancel_wait(struct mp_cancel *c, double timeout)
{
- return WaitForSingleObject(c->event, timeout < 0 ? INFINITE : timeout * 1000)
- == WAIT_OBJECT_0;
+ struct pollfd fd = { .fd = c->wakeup_pipe[0], .events = POLLIN };
+ poll(&fd, 1, timeout * 1000);
+ return fd.revents & POLLIN;
}
+
+// The FD becomes readable if mp_cancel_test() would return true.
+// Don't actually read from it, just use it for poll().
+int mp_cancel_get_fd(struct mp_cancel *c)
+{
+ return c->wakeup_pipe[0];
+}
+
#else
+
+struct mp_cancel {
+ atomic_bool triggered;
+ HANDLE event;
+};
+
+static void cancel_destroy(void *p)
+{
+ struct mp_cancel *c = p;
+ CloseHandle(c->event);
+}
+
+struct mp_cancel *mp_cancel_new(void *talloc_ctx)
+{
+ struct mp_cancel *c = talloc_ptrtype(talloc_ctx, c);
+ talloc_set_destructor(c, cancel_destroy);
+ *c = (struct mp_cancel){.triggered = ATOMIC_VAR_INIT(false)};
+ c->event = CreateEventW(NULL, TRUE, FALSE, NULL);
+ return c;
+}
+
+void mp_cancel_trigger(struct mp_cancel *c)
+{
+ atomic_store(&c->triggered, true);
+ SetEvent(c->event);
+}
+
+void mp_cancel_reset(struct mp_cancel *c)
+{
+ atomic_store(&c->triggered, false);
+ ResetEvent(c->event);
+}
+
+bool mp_cancel_test(struct mp_cancel *c)
+{
+ return c ? atomic_load_explicit(&c->triggered, memory_order_relaxed) : false;
+}
+
bool mp_cancel_wait(struct mp_cancel *c, double timeout)
{
- struct pollfd fd = { .fd = c->wakeup_pipe[0], .events = POLLIN };
- poll(&fd, 1, timeout * 1000);
- return fd.revents & POLLIN;
+ return WaitForSingleObject(c->event, timeout < 0 ? INFINITE : timeout * 1000)
+ == WAIT_OBJECT_0;
}
-#endif
-#ifdef __MINGW32__
void *mp_cancel_get_event(struct mp_cancel *c)
{
return c->event;
}
-#endif
-// The FD becomes readable if mp_cancel_test() would return true.
-// Don't actually read from it, just use it for poll().
int mp_cancel_get_fd(struct mp_cancel *c)
{
- return c->wakeup_pipe[0];
+ return -1;
}
+#endif
+
char **stream_get_proto_list(void)
{
char **list = NULL;
diff --git a/stream/stream_cdda.c b/stream/stream_cdda.c
index 8fadf3452a..1d96ea6029 100644
--- a/stream/stream_cdda.c
+++ b/stream/stream_cdda.c
@@ -384,6 +384,8 @@ static int open_cdda(stream_t *st)
st->control = control;
st->close = close_cdda;
+ st->streaming = true;
+
st->type = STREAMTYPE_CDDA;
st->demuxer = "+disc";
diff --git a/stream/stream_memory.c b/stream/stream_memory.c
index 4bcb860c49..84947b5aeb 100644
--- a/stream/stream_memory.c
+++ b/stream/stream_memory.c
@@ -55,6 +55,32 @@ static int control(stream_t *s, int cmd, void *arg)
return STREAM_UNSUPPORTED;
}
+static int h_to_i(unsigned char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+static bool bstr_to_hex_inplace(bstr *h)
+{
+ if (h->len % 2)
+ return false;
+ for (int n = 0; n < h->len / 2; n++) {
+ int hi = h_to_i(h->start[n * 2 + 0]);
+ int lo = h_to_i(h->start[n * 2 + 1]);
+ if (hi < 0 || lo < 0)
+ return false;
+ h->start[n] = (hi << 4) | lo;
+ }
+ h->len /= 2;
+ return true;
+}
+
static int open_f(stream_t *stream)
{
stream->fill_buffer = fill_buffer;
@@ -68,14 +94,21 @@ static int open_f(stream_t *stream)
// Initial data
bstr data = bstr0(stream->url);
- bstr_eatstart0(&data, "memory://");
+ bool use_hex = bstr_eatstart0(&data, "hex://");
+ if (!use_hex)
+ bstr_eatstart0(&data, "memory://");
stream_control(stream, STREAM_CTRL_SET_CONTENTS, &data);
+ if (use_hex && !bstr_to_hex_inplace(&p->data)) {
+ MP_FATAL(stream, "Invalid data.\n");
+ return STREAM_ERROR;
+ }
+
return STREAM_OK;
}
const stream_info_t stream_info_memory = {
.name = "memory",
.open = open_f,
- .protocols = (const char*const[]){ "memory", NULL },
+ .protocols = (const char*const[]){ "memory", "hex", NULL },
};