summaryrefslogtreecommitdiffstats
path: root/stream
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2018-02-21 17:02:18 +0100
committerKevin Mitchell <kevmitch@gmail.com>2018-02-21 22:57:39 -0800
commitfc76d41194813754fb687189a312f564c941e5fa (patch)
tree3e4f93a4fc3c02960120ea92e366c32bd6184d57 /stream
parent4527409c8d968564de53e4dcf4021ff3ae2843b5 (diff)
downloadmpv-fc76d41194813754fb687189a312f564c941e5fa.tar.bz2
mpv-fc76d41194813754fb687189a312f564c941e5fa.tar.xz
stream_file: add mode for reading appended files
Do this because retrying reading on higher levels (like the demuxer) usually causes tons of problems. A hack like this is simpler and could allow to remove some of the higher level retry behavior. This works by trying to detect whether the file is appended. If we reach EOF, check if the file size changed compared to the initial value. If it did, it means the file was appended at least once, and we set the p->appending flag. If that flag is set, we simply retry reading more data every time we encounter EOF. The only way to do this is polling, and we poll for at most 10 times, after waiting for 200ms every time.
Diffstat (limited to 'stream')
-rw-r--r--stream/stream_file.c55
1 files changed, 48 insertions, 7 deletions
diff --git a/stream/stream_file.c b/stream/stream_file.c
index d12d0d20b1..66c2a1a4c1 100644
--- a/stream/stream_file.c
+++ b/stream/stream_file.c
@@ -61,11 +61,27 @@ struct priv {
int fd;
bool close;
bool use_poll;
+ bool regular_file;
+ bool appending;
+ int64_t orig_size;
};
+// Total timeout = RETRY_TIMEOUT * MAX_RETRIES
+#define RETRY_TIMEOUT 0.2
+#define MAX_RETRIES 10
+
+static int64_t get_size(stream_t *s)
+{
+ struct priv *p = s->priv;
+ off_t size = lseek(p->fd, 0, SEEK_END);
+ lseek(p->fd, s->pos, SEEK_SET);
+ return size == (off_t)-1 ? -1 : size;
+}
+
static int fill_buffer(stream_t *s, char *buffer, int max_len)
{
struct priv *p = s->priv;
+
#ifndef __MINGW32__
if (p->use_poll) {
int c = s->cancel ? mp_cancel_get_fd(s->cancel) : -1;
@@ -78,8 +94,28 @@ static int fill_buffer(stream_t *s, char *buffer, int max_len)
return -1;
}
#endif
- int r = read(p->fd, buffer, max_len);
- return (r <= 0) ? -1 : r;
+
+ for (int retries = 0; retries < MAX_RETRIES; retries++) {
+ int r = read(p->fd, buffer, max_len);
+ if (r > 0)
+ return r;
+
+ // Try to detect and handle files being appended during playback.
+ int64_t size = get_size(s);
+ if (p->regular_file && size > p->orig_size && !p->appending) {
+ MP_WARN(s, "File is apparently being appended to, will keep "
+ "retrying with timeouts.\n");
+ p->appending = true;
+ }
+
+ if (!p->appending || p->use_poll)
+ break;
+
+ if (mp_cancel_wait(s->cancel, RETRY_TIMEOUT))
+ break;
+ }
+
+ return 0;
}
static int write_buffer(stream_t *s, char *buffer, int len)
@@ -105,12 +141,10 @@ static int seek(stream_t *s, int64_t newpos)
static int control(stream_t *s, int cmd, void *arg)
{
- struct priv *p = s->priv;
switch (cmd) {
case STREAM_CTRL_GET_SIZE: {
- off_t size = lseek(p->fd, 0, SEEK_END);
- lseek(p->fd, s->pos, SEEK_SET);
- if (size != (off_t)-1) {
+ int64_t size = get_size(s);
+ if (size >= 0) {
*(int64_t *)arg = size;
return 1;
}
@@ -265,6 +299,9 @@ static int open_f(stream_t *stream)
p->fd = 1;
}
} else {
+ if (bstr_startswith0(bstr0(stream->url), "appending://"))
+ p->appending = true;
+
mode_t openmode = S_IRUSR | S_IWUSR;
#ifndef __MINGW32__
openmode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
@@ -289,6 +326,7 @@ static int open_f(stream_t *stream)
#ifndef __MINGW32__
if (S_ISREG(st.st_mode)) {
p->use_poll = false;
+ p->regular_file = true;
// O_NONBLOCK has weird semantics on file locks; remove it.
int val = fcntl(p->fd, F_GETFL) & ~(unsigned)O_NONBLOCK;
fcntl(p->fd, F_SETFL, val);
@@ -319,13 +357,16 @@ static int open_f(stream_t *stream)
if (check_stream_network(p->fd))
stream->streaming = true;
+ p->orig_size = get_size(stream);
+
return STREAM_OK;
}
const stream_info_t stream_info_file = {
.name = "file",
.open = open_f,
- .protocols = (const char*const[]){ "file", "", "fd", "fdclose", NULL },
+ .protocols = (const char*const[]){ "file", "", "fd", "fdclose",
+ "appending", NULL },
.can_write = true,
.is_safe = true,
};