cache: use threads instead of fork()

Basically rewrite all the code supporting the cache (i.e. anything other
than the ringbuffer logic). The underlying design is untouched.

Note that the old cache2.c (on which this code is based) already had a
threading implementation. This was mostly unused on Linux, and had some
problems, such as using shared volatile variables for communication and
uninterruptible timeouts, instead of using locks for synchronization.

This commit does use proper locking, while still retaining the way the
old cache worked. It's basically a big refactor.

Simplify the code too. Since we don't need to copy stream ctrl args
anymore (we're always guaranteed a shared address space now), lots of
annoying code just goes away. Likewise, we don't need to care about
sector sizes. The cache uses the high-level stream API to read from
other streams, and sector sizes are handled transparently.
This commit is contained in:
wm4 2013-05-25 15:03:30 +02:00
parent 4abec2f7b2
commit 236577af09
6 changed files with 444 additions and 572 deletions

View File

@ -287,12 +287,15 @@
Adjust the brightness of the video signal (default: 0). Not supported by
all video output drivers.
--cache=<kBytes>
Enable caching of the input stream (if not already enabled) and set the
size of the cache in kilobytes. Caching is enabled by default (with a
default cache size) for network streams. May be useful when playing files
from slow media, but can also have negative effects, especially with file
formats that require a lot of seeking, such as mp4. See also ``--no-cache``.
--cache=<kBytes|no|auto>
Set the size of the cache in kilobytes, disable it with ``no``, or
automatically enable it if needed with ``auto`` (default: ``auto``).
With ``auto``, the cache will usually be enabled for network streams,
using a default size.
May be useful when playing files from slow media, but can also have
negative effects, especially with file formats that require a lot of
seeking, such as mp4.
Note that half the cache size will be used to allow fast seeking back. This
is also the reason why a full cache is usually reported as 50% full. The
@ -319,6 +322,12 @@
filled to this position rather than performing a stream seek (default:
50).
This matters for small forward seeks. With slow streams (especially http
streams) there is a tradeoff between skipping the data between current
position and seek destination, or performing an actual seek. Depending
on the situation, either of these might be slower than the other method.
This option allows control over this.
--cdda=<option1:option2>
This option can be used to tune the CD Audio reading feature of mpv.

9
configure vendored
View File

@ -493,7 +493,6 @@ libavdevice=auto
_stream_cache=yes
_priority=no
def_dos_paths="#define HAVE_DOS_PATHS 0"
def_stream_cache="#define CONFIG_STREAM_CACHE 1"
def_priority="#undef CONFIG_PRIORITY"
need_shmem=yes
_build_man=auto
@ -1452,9 +1451,11 @@ else
fi
echores "$_pthreads"
if cygwin || mingw32 ; then
_stream_cache=no
def_stream_cache="#undef CONFIG_STREAM_CACHE"
_stream_cache="$_pthreads"
if test "$_stream_cache" = yes ; then
def_stream_cache='#define CONFIG_STREAM_CACHE'
else
def_stream_cache='#undef CONFIG_STREAM_CACHE'
fi
echocheck "rpath"

View File

@ -324,7 +324,8 @@ const m_option_t mp_opts[] = {
#ifdef CONFIG_STREAM_CACHE
OPT_CHOICE_OR_INT("cache", stream_cache_size, 0, 32, 0x7fffffff,
({"no", -1}),
({"no", 0},
{"auto", -1}),
OPTDEF_INT(-1)),
OPT_FLOATRANGE("cache-min", stream_cache_min_percent, 0, 0, 99),
OPT_FLOATRANGE("cache-seek-min", stream_cache_seek_min_percent, 0, 0, 99),

File diff suppressed because it is too large Load Diff

View File

@ -138,6 +138,7 @@ static const stream_info_t *const auto_open_streams[] = {
};
static stream_t *new_stream(void);
static int stream_seek_unbuffered(stream_t *s, int64_t newpos);
static stream_t *open_stream_plugin(const stream_info_t *sinfo,
const char *filename,
@ -187,6 +188,9 @@ static stream_t *open_stream_plugin(const stream_info_t *sinfo,
return NULL;
}
if (!s->read_chunk)
s->read_chunk = 4 * (s->sector_size ? s->sector_size : STREAM_BUFFER_SIZE);
if (s->streaming && !s->cache_size) {
// Set default cache size to use if user does not specify it.
s->cache_size = 320;
@ -337,10 +341,10 @@ void stream_set_capture_file(stream_t *s, const char *filename)
}
}
void stream_capture_write(stream_t *s)
static void stream_capture_write(stream_t *s, void *buf, size_t len)
{
if (s->capture_file) {
if (fwrite(s->buffer, s->buf_len, 1, s->capture_file) < 1) {
if (s->capture_file && len > 0) {
if (fwrite(buf, len, 1, s->capture_file) < 1) {
mp_tmsg(MSGT_GLOBAL, MSGL_ERR, "Error writing capture file: %s\n",
strerror(errno));
stream_set_capture_file(s, NULL);
@ -352,7 +356,7 @@ void stream_capture_write(stream_t *s)
// s->buffer, but into buf[0..len] instead.
// Returns < 0 on error, 0 on EOF, and length of bytes read on success.
// Partial reads are possible, even if EOF is not reached.
int stream_read_unbuffered(stream_t *s, void *buf, int len)
static int stream_read_unbuffered(stream_t *s, void *buf, int len)
{
int orig_len = len;
s->buf_pos = s->buf_len = 0;
@ -397,6 +401,7 @@ eof_out:
// This e.g. avoids issues with eof getting stuck when lavf seeks in MPEG-TS
s->eof = 0;
s->pos += len;
stream_capture_write(s, buf, len);
return len;
}
@ -427,8 +432,6 @@ int stream_fill_buffer(stream_t *s)
return 0;
s->buf_pos = 0;
s->buf_len = len;
// printf("[%d]",len);fflush(stdout);
stream_capture_write(s);
return len;
}
@ -480,7 +483,7 @@ int stream_write_buffer(stream_t *s, unsigned char *buf, int len)
}
// Seek function bypassing the local stream buffer.
int stream_seek_unbuffered(stream_t *s, int64_t newpos)
static int stream_seek_unbuffered(stream_t *s, int64_t newpos)
{
if (newpos == 0 || newpos != s->pos) {
switch (s->type) {
@ -720,10 +723,16 @@ int stream_enable_cache_percent(stream_t **stream, int64_t stream_cache_size,
float stream_cache_min_percent,
float stream_cache_seek_min_percent)
{
return stream_enable_cache(stream, stream_cache_size * 1024,
stream_cache_size * 1024 *
if (stream_cache_size == -1)
stream_cache_size = (*stream)->cache_size;
stream_cache_size = stream_cache_size * 1024; // input is in KiB
return stream_enable_cache(stream, stream_cache_size,
stream_cache_size *
(stream_cache_min_percent / 100.0),
stream_cache_size * 1024 *
stream_cache_size *
(stream_cache_seek_min_percent / 100.0));
}
@ -756,7 +765,6 @@ int stream_enable_cache(stream_t **stream, int64_t size, int64_t min,
cache->opts = orig->opts;
cache->sector_size = orig->sector_size;
cache->read_chunk = orig->read_chunk;
cache->cache_size = orig->cache_size;
cache->start_pos = orig->start_pos;
cache->end_pos = orig->end_pos;

View File

@ -174,7 +174,7 @@ typedef struct stream {
int uncached_type; // like (uncached_stream ? uncached_stream->type : type)
int flags; // MP_STREAM_SEEK_* or'ed flags
int sector_size; // sector size (seek will be aligned on this size if non 0)
int read_chunk; // maximum amount of data to read at once to limit latency (0 for default)
int read_chunk; // maximum amount of data to read at once to limit latency
unsigned int buf_pos, buf_len;
int64_t pos, start_pos, end_pos;
int eof;
@ -205,7 +205,6 @@ int stream_fill_buffer(stream_t *s);
void stream_unread_buffer(stream_t *s, void *buffer, size_t buffer_size);
void stream_set_capture_file(stream_t *s, const char *filename);
void stream_capture_write(stream_t *s);
int stream_enable_cache_percent(stream_t **stream, int64_t stream_cache_size,
float stream_cache_min_percent,
@ -330,9 +329,6 @@ void stream_set_interrupt_callback(int (*cb)(struct input_ctx *, int),
/// wait for time milliseconds
int stream_check_interrupt(int time);
int stream_read_unbuffered(stream_t *s, void *buf, int len);
int stream_seek_unbuffered(stream_t *s, int64_t newpos);
bool stream_manages_timeline(stream_t *s);
extern int dvd_title;