2010-01-30 23:26:47 +01:00
|
|
|
/*
|
|
|
|
* This file is part of MPlayer.
|
|
|
|
*
|
|
|
|
* MPlayer is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* MPlayer is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
2001-02-24 21:28:24 +01:00
|
|
|
|
2001-08-01 11:14:02 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
2001-02-24 21:28:24 +01:00
|
|
|
|
2001-08-01 01:18:16 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2003-04-02 18:52:00 +02:00
|
|
|
#ifndef __MINGW32__
|
2001-04-22 18:56:20 +02:00
|
|
|
#include <sys/ioctl.h>
|
2002-07-26 06:04:51 +02:00
|
|
|
#include <sys/wait.h>
|
2003-04-02 18:52:00 +02:00
|
|
|
#endif
|
2001-08-01 01:18:16 +02:00
|
|
|
#include <fcntl.h>
|
2003-04-02 18:25:07 +02:00
|
|
|
#include <strings.h>
|
2011-02-10 22:25:38 +01:00
|
|
|
#include <assert.h>
|
2001-04-22 18:56:20 +02:00
|
|
|
|
2012-02-01 19:01:16 +01:00
|
|
|
#include <libavutil/common.h>
|
2014-01-19 20:21:11 +01:00
|
|
|
#include "compat/mpbswap.h"
|
2012-02-01 19:01:16 +01:00
|
|
|
|
2011-02-25 17:10:00 +01:00
|
|
|
#include "talloc.h"
|
|
|
|
|
2001-08-01 11:14:02 +02:00
|
|
|
#include "config.h"
|
2003-06-11 18:48:09 +02:00
|
|
|
|
2013-12-17 02:39:45 +01:00
|
|
|
#include "common/common.h"
|
2013-12-21 20:36:45 +01:00
|
|
|
#include "common/global.h"
|
2013-12-17 02:39:45 +01:00
|
|
|
#include "bstr/bstr.h"
|
|
|
|
#include "common/msg.h"
|
2013-12-17 02:02:25 +01:00
|
|
|
#include "options/path.h"
|
2010-05-30 15:39:41 +02:00
|
|
|
#include "osdep/timer.h"
|
2001-04-22 18:56:20 +02:00
|
|
|
#include "stream.h"
|
2001-02-24 21:28:24 +01:00
|
|
|
|
2013-12-17 02:02:25 +01:00
|
|
|
#include "options/m_option.h"
|
|
|
|
#include "options/m_config.h"
|
2003-04-02 18:25:07 +02:00
|
|
|
|
stream: add stream_unread_buffer()
demux_lavf probes up to 2 MB of data in the worst case. When the ffmpeg
demuxer is actually opened, the stream is seeked back to 0, and the
previously read data is thrown away.
This wasn't a problem for playback of local files, but it's less than
ideal for playing from slow media (like web streams), and breaks
completely if the media is not seekable (pipes, some web streams).
This new function is intended to allow fixing this. demux_lavf will use
it to put the read probe data back into the buffer.
The simplest way of implementing this function is by making it
transparently extend the normal stream buffer. This makes sure no
existing code is broken by new weird special cases. For simplicity
and to avoid possible performance loss due to extra dereferencing
when accessing the buffer, we just extend the static buffer from
8 KB to 2 MB. Normally, most of these 2 MB will stay uncommitted, so
there's no associated waste of memory. If demux_lavf really reads all
2 MB, the memory will be committed and stay unused, though.
2013-05-24 23:20:09 +02:00
|
|
|
// Includes additional padding in case sizes get rounded up by sector size.
|
|
|
|
#define TOTAL_BUFFER_SIZE (STREAM_MAX_BUFFER_SIZE + STREAM_MAX_SECTOR_SIZE)
|
|
|
|
|
2012-10-13 17:09:35 +02:00
|
|
|
/// We keep these 2 for the gui atm, but they will be removed.
|
2013-01-24 17:43:07 +01:00
|
|
|
char *cdrom_device = NULL;
|
|
|
|
char *dvd_device = NULL;
|
|
|
|
int dvd_title = 0;
|
2012-10-13 17:09:35 +02:00
|
|
|
|
2008-04-30 06:15:52 +02:00
|
|
|
struct input_ctx;
|
|
|
|
static int (*stream_check_interrupt_cb)(struct input_ctx *ctx, int time);
|
|
|
|
static struct input_ctx *stream_check_interrupt_ctx;
|
2008-04-09 02:36:28 +02:00
|
|
|
|
2007-12-02 14:22:53 +01:00
|
|
|
extern const stream_info_t stream_info_vcd;
|
|
|
|
extern const stream_info_t stream_info_cdda;
|
|
|
|
extern const stream_info_t stream_info_dvb;
|
|
|
|
extern const stream_info_t stream_info_tv;
|
|
|
|
extern const stream_info_t stream_info_pvr;
|
|
|
|
extern const stream_info_t stream_info_smb;
|
|
|
|
extern const stream_info_t stream_info_null;
|
2013-06-27 17:21:46 +02:00
|
|
|
extern const stream_info_t stream_info_memory;
|
2007-12-02 14:22:53 +01:00
|
|
|
extern const stream_info_t stream_info_mf;
|
2009-11-17 17:09:17 +01:00
|
|
|
extern const stream_info_t stream_info_ffmpeg;
|
demux_lavf: add support for libavdevice
libavdevice supports various "special" video and audio inputs, such
as screen-capture or libavfilter filter graphs.
libavdevice inputs are implemented as demuxers. They don't use the
custom stream callbacks (in AVFormatContext.pb). Instead, input
parameters are passed as filename. This means the mpv stream layer has
to be disabled. Do this by adding the pseudo stream handler avdevice://,
whose only purpose is passing the filename to demux_lavf, without
actually doing anything.
Change the logic how the filename is passed to libavformat. Remove
handling of the filename from demux_open_lavf() and move it to
lavf_check_file(). (This also fixes a possible bug when skipping the
"lavf://" prefix.)
libavdevice now can be invoked by specifying demuxer and args as in:
mpv avdevice://demuxer:args
The args are passed as filename to libavformat. When using libavdevice
demuxers, their actual meaning is highly implementation specific. They
don't refer to actual filenames.
Note:
libavdevice is disabled by default. There is one problem: libavdevice
pulls in libavfilter, which in turn causes symbol clashes with mpv
internals. The problem is that libavfilter includes a mplayer filter
bridge, which is used to interface with a set of nearly unmodified
mplayer filters copied into libavfilter. This filter bridge uses the
same symbol names as mplayer/mpv's filter chain, which results in symbol
clashes at link-time.
This can be prevented by building ffmpeg with --disable-filter=mp, but
unfortunately this is not the default.
This means linking to libavdevice (which in turn forces linking with
libavfilter by default) must be disabled. We try doing this by compiling
a test file that defines one of the clashing symbols (vf_mpi_clear).
To enable libavdevice input, ffmpeg should be built with the options:
--disable-filter=mp
and mpv with:
--enable-libavdevice
Originally, I tried to auto-detect it. But the resulting complications
in configure did't seem worth the trouble.
2012-11-30 18:41:04 +01:00
|
|
|
extern const stream_info_t stream_info_avdevice;
|
2007-12-02 14:22:53 +01:00
|
|
|
extern const stream_info_t stream_info_file;
|
|
|
|
extern const stream_info_t stream_info_ifo;
|
|
|
|
extern const stream_info_t stream_info_dvd;
|
Add prelimimary (basic, possibly broken) dvdnav support
This readds a more or less completely new dvdnav implementation, though
it's based on the code from before commit 41fbcee. Note that this is
rather basic, and might be broken or not quite usable in many cases.
Most importantly, navigation highlights are not correctly implemented.
This would require changes in the FFmpeg dvdsub decoder (to apply a
different internal CLUT), so supporting it is not really possible right
now. And in fact, I don't think I ever want to support it, because it's
a very small gain for a lot of work. Instead, mpv will display fake
highlights, which are an approximate bounding box around the real
highlights.
Some things like mouse input or switching audio/subtitles stream using
the dvdnav VM are not supported.
Might be quite fragile on transitions: if dvdnav initiates a transition,
and doesn't give us enough mpeg data to initialize video playback, the
player will just quit.
This is added only because some users seem to want it. I don't intend to
make mpv a good DVD player, so the very basic minimum will have to do.
How about you just convert your DVD to proper video files?
2013-12-12 01:44:28 +01:00
|
|
|
extern const stream_info_t stream_info_dvdnav;
|
2010-07-05 19:04:46 +02:00
|
|
|
extern const stream_info_t stream_info_bluray;
|
2014-03-28 16:00:02 +01:00
|
|
|
extern const stream_info_t stream_info_bdnav;
|
2013-08-25 22:58:29 +02:00
|
|
|
extern const stream_info_t stream_info_rar_filter;
|
|
|
|
extern const stream_info_t stream_info_rar_entry;
|
2013-11-19 22:26:35 +01:00
|
|
|
extern const stream_info_t stream_info_edl;
|
2003-04-02 18:25:07 +02:00
|
|
|
|
2013-08-25 22:50:16 +02:00
|
|
|
static const stream_info_t *const stream_list[] = {
|
2013-07-16 13:28:28 +02:00
|
|
|
#if HAVE_VCD
|
2013-01-24 17:43:07 +01:00
|
|
|
&stream_info_vcd,
|
2003-04-09 09:31:11 +02:00
|
|
|
#endif
|
2013-07-16 13:28:28 +02:00
|
|
|
#if HAVE_CDDA
|
2013-01-24 17:43:07 +01:00
|
|
|
&stream_info_cdda,
|
2003-04-06 18:36:17 +02:00
|
|
|
#endif
|
2013-09-22 02:40:29 +02:00
|
|
|
&stream_info_ffmpeg,
|
2013-01-24 17:43:07 +01:00
|
|
|
&stream_info_avdevice,
|
2013-07-16 13:28:28 +02:00
|
|
|
#if HAVE_DVBIN
|
2013-01-24 17:43:07 +01:00
|
|
|
&stream_info_dvb,
|
2003-08-11 02:02:46 +02:00
|
|
|
#endif
|
2013-07-16 13:28:28 +02:00
|
|
|
#if HAVE_TV
|
2013-01-24 17:43:07 +01:00
|
|
|
&stream_info_tv,
|
2006-07-31 20:36:29 +02:00
|
|
|
#endif
|
2013-07-16 13:28:28 +02:00
|
|
|
#if HAVE_PVR
|
2013-01-24 17:43:07 +01:00
|
|
|
&stream_info_pvr,
|
2006-07-10 23:32:19 +02:00
|
|
|
#endif
|
2013-07-16 13:28:28 +02:00
|
|
|
#if HAVE_LIBSMBCLIENT
|
2013-01-24 17:43:07 +01:00
|
|
|
&stream_info_smb,
|
2003-08-15 21:13:23 +02:00
|
|
|
#endif
|
2013-07-16 13:28:28 +02:00
|
|
|
#if HAVE_DVDREAD
|
2013-01-24 17:43:07 +01:00
|
|
|
&stream_info_ifo,
|
|
|
|
&stream_info_dvd,
|
2005-12-14 22:52:41 +01:00
|
|
|
#endif
|
Add prelimimary (basic, possibly broken) dvdnav support
This readds a more or less completely new dvdnav implementation, though
it's based on the code from before commit 41fbcee. Note that this is
rather basic, and might be broken or not quite usable in many cases.
Most importantly, navigation highlights are not correctly implemented.
This would require changes in the FFmpeg dvdsub decoder (to apply a
different internal CLUT), so supporting it is not really possible right
now. And in fact, I don't think I ever want to support it, because it's
a very small gain for a lot of work. Instead, mpv will display fake
highlights, which are an approximate bounding box around the real
highlights.
Some things like mouse input or switching audio/subtitles stream using
the dvdnav VM are not supported.
Might be quite fragile on transitions: if dvdnav initiates a transition,
and doesn't give us enough mpeg data to initialize video playback, the
player will just quit.
This is added only because some users seem to want it. I don't intend to
make mpv a good DVD player, so the very basic minimum will have to do.
How about you just convert your DVD to proper video files?
2013-12-12 01:44:28 +01:00
|
|
|
#if HAVE_DVDNAV
|
|
|
|
&stream_info_dvdnav,
|
|
|
|
#endif
|
2013-07-16 13:28:28 +02:00
|
|
|
#if HAVE_LIBBLURAY
|
2013-01-24 17:43:07 +01:00
|
|
|
&stream_info_bluray,
|
2014-03-28 16:00:02 +01:00
|
|
|
&stream_info_bdnav,
|
2010-07-05 19:04:46 +02:00
|
|
|
#endif
|
2005-05-19 21:50:39 +02:00
|
|
|
|
2013-06-27 17:21:46 +02:00
|
|
|
&stream_info_memory,
|
2013-01-24 17:43:07 +01:00
|
|
|
&stream_info_null,
|
|
|
|
&stream_info_mf,
|
2013-11-19 22:26:35 +01:00
|
|
|
&stream_info_edl,
|
2013-08-25 22:58:29 +02:00
|
|
|
&stream_info_rar_filter,
|
|
|
|
&stream_info_rar_entry,
|
2013-01-24 17:43:07 +01:00
|
|
|
&stream_info_file,
|
|
|
|
NULL
|
2003-04-02 18:25:07 +02:00
|
|
|
};
|
|
|
|
|
2013-05-25 15:03:30 +02:00
|
|
|
static int stream_seek_unbuffered(stream_t *s, int64_t newpos);
|
2013-05-24 17:47:01 +02:00
|
|
|
|
2013-08-02 17:03:30 +02:00
|
|
|
static int from_hex(unsigned char c)
|
|
|
|
{
|
|
|
|
if (c >= 'a' && c <= 'f')
|
|
|
|
return c - 'a' + 10;
|
|
|
|
if (c >= 'A' && c <= 'F')
|
|
|
|
return c - 'A' + 10;
|
|
|
|
if (c >= '0' && c <= '9')
|
|
|
|
return c - '0';
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Replace escape sequences in an URL (or a part of an URL)
|
|
|
|
void mp_url_unescape_inplace(char *buf)
|
|
|
|
{
|
|
|
|
int len = strlen(buf);
|
|
|
|
int o = 0;
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
unsigned char c = buf[i];
|
|
|
|
if (c == '%' && i + 2 < len) { //must have 2 more chars
|
|
|
|
int c1 = from_hex(buf[i + 1]);
|
|
|
|
int c2 = from_hex(buf[i + 2]);
|
|
|
|
if (c1 >= 0 && c2 >= 0) {
|
|
|
|
c = c1 * 16 + c2;
|
|
|
|
i = i + 2; //only skip next 2 chars if valid esc
|
|
|
|
}
|
|
|
|
}
|
|
|
|
buf[o++] = c;
|
|
|
|
}
|
|
|
|
buf[o++] = '\0';
|
|
|
|
}
|
|
|
|
|
2013-08-25 22:58:29 +02:00
|
|
|
// Escape according to http://tools.ietf.org/html/rfc3986#section-2.1
|
|
|
|
// Only unreserved characters are not escaped.
|
|
|
|
// The argument ok (if not NULL) is as follows:
|
|
|
|
// ok[0] != '~': additional characters that are not escaped
|
|
|
|
// ok[0] == '~': do not escape anything but these characters
|
|
|
|
// (can't override the unreserved characters, which are
|
|
|
|
// never escaped, and '%', which is always escaped)
|
|
|
|
char *mp_url_escape(void *talloc_ctx, const char *s, const char *ok)
|
|
|
|
{
|
|
|
|
int len = strlen(s);
|
|
|
|
char *buf = talloc_array(talloc_ctx, char, len * 3 + 1);
|
|
|
|
int o = 0;
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
unsigned char c = s[i];
|
|
|
|
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
|
|
|
(c >= '0' && c <= '9') || strchr("-._~", c) ||
|
|
|
|
(ok && ((ok[0] != '~') == !!strchr(ok, c)) && c != '%'))
|
|
|
|
{
|
|
|
|
buf[o++] = c;
|
|
|
|
} else {
|
|
|
|
const char hex[] = "0123456789ABCDEF";
|
|
|
|
buf[o++] = '%';
|
|
|
|
buf[o++] = hex[c / 16];
|
|
|
|
buf[o++] = hex[c % 16];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
buf[o++] = '\0';
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2013-08-02 17:02:34 +02:00
|
|
|
static const char *find_url_opt(struct stream *s, const char *opt)
|
|
|
|
{
|
stream: fix url_options field, make protocols field not fixed length
The way the url_options field was handled was not entirely sane: it's
actually a flexible array member, so it points to garbage for streams
which do not initialize this member (it just points to the data right
after the struct, which is garbage in theory and practice). This was
not actually a problem, since the field is only used if priv_size is
set (due to how this stuff is used). But it doesn't allow setting
priv_size only, which might be useful in some cases.
Also, make the protocols array not a fixed size array. Most stream
implementations have only 1 protocol prefix, but stream_lavf.c has
over 10 (whitelists ffmpeg protocols). The high size of the fixed
size protocol array wastes space, and it is _still_ annoying to
add new prefixes to stream_lavf (have to bump the maximum length),
so make it arbitrary length.
The two changes (plus some more cosmetic changes) arte conflated into
one, because it was annoying going over all the stream implementations.
2013-08-25 22:49:27 +02:00
|
|
|
for (int n = 0; s->info->url_options && s->info->url_options[n]; n++) {
|
|
|
|
const char *entry = s->info->url_options[n];
|
|
|
|
const char *t = strchr(entry, '=');
|
|
|
|
assert(t);
|
|
|
|
if (strncmp(opt, entry, t - entry) == 0)
|
|
|
|
return t + 1;
|
2013-08-02 17:02:34 +02:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bstr split_next(bstr *s, char end, const char *delim)
|
|
|
|
{
|
|
|
|
int idx = bstrcspn(*s, delim);
|
|
|
|
if (end && (idx >= s->len || s->start[idx] != end))
|
|
|
|
return (bstr){0};
|
|
|
|
bstr r = bstr_splice(*s, 0, idx);
|
|
|
|
*s = bstr_cut(*s, idx + (end ? 1 : 0));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the stream URL, syntax:
|
|
|
|
// proto:// [<username>@]<hostname>[:<port>][/<filename>]
|
|
|
|
// (the proto:// part is already removed from s->path)
|
|
|
|
// This code originates from times when http code used this, but now it's
|
|
|
|
// just relict from other stream implementations reusing this code.
|
|
|
|
static bool parse_url(struct stream *st, struct m_config *config)
|
|
|
|
{
|
|
|
|
bstr s = bstr0(st->path);
|
|
|
|
const char *f_names[4] = {"username", "hostname", "port", "filename"};
|
|
|
|
bstr f[4];
|
|
|
|
f[0] = split_next(&s, '@', "@:/");
|
|
|
|
f[1] = split_next(&s, 0, ":/");
|
|
|
|
f[2] = bstr_eatstart0(&s, ":") ? split_next(&s, 0, "/") : (bstr){0};
|
|
|
|
f[3] = bstr_eatstart0(&s, "/") ? s : (bstr){0};
|
|
|
|
for (int n = 0; n < 4; n++) {
|
|
|
|
if (f[n].len) {
|
|
|
|
const char *opt = find_url_opt(st, f_names[n]);
|
|
|
|
if (!opt) {
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_ERR(st, "Stream type '%s' accepts no '%s' field in URLs.\n",
|
|
|
|
st->info->name, f_names[n]);
|
2013-08-02 17:02:34 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int r = m_config_set_option(config, bstr0(opt), f[n]);
|
|
|
|
if (r < 0) {
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_ERR(st, "Error setting stream option: %s\n",
|
|
|
|
m_option_strerror(r));
|
2013-08-02 17:02:34 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static stream_t *new_stream(void)
|
|
|
|
{
|
|
|
|
stream_t *s = talloc_size(NULL, sizeof(stream_t) + TOTAL_BUFFER_SIZE);
|
|
|
|
memset(s, 0, sizeof(stream_t));
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2013-08-25 22:50:16 +02:00
|
|
|
static const char *match_proto(const char *url, const char *proto)
|
|
|
|
{
|
|
|
|
int l = strlen(proto);
|
|
|
|
if (l > 0) {
|
|
|
|
if (strncasecmp(url, proto, l) == 0 && strncmp("://", url + l, 3) == 0)
|
|
|
|
return url + l + 3;
|
2013-09-04 14:04:35 +02:00
|
|
|
} else if (!mp_is_url(bstr0(url))) {
|
|
|
|
return url; // pure filenames
|
2013-08-25 22:50:16 +02:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int open_internal(const stream_info_t *sinfo, struct stream *underlying,
|
2013-12-21 20:36:45 +01:00
|
|
|
const char *url, int flags, struct mpv_global *global,
|
2013-08-25 22:50:16 +02:00
|
|
|
struct stream **ret)
|
2008-04-23 05:35:36 +02:00
|
|
|
{
|
2013-08-25 22:50:16 +02:00
|
|
|
if (sinfo->stream_filter != !!underlying)
|
|
|
|
return STREAM_NO_MATCH;
|
|
|
|
if (sinfo->stream_filter && (flags & STREAM_NO_FILTERS))
|
|
|
|
return STREAM_NO_MATCH;
|
|
|
|
|
|
|
|
const char *path = NULL;
|
|
|
|
// Stream filters use the original URL, with no protocol matching at all.
|
|
|
|
if (!sinfo->stream_filter) {
|
|
|
|
for (int n = 0; sinfo->protocols && sinfo->protocols[n]; n++) {
|
|
|
|
path = match_proto(url, sinfo->protocols[n]);
|
|
|
|
if (path)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!path)
|
|
|
|
return STREAM_NO_MATCH;
|
|
|
|
}
|
|
|
|
|
2013-08-02 17:02:34 +02:00
|
|
|
stream_t *s = new_stream();
|
2013-12-21 20:36:45 +01:00
|
|
|
s->log = mp_log_new(s, global->log, sinfo->name);
|
2013-08-02 17:02:34 +02:00
|
|
|
s->info = sinfo;
|
2013-12-21 20:36:45 +01:00
|
|
|
s->opts = global->opts;
|
|
|
|
s->global = global;
|
2013-08-02 17:02:34 +02:00
|
|
|
s->url = talloc_strdup(s, url);
|
|
|
|
s->path = talloc_strdup(s, path);
|
2013-08-25 22:50:16 +02:00
|
|
|
s->source = underlying;
|
2013-12-14 01:21:06 +01:00
|
|
|
s->allow_caching = true;
|
2013-01-24 17:43:07 +01:00
|
|
|
|
|
|
|
// Parse options
|
2013-08-02 17:02:34 +02:00
|
|
|
if (sinfo->priv_size) {
|
|
|
|
struct m_obj_desc desc = {
|
|
|
|
.priv_size = sinfo->priv_size,
|
|
|
|
.priv_defaults = sinfo->priv_defaults,
|
|
|
|
.options = sinfo->options,
|
|
|
|
};
|
2013-12-21 20:36:45 +01:00
|
|
|
struct m_config *config = m_config_from_obj_desc(s, s->log, &desc);
|
2013-08-02 17:02:34 +02:00
|
|
|
s->priv = config->optstruct;
|
|
|
|
if (s->info->url_options && !parse_url(s, config)) {
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_ERR(s, "URL parsing failed on url %s\n", url);
|
2013-08-02 17:02:34 +02:00
|
|
|
talloc_free(s);
|
2013-08-25 22:50:16 +02:00
|
|
|
return STREAM_ERROR;
|
2013-01-24 17:43:07 +01:00
|
|
|
}
|
2003-04-02 18:25:07 +02:00
|
|
|
}
|
2013-08-02 17:02:34 +02:00
|
|
|
|
2013-07-07 20:49:15 +02:00
|
|
|
s->flags = 0;
|
2013-08-25 22:50:16 +02:00
|
|
|
s->mode = flags & (STREAM_READ | STREAM_WRITE);
|
|
|
|
int r = sinfo->open(s, s->mode);
|
|
|
|
if (r != STREAM_OK) {
|
2013-01-24 17:43:07 +01:00
|
|
|
talloc_free(s);
|
2013-08-25 22:50:16 +02:00
|
|
|
return r;
|
2013-01-24 17:43:07 +01:00
|
|
|
}
|
2012-11-17 18:12:13 +01:00
|
|
|
|
2013-05-25 15:03:30 +02:00
|
|
|
if (!s->read_chunk)
|
|
|
|
s->read_chunk = 4 * (s->sector_size ? s->sector_size : STREAM_BUFFER_SIZE);
|
|
|
|
|
2013-06-05 02:00:13 +02:00
|
|
|
if (!s->seek)
|
2013-01-24 17:43:07 +01:00
|
|
|
s->flags &= ~MP_STREAM_SEEK;
|
|
|
|
if (s->seek && !(s->flags & MP_STREAM_SEEK))
|
|
|
|
s->flags |= MP_STREAM_SEEK;
|
2009-07-07 01:26:13 +02:00
|
|
|
|
2013-11-03 17:46:36 +01:00
|
|
|
if (!(s->flags & MP_STREAM_SEEK))
|
|
|
|
s->end_pos = 0;
|
2013-08-22 18:21:32 +02:00
|
|
|
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
s->uncached_type = s->type;
|
|
|
|
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_VERBOSE(s, "Opened: [%s] %s\n", sinfo->name, url);
|
2009-07-07 01:26:13 +02:00
|
|
|
|
2013-01-24 17:43:07 +01:00
|
|
|
if (s->mime_type)
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_VERBOSE(s, "Mime-type: '%s'\n", s->mime_type);
|
2012-12-10 01:28:20 +01:00
|
|
|
|
2013-08-25 22:50:16 +02:00
|
|
|
*ret = s;
|
|
|
|
return STREAM_OK;
|
2013-08-02 17:02:34 +02:00
|
|
|
}
|
2003-04-02 18:25:07 +02:00
|
|
|
|
2013-12-21 20:36:45 +01:00
|
|
|
struct stream *stream_create(const char *url, int flags, struct mpv_global *global)
|
2008-04-23 05:35:36 +02:00
|
|
|
{
|
2013-12-21 20:36:45 +01:00
|
|
|
struct mp_log *log = mp_log_new(NULL, global->log, "!stream");
|
2013-08-25 22:50:16 +02:00
|
|
|
struct stream *s = NULL;
|
2013-08-02 17:02:34 +02:00
|
|
|
assert(url);
|
2013-01-24 17:43:07 +01:00
|
|
|
|
2013-08-25 22:50:16 +02:00
|
|
|
// Open stream proper
|
|
|
|
for (int i = 0; stream_list[i]; i++) {
|
2013-12-21 20:36:45 +01:00
|
|
|
int r = open_internal(stream_list[i], NULL, url, flags, global, &s);
|
2013-08-25 22:50:16 +02:00
|
|
|
if (r == STREAM_OK)
|
|
|
|
break;
|
|
|
|
if (r == STREAM_NO_MATCH || r == STREAM_UNSUPPORTED)
|
2013-01-24 17:43:07 +01:00
|
|
|
continue;
|
2013-08-25 22:50:16 +02:00
|
|
|
if (r != STREAM_OK) {
|
2013-12-21 20:36:45 +01:00
|
|
|
mp_err(log, "Failed to open %s.\n", url);
|
|
|
|
goto done;
|
2013-01-24 17:43:07 +01:00
|
|
|
}
|
2013-08-25 22:50:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!s) {
|
2013-12-21 20:36:45 +01:00
|
|
|
mp_err(log, "No stream found to handle url %s\n", url);
|
|
|
|
goto done;
|
2013-08-25 22:50:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Open stream filters
|
|
|
|
for (;;) {
|
|
|
|
struct stream *new = NULL;
|
|
|
|
for (int i = 0; stream_list[i]; i++) {
|
2013-12-21 20:36:45 +01:00
|
|
|
int r = open_internal(stream_list[i], s, s->url, flags, global, &new);
|
2013-08-25 22:50:16 +02:00
|
|
|
if (r == STREAM_OK)
|
2013-01-24 17:43:07 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-08-25 22:50:16 +02:00
|
|
|
if (!new)
|
|
|
|
break;
|
|
|
|
s = new;
|
2003-04-02 18:25:07 +02:00
|
|
|
}
|
|
|
|
|
2013-12-21 20:36:45 +01:00
|
|
|
done:
|
|
|
|
talloc_free(log);
|
2013-08-25 22:50:16 +02:00
|
|
|
return s;
|
2003-04-02 18:25:07 +02:00
|
|
|
}
|
|
|
|
|
2013-12-21 20:36:45 +01:00
|
|
|
struct stream *stream_open(const char *filename, struct mpv_global *global)
|
2012-10-13 17:09:35 +02:00
|
|
|
{
|
2013-12-21 20:36:45 +01:00
|
|
|
return stream_create(filename, STREAM_READ, global);
|
2012-10-13 17:09:35 +02:00
|
|
|
}
|
|
|
|
|
2013-12-21 20:36:45 +01:00
|
|
|
stream_t *open_output_stream(const char *filename, struct mpv_global *global)
|
2008-04-23 05:35:36 +02:00
|
|
|
{
|
2013-12-21 20:36:45 +01:00
|
|
|
return stream_create(filename, STREAM_WRITE, global);
|
2006-12-18 21:56:24 +01:00
|
|
|
}
|
|
|
|
|
2012-04-22 14:10:49 +02:00
|
|
|
static int stream_reconnect(stream_t *s)
|
|
|
|
{
|
|
|
|
#define MAX_RECONNECT_RETRIES 5
|
2014-04-25 19:11:58 +02:00
|
|
|
#define RECONNECT_SLEEP_MAX_MS 500
|
2013-01-24 18:45:24 +01:00
|
|
|
if (!s->streaming)
|
|
|
|
return 0;
|
2013-11-03 17:46:36 +01:00
|
|
|
if (!(s->flags & MP_STREAM_SEEK_FW))
|
2013-11-03 17:30:34 +01:00
|
|
|
return 0;
|
2012-11-18 20:46:12 +01:00
|
|
|
int64_t pos = s->pos;
|
2014-04-25 19:11:58 +02:00
|
|
|
int sleep_ms = 5;
|
2013-01-24 18:45:24 +01:00
|
|
|
for (int retry = 0; retry < MAX_RECONNECT_RETRIES; retry++) {
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_WARN(s, "Connection lost! Attempting to reconnect (%d)...\n", retry + 1);
|
2013-01-24 18:45:24 +01:00
|
|
|
|
2014-04-25 19:11:58 +02:00
|
|
|
if (retry) {
|
|
|
|
mp_sleep_us(sleep_ms * 1000);
|
|
|
|
sleep_ms = MPMIN(sleep_ms * 2, RECONNECT_SLEEP_MAX_MS);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stream_check_interrupt(0))
|
2013-06-06 20:39:55 +02:00
|
|
|
return 0;
|
2013-01-24 18:45:24 +01:00
|
|
|
|
2013-01-24 17:43:07 +01:00
|
|
|
s->eof = 1;
|
2013-06-06 20:39:58 +02:00
|
|
|
s->pos = 0;
|
|
|
|
s->buf_pos = s->buf_len = 0;
|
2013-01-24 18:45:24 +01:00
|
|
|
|
2013-07-07 21:04:19 +02:00
|
|
|
int r = stream_control(s, STREAM_CTRL_RECONNECT, NULL);
|
|
|
|
if (r == STREAM_UNSUPPORTED)
|
|
|
|
return 0;
|
|
|
|
if (r != STREAM_OK)
|
|
|
|
continue;
|
2013-01-24 18:45:24 +01:00
|
|
|
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
if (stream_seek_unbuffered(s, pos) < 0 && s->pos == pos)
|
2013-01-24 18:45:24 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2012-04-22 14:10:49 +02:00
|
|
|
}
|
|
|
|
|
2013-05-11 22:19:33 +02:00
|
|
|
void stream_set_capture_file(stream_t *s, const char *filename)
|
|
|
|
{
|
|
|
|
if (!bstr_equals(bstr0(s->capture_filename), bstr0(filename))) {
|
|
|
|
if (s->capture_file)
|
|
|
|
fclose(s->capture_file);
|
|
|
|
talloc_free(s->capture_filename);
|
|
|
|
s->capture_file = NULL;
|
|
|
|
s->capture_filename = NULL;
|
|
|
|
if (filename) {
|
|
|
|
s->capture_file = fopen(filename, "wb");
|
|
|
|
if (s->capture_file) {
|
|
|
|
s->capture_filename = talloc_strdup(NULL, filename);
|
|
|
|
} else {
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_ERR(s, "Error opening capture file: %s\n", strerror(errno));
|
2013-05-11 22:19:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-25 15:03:30 +02:00
|
|
|
static void stream_capture_write(stream_t *s, void *buf, size_t len)
|
2013-05-11 22:19:33 +02:00
|
|
|
{
|
2013-05-25 15:03:30 +02:00
|
|
|
if (s->capture_file && len > 0) {
|
|
|
|
if (fwrite(buf, len, 1, s->capture_file) < 1) {
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_ERR(s, "Error writing capture file: %s\n", strerror(errno));
|
2013-05-11 22:19:33 +02:00
|
|
|
stream_set_capture_file(s, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
// Read function bypassing the local stream buffer. This will not write into
|
|
|
|
// 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.
|
2013-05-25 15:03:30 +02:00
|
|
|
static int stream_read_unbuffered(stream_t *s, void *buf, int len)
|
2010-10-27 21:04:04 +02:00
|
|
|
{
|
2013-01-24 17:43:07 +01:00
|
|
|
int orig_len = len;
|
stream: add stream_unread_buffer()
demux_lavf probes up to 2 MB of data in the worst case. When the ffmpeg
demuxer is actually opened, the stream is seeked back to 0, and the
previously read data is thrown away.
This wasn't a problem for playback of local files, but it's less than
ideal for playing from slow media (like web streams), and breaks
completely if the media is not seekable (pipes, some web streams).
This new function is intended to allow fixing this. demux_lavf will use
it to put the read probe data back into the buffer.
The simplest way of implementing this function is by making it
transparently extend the normal stream buffer. This makes sure no
existing code is broken by new weird special cases. For simplicity
and to avoid possible performance loss due to extra dereferencing
when accessing the buffer, we just extend the static buffer from
8 KB to 2 MB. Normally, most of these 2 MB will stay uncommitted, so
there's no associated waste of memory. If demux_lavf really reads all
2 MB, the memory will be committed and stay unused, though.
2013-05-24 23:20:09 +02:00
|
|
|
s->buf_pos = s->buf_len = 0;
|
2013-01-24 17:43:07 +01:00
|
|
|
// we will retry even if we already reached EOF previously.
|
stream: remove fd member
Stream implementations could set this to a unix file descriptor. The
generic stream code could use it as fallback for a few things. This
was confusing and insane. In most cases, the stream implementations
defined all callbacks, so setting the fd member didn't have any
advantages, other than avoiding defining a private struct to store it.
It appears that even if the stream implementation used close() on the
fd (or something equivalent), stream.c would close() it a second time
(and on windows, even would call closesocket()), which should be proof
for the insanity of this code.
For stream_file.c, additionally make sure we don't close stdin or
stdout if "-" is used as filename.
For stream_vcd.c, remove the control() code. This code most likely
didn't make the slightest sense, because it used a different type
for stream->priv. It also leaked memory. Maybe it worked, but it's
incorrect and insignificant anyway, so kill it. This code was added
with commit 9521c19 (svn commit 31019).
Untested for all protocols other than stream_file.c.
2013-07-12 22:07:07 +02:00
|
|
|
len = s->fill_buffer ? s->fill_buffer(s, buf, len) : -1;
|
2013-06-21 20:16:52 +02:00
|
|
|
if (len < 0)
|
|
|
|
len = 0;
|
|
|
|
if (len == 0) {
|
2013-01-24 17:43:07 +01:00
|
|
|
// do not retry if this looks like proper eof
|
|
|
|
if (s->eof || (s->end_pos && s->pos == s->end_pos))
|
|
|
|
goto eof_out;
|
|
|
|
|
|
|
|
// just in case this is an error e.g. due to network
|
|
|
|
// timeout reset and retry
|
|
|
|
if (!stream_reconnect(s))
|
|
|
|
goto eof_out;
|
|
|
|
// make sure EOF is set to ensure no endless loops
|
2011-07-04 21:14:06 +02:00
|
|
|
s->eof = 1;
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
return stream_read_unbuffered(s, buf, orig_len);
|
2011-07-04 21:21:59 +02:00
|
|
|
|
|
|
|
eof_out:
|
2013-01-24 17:43:07 +01:00
|
|
|
s->eof = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// When reading succeeded we are obviously not at eof.
|
|
|
|
s->eof = 0;
|
|
|
|
s->pos += len;
|
2013-05-25 15:03:30 +02:00
|
|
|
stream_capture_write(s, buf, len);
|
2013-01-24 17:43:07 +01:00
|
|
|
return len;
|
2010-10-27 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
2013-08-22 18:27:31 +02:00
|
|
|
static int stream_fill_buffer_by(stream_t *s, int64_t len)
|
2013-01-24 17:43:07 +01:00
|
|
|
{
|
2013-08-22 18:27:31 +02:00
|
|
|
len = MPMIN(len, s->read_chunk);
|
|
|
|
len = MPMAX(len, STREAM_BUFFER_SIZE);
|
|
|
|
if (s->sector_size)
|
|
|
|
len = s->sector_size;
|
2013-07-07 21:58:48 +02:00
|
|
|
len = stream_read_unbuffered(s, s->buffer, len);
|
2013-01-24 17:43:07 +01:00
|
|
|
s->buf_pos = 0;
|
2013-06-21 20:16:52 +02:00
|
|
|
s->buf_len = len;
|
2013-06-06 20:39:50 +02:00
|
|
|
return s->buf_len;
|
2001-02-24 21:28:24 +01:00
|
|
|
}
|
|
|
|
|
2013-08-22 18:27:31 +02:00
|
|
|
int stream_fill_buffer(stream_t *s)
|
|
|
|
{
|
|
|
|
return stream_fill_buffer_by(s, STREAM_BUFFER_SIZE);
|
|
|
|
}
|
|
|
|
|
2013-05-27 21:53:40 +02:00
|
|
|
// Read between 1..buf_size bytes of data, return how much data has been read.
|
2013-06-21 20:16:52 +02:00
|
|
|
// Return 0 on EOF, error, of if buf_size was 0.
|
2013-05-27 21:53:40 +02:00
|
|
|
int stream_read_partial(stream_t *s, char *buf, int buf_size)
|
|
|
|
{
|
|
|
|
assert(s->buf_pos <= s->buf_len);
|
|
|
|
assert(buf_size >= 0);
|
|
|
|
if (s->buf_pos == s->buf_len && buf_size > 0) {
|
|
|
|
s->buf_pos = s->buf_len = 0;
|
|
|
|
// Do a direct read, but only if there's no sector alignment requirement
|
|
|
|
// Also, small reads will be more efficient with buffering & copying
|
|
|
|
if (!s->sector_size && buf_size >= STREAM_BUFFER_SIZE)
|
|
|
|
return stream_read_unbuffered(s, buf, buf_size);
|
|
|
|
if (!stream_fill_buffer(s))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int len = FFMIN(buf_size, s->buf_len - s->buf_pos);
|
|
|
|
memcpy(buf, &s->buffer[s->buf_pos], len);
|
|
|
|
s->buf_pos += len;
|
2013-07-04 17:58:48 +02:00
|
|
|
if (len > 0)
|
|
|
|
s->eof = 0;
|
2013-05-27 21:53:40 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2013-05-24 11:56:49 +02:00
|
|
|
int stream_read(stream_t *s, char *mem, int total)
|
|
|
|
{
|
|
|
|
int len = total;
|
|
|
|
while (len > 0) {
|
2013-05-27 21:53:40 +02:00
|
|
|
int read = stream_read_partial(s, mem, len);
|
|
|
|
if (read <= 0)
|
|
|
|
break; // EOF
|
|
|
|
mem += read;
|
|
|
|
len -= read;
|
2013-05-24 11:56:49 +02:00
|
|
|
}
|
2013-07-04 17:58:48 +02:00
|
|
|
total -= len;
|
|
|
|
if (total > 0)
|
|
|
|
s->eof = 0;
|
|
|
|
return total;
|
2013-05-24 11:56:49 +02:00
|
|
|
}
|
|
|
|
|
2013-06-21 21:06:36 +02:00
|
|
|
// Read ahead at most len bytes without changing the read position. Return a
|
|
|
|
// pointer to the internal buffer, starting from the current read position.
|
|
|
|
// Can read ahead at most STREAM_MAX_BUFFER_SIZE bytes.
|
|
|
|
// The returned buffer becomes invalid on the next stream call, and you must
|
|
|
|
// not write to it.
|
|
|
|
struct bstr stream_peek(stream_t *s, int len)
|
|
|
|
{
|
|
|
|
assert(len >= 0);
|
|
|
|
assert(len <= STREAM_MAX_BUFFER_SIZE);
|
|
|
|
if (s->buf_len - s->buf_pos < len) {
|
|
|
|
// Move to front to guarantee we really can read up to max size.
|
|
|
|
int buf_valid = s->buf_len - s->buf_pos;
|
|
|
|
memmove(s->buffer, &s->buffer[s->buf_pos], buf_valid);
|
|
|
|
// Fill rest of the buffer.
|
|
|
|
while (buf_valid < len) {
|
2013-08-26 23:28:05 +02:00
|
|
|
int chunk = MPMAX(len - buf_valid, STREAM_BUFFER_SIZE);
|
2013-06-21 21:06:36 +02:00
|
|
|
if (s->sector_size)
|
2014-01-02 00:39:14 +01:00
|
|
|
chunk = s->sector_size;
|
2013-06-21 21:06:36 +02:00
|
|
|
assert(buf_valid + chunk <= TOTAL_BUFFER_SIZE);
|
|
|
|
int read = stream_read_unbuffered(s, &s->buffer[buf_valid], chunk);
|
|
|
|
if (read == 0)
|
|
|
|
break; // EOF
|
|
|
|
buf_valid += read;
|
|
|
|
}
|
|
|
|
s->buf_pos = 0;
|
|
|
|
s->buf_len = buf_valid;
|
|
|
|
if (s->buf_len)
|
|
|
|
s->eof = 0;
|
|
|
|
}
|
|
|
|
return (bstr){.start = &s->buffer[s->buf_pos],
|
|
|
|
.len = FFMIN(len, s->buf_len - s->buf_pos)};
|
|
|
|
}
|
|
|
|
|
2013-01-24 17:43:07 +01:00
|
|
|
int stream_write_buffer(stream_t *s, unsigned char *buf, int len)
|
|
|
|
{
|
|
|
|
int rd;
|
|
|
|
if (!s->write_buffer)
|
|
|
|
return -1;
|
|
|
|
rd = s->write_buffer(s, buf, len);
|
|
|
|
if (rd < 0)
|
|
|
|
return -1;
|
|
|
|
s->pos += rd;
|
|
|
|
assert(rd == len && "stream_write_buffer(): unexpected short write");
|
|
|
|
return rd;
|
2006-12-18 21:56:24 +01:00
|
|
|
}
|
|
|
|
|
2013-08-22 18:21:32 +02:00
|
|
|
static int stream_skip_read(struct stream *s, int64_t len)
|
|
|
|
{
|
|
|
|
while (len > 0) {
|
|
|
|
int x = s->buf_len - s->buf_pos;
|
|
|
|
if (x == 0) {
|
2013-08-22 18:27:31 +02:00
|
|
|
if (!stream_fill_buffer_by(s, len))
|
2013-08-22 18:21:32 +02:00
|
|
|
return 0; // EOF
|
|
|
|
x = s->buf_len - s->buf_pos;
|
|
|
|
}
|
|
|
|
if (x > len)
|
|
|
|
x = len;
|
|
|
|
s->buf_pos += x;
|
|
|
|
len -= x;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-12-14 00:51:00 +01:00
|
|
|
// Drop the internal buffer. Note that this will advance the stream position
|
|
|
|
// (as seen by stream_tell()), because the real stream position is ahead of the
|
|
|
|
// logical stream position by the amount of buffered but not yet read data.
|
|
|
|
void stream_drop_buffers(stream_t *s)
|
|
|
|
{
|
|
|
|
s->buf_pos = s->buf_len = 0;
|
|
|
|
s->eof = 0;
|
|
|
|
}
|
|
|
|
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
// Seek function bypassing the local stream buffer.
|
2013-05-25 15:03:30 +02:00
|
|
|
static int stream_seek_unbuffered(stream_t *s, int64_t newpos)
|
2010-10-27 21:04:04 +02:00
|
|
|
{
|
2013-07-07 21:04:19 +02:00
|
|
|
if (newpos != s->pos) {
|
2013-11-03 17:46:36 +01:00
|
|
|
if (newpos > s->pos && !(s->flags & MP_STREAM_SEEK_FW)) {
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_ERR(s, "Can not seek in this stream\n");
|
2013-07-07 20:49:15 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (newpos < s->pos && !(s->flags & MP_STREAM_SEEK_BW)) {
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_ERR(s, "Cannot seek backward in linear streams!\n");
|
2013-07-07 20:49:15 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (s->seek(s, newpos) <= 0) {
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_ERR(s, "Seek failed\n");
|
2013-07-07 20:49:15 +02:00
|
|
|
return 0;
|
2013-01-24 17:43:07 +01:00
|
|
|
}
|
|
|
|
}
|
2013-08-22 18:23:33 +02:00
|
|
|
s->pos = newpos;
|
2013-06-06 20:39:58 +02:00
|
|
|
s->eof = 0; // EOF reset when seek succeeds.
|
2013-01-24 17:43:07 +01:00
|
|
|
return -1;
|
2010-10-27 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
// Unlike stream_seek, does not try to seek within local buffer.
|
|
|
|
// Unlike stream_seek_unbuffered(), it still fills the local buffer.
|
|
|
|
static int stream_seek_long(stream_t *s, int64_t pos)
|
2013-01-24 17:43:07 +01:00
|
|
|
{
|
2013-12-14 00:51:00 +01:00
|
|
|
stream_drop_buffers(s);
|
2010-10-27 21:04:04 +02:00
|
|
|
|
2013-01-24 17:43:07 +01:00
|
|
|
if (s->mode == STREAM_WRITE) {
|
2013-11-03 17:46:36 +01:00
|
|
|
if (!(s->flags & MP_STREAM_SEEK) || !s->seek(s, pos))
|
2013-01-24 17:43:07 +01:00
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
2010-10-27 21:04:04 +02:00
|
|
|
|
2013-06-06 18:16:57 +02:00
|
|
|
int64_t newpos = pos;
|
2013-01-24 17:43:07 +01:00
|
|
|
if (s->sector_size)
|
|
|
|
newpos = (pos / s->sector_size) * s->sector_size;
|
|
|
|
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_TRACE(s, "Seek from %" PRId64 " to %" PRId64
|
|
|
|
" (with offset %d)\n", s->pos, pos, (int)(pos - newpos));
|
2013-06-06 20:39:53 +02:00
|
|
|
|
2013-11-03 17:46:36 +01:00
|
|
|
if (pos >= s->pos && !(s->flags & MP_STREAM_SEEK) &&
|
|
|
|
(s->flags & MP_STREAM_FAST_SKIPPING))
|
|
|
|
{
|
2013-08-22 18:21:32 +02:00
|
|
|
// skipping is handled by generic code below
|
|
|
|
} else if (stream_seek_unbuffered(s, newpos) >= 0) {
|
2013-06-06 20:40:05 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2010-10-27 21:04:04 +02:00
|
|
|
|
2013-08-22 18:21:32 +02:00
|
|
|
if (pos >= s->pos && stream_skip_read(s, pos - s->pos) > 0)
|
|
|
|
return 1; // success
|
2001-02-24 21:28:24 +01:00
|
|
|
|
2013-06-06 17:51:43 +02:00
|
|
|
// Fill failed, but seek still is a success (partially).
|
2013-01-24 17:43:07 +01:00
|
|
|
s->buf_pos = 0;
|
|
|
|
s->buf_len = 0;
|
2013-06-06 20:40:05 +02:00
|
|
|
s->eof = 0; // eof should be set only on read
|
2010-01-18 13:38:56 +01:00
|
|
|
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_VERBOSE(s, "Seek to/past EOF: no buffer preloaded.\n");
|
2013-01-24 17:43:07 +01:00
|
|
|
return 1;
|
2001-02-24 21:28:24 +01:00
|
|
|
}
|
|
|
|
|
2013-05-24 11:56:49 +02:00
|
|
|
int stream_seek(stream_t *s, int64_t pos)
|
|
|
|
{
|
|
|
|
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_TRACE(s, "seek to 0x%llX\n", (long long)pos);
|
2013-05-24 11:56:49 +02:00
|
|
|
|
2013-12-14 00:52:39 +01:00
|
|
|
if (pos == stream_tell(s))
|
|
|
|
return 1;
|
|
|
|
|
2013-05-24 11:56:49 +02:00
|
|
|
if (pos < 0) {
|
2013-12-21 20:36:45 +01:00
|
|
|
MP_ERR(s, "Invalid seek to negative position %llx!\n", (long long)pos);
|
2013-05-24 11:56:49 +02:00
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
if (pos < s->pos) {
|
2013-06-06 20:40:05 +02:00
|
|
|
int64_t x = pos - (s->pos - (int)s->buf_len);
|
2013-05-24 11:56:49 +02:00
|
|
|
if (x >= 0) {
|
|
|
|
s->buf_pos = x;
|
|
|
|
s->eof = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
return stream_seek_long(s, pos);
|
2013-05-24 11:56:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int stream_skip(stream_t *s, int64_t len)
|
|
|
|
{
|
2013-06-06 20:40:05 +02:00
|
|
|
int64_t target = stream_tell(s) + len;
|
|
|
|
if (len < 0)
|
|
|
|
return stream_seek(s, target);
|
|
|
|
if (len > 2 * STREAM_BUFFER_SIZE && (s->flags & MP_STREAM_SEEK_FW)) {
|
|
|
|
// Seek to 1 byte before target - this is the only way to distinguish
|
|
|
|
// skip-to-EOF and skip-past-EOF in general. Successful seeking means
|
|
|
|
// absolutely nothing, so test by doing a real read of the last byte.
|
|
|
|
int r = stream_seek(s, target - 1);
|
|
|
|
if (r) {
|
|
|
|
stream_read_char(s);
|
2013-06-06 17:51:43 +02:00
|
|
|
return !stream_eof(s) && stream_tell(s) == target;
|
2013-06-06 20:40:05 +02:00
|
|
|
}
|
|
|
|
return r;
|
2013-05-24 11:56:49 +02:00
|
|
|
}
|
2013-08-22 18:21:32 +02:00
|
|
|
return stream_skip_read(s, len);
|
2013-05-24 11:56:49 +02:00
|
|
|
}
|
2001-02-24 21:28:24 +01:00
|
|
|
|
2013-01-24 17:43:07 +01:00
|
|
|
int stream_control(stream_t *s, int cmd, void *arg)
|
|
|
|
{
|
|
|
|
if (!s->control)
|
|
|
|
return STREAM_UNSUPPORTED;
|
|
|
|
return s->control(s, cmd, arg);
|
2006-02-27 22:06:47 +01:00
|
|
|
}
|
|
|
|
|
2012-11-18 21:23:17 +01:00
|
|
|
void stream_update_size(stream_t *s)
|
|
|
|
{
|
2013-11-03 17:46:36 +01:00
|
|
|
if (!(s->flags & MP_STREAM_SEEK))
|
|
|
|
return;
|
2012-11-18 21:23:17 +01:00
|
|
|
uint64_t size;
|
|
|
|
if (stream_control(s, STREAM_CTRL_GET_SIZE, &size) == STREAM_OK) {
|
|
|
|
if (size > s->end_pos)
|
|
|
|
s->end_pos = size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-24 17:43:07 +01:00
|
|
|
void free_stream(stream_t *s)
|
|
|
|
{
|
2013-07-12 22:06:14 +02:00
|
|
|
if (!s)
|
|
|
|
return;
|
|
|
|
|
2013-05-11 22:19:33 +02:00
|
|
|
stream_set_capture_file(s, NULL);
|
2010-11-02 02:17:41 +01:00
|
|
|
|
2013-01-24 17:43:07 +01:00
|
|
|
if (s->close)
|
|
|
|
s->close(s);
|
2013-07-12 22:06:14 +02:00
|
|
|
free_stream(s->uncached_stream);
|
2013-08-25 22:50:16 +02:00
|
|
|
free_stream(s->source);
|
2013-01-24 17:43:07 +01:00
|
|
|
talloc_free(s);
|
2001-02-24 21:28:24 +01:00
|
|
|
}
|
|
|
|
|
2008-04-30 06:15:52 +02:00
|
|
|
void stream_set_interrupt_callback(int (*cb)(struct input_ctx *, int),
|
|
|
|
struct input_ctx *ctx)
|
|
|
|
{
|
2008-04-09 02:36:28 +02:00
|
|
|
stream_check_interrupt_cb = cb;
|
2008-04-30 06:15:52 +02:00
|
|
|
stream_check_interrupt_ctx = ctx;
|
2008-04-09 02:36:28 +02:00
|
|
|
}
|
|
|
|
|
2013-01-24 17:43:07 +01:00
|
|
|
int stream_check_interrupt(int time)
|
|
|
|
{
|
|
|
|
if (!stream_check_interrupt_cb) {
|
2013-05-25 19:56:52 +02:00
|
|
|
mp_sleep_us(time * 1000);
|
2010-05-28 20:49:02 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2008-04-30 06:15:52 +02:00
|
|
|
return stream_check_interrupt_cb(stream_check_interrupt_ctx, time);
|
2008-04-09 02:36:28 +02:00
|
|
|
}
|
2010-02-28 14:54:55 +01:00
|
|
|
|
2013-06-21 00:47:58 +02:00
|
|
|
stream_t *open_memory_stream(void *data, int len)
|
|
|
|
{
|
|
|
|
assert(len >= 0);
|
2013-12-21 20:36:45 +01:00
|
|
|
struct mpv_global *dummy = talloc_zero(NULL, struct mpv_global);
|
|
|
|
dummy->log = mp_null_log;
|
|
|
|
stream_t *s = stream_open("memory://", dummy);
|
2013-06-27 17:21:46 +02:00
|
|
|
assert(s);
|
2013-12-21 20:36:45 +01:00
|
|
|
talloc_steal(s, dummy);
|
2013-06-27 17:21:46 +02:00
|
|
|
stream_control(s, STREAM_CTRL_SET_CONTENTS, &(bstr){data, len});
|
2013-06-21 00:47:58 +02:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2013-07-10 15:03:54 +02:00
|
|
|
static int stream_enable_cache(stream_t **stream, int64_t size, int64_t min,
|
|
|
|
int64_t seek_limit);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \return 1 on success, 0 if the function was interrupted and -1 on error, or
|
|
|
|
* if the cache is disabled
|
|
|
|
*/
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
int stream_enable_cache_percent(stream_t **stream, int64_t stream_cache_size,
|
2013-07-10 15:03:54 +02:00
|
|
|
int64_t stream_cache_def_size,
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
float stream_cache_min_percent,
|
|
|
|
float stream_cache_seek_min_percent)
|
|
|
|
{
|
2013-05-25 15:03:30 +02:00
|
|
|
if (stream_cache_size == -1)
|
2013-07-10 15:03:54 +02:00
|
|
|
stream_cache_size = (*stream)->streaming ? stream_cache_def_size : 0;
|
2013-05-25 15:03:30 +02:00
|
|
|
|
|
|
|
stream_cache_size = stream_cache_size * 1024; // input is in KiB
|
|
|
|
return stream_enable_cache(stream, stream_cache_size,
|
|
|
|
stream_cache_size *
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
(stream_cache_min_percent / 100.0),
|
2013-05-25 15:03:30 +02:00
|
|
|
stream_cache_size *
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
(stream_cache_seek_min_percent / 100.0));
|
|
|
|
}
|
|
|
|
|
2013-07-10 15:03:54 +02:00
|
|
|
static int stream_enable_cache(stream_t **stream, int64_t size, int64_t min,
|
|
|
|
int64_t seek_limit)
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
{
|
|
|
|
stream_t *orig = *stream;
|
|
|
|
|
2013-12-14 01:21:06 +01:00
|
|
|
if (orig->mode != STREAM_READ || !orig->allow_caching)
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
return 1;
|
|
|
|
|
2013-08-02 17:02:34 +02:00
|
|
|
stream_t *cache = new_stream();
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
cache->uncached_type = orig->type;
|
|
|
|
cache->uncached_stream = orig;
|
|
|
|
cache->flags |= MP_STREAM_SEEK;
|
|
|
|
cache->mode = STREAM_READ;
|
2013-06-09 22:47:17 +02:00
|
|
|
cache->read_chunk = 4 * STREAM_BUFFER_SIZE;
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
|
2013-07-12 22:06:14 +02:00
|
|
|
cache->url = talloc_strdup(cache, orig->url);
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
cache->mime_type = talloc_strdup(cache, orig->mime_type);
|
2013-09-10 15:23:27 +02:00
|
|
|
cache->demuxer = talloc_strdup(cache, orig->demuxer);
|
2013-07-12 22:06:14 +02:00
|
|
|
cache->lavf_type = talloc_strdup(cache, orig->lavf_type);
|
2013-08-25 20:40:21 +02:00
|
|
|
cache->safe_origin = orig->safe_origin;
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
cache->opts = orig->opts;
|
2013-12-21 20:36:45 +01:00
|
|
|
cache->global = orig->global;
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
cache->start_pos = orig->start_pos;
|
|
|
|
cache->end_pos = orig->end_pos;
|
|
|
|
|
2013-12-21 20:36:45 +01:00
|
|
|
cache->log = mp_log_new(cache, cache->global->log, "cache");
|
|
|
|
|
2013-11-28 19:28:38 +01:00
|
|
|
int res = stream_cache_init(cache, orig, size, min, seek_limit);
|
cache: make the stream cache a proper stream that wraps other streams
Before this commit, the cache was franken-hacked on top of the stream
API. You had to use special functions (like cache_stream_fill_buffer()
instead of stream_fill_buffer()), which would access the stream in a
cached manner.
The whole idea about the previous design was that the cache runs in a
thread or in a forked process, while the cache awa functions made sure
the stream instance looked consistent to the user. If you used the
normal functions instead of the special ones while the cache was
running, you were out of luck.
Make it a bit more reasonable by turning the cache into a stream on its
own. This makes it behave exactly like a normal stream. The stream
callbacks call into the original (uncached) stream to do work. No
special cache functions or redirections are needed. The only different
thing about cache streams is that they are created by special functions,
instead of being part of the auto_open_streams[] array.
To make things simpler, remove the threading implementation, which was
messed into the code. The threading code could perhaps be kept, but I
don't really want to have to worry about this special case. A proper
threaded implementation will be added later.
Remove the cache enabling code from stream_radio.c. Since enabling the
cache involves replacing the old stream with a new one, the code as-is
can't be kept. It would be easily possible to enable the cache by
requesting a cache size (which is also much simpler). But nobody uses
stream_radio.c and I can't even test this thing, and the cache is
probably not really important for it either.
2013-05-24 18:49:09 +02:00
|
|
|
if (res <= 0) {
|
|
|
|
cache->uncached_stream = NULL; // don't free original stream
|
|
|
|
free_stream(cache);
|
|
|
|
} else {
|
|
|
|
*stream = cache;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-01-19 20:21:11 +01:00
|
|
|
static uint16_t stream_read_word_endian(stream_t *s, bool big_endian)
|
2010-02-28 16:24:30 +01:00
|
|
|
{
|
2014-01-19 20:21:11 +01:00
|
|
|
unsigned int y = stream_read_char(s);
|
|
|
|
y = (y << 8) | stream_read_char(s);
|
|
|
|
if (big_endian)
|
|
|
|
y = bswap_16(y);
|
|
|
|
return y;
|
2010-02-28 16:24:30 +01:00
|
|
|
}
|
|
|
|
|
2014-01-19 20:21:11 +01:00
|
|
|
// Read characters until the next '\n' (including), or until the buffer in s is
|
|
|
|
// exhausted.
|
|
|
|
static int read_characters(stream_t *s, uint8_t *dst, int dstsize, int utf16)
|
2010-02-28 16:24:30 +01:00
|
|
|
{
|
2014-01-19 20:21:11 +01:00
|
|
|
if (utf16 == 1 || utf16 == 2) {
|
|
|
|
uint8_t *cur = dst;
|
|
|
|
while (1) {
|
|
|
|
if ((cur - dst) + 8 >= dstsize) // PUT_UTF8 writes max. 8 bytes
|
|
|
|
return -1; // line too long
|
|
|
|
uint32_t c;
|
2013-01-24 17:43:07 +01:00
|
|
|
uint8_t tmp;
|
2014-01-19 20:21:11 +01:00
|
|
|
GET_UTF16(c, stream_read_word_endian(s, utf16 == 2), return -1;)
|
|
|
|
if (s->eof)
|
|
|
|
break; // legitimate EOF; ignore the case of partial reads
|
|
|
|
PUT_UTF8(c, tmp, *cur++ = tmp;)
|
|
|
|
if (c == '\n')
|
|
|
|
break;
|
2013-01-24 17:43:07 +01:00
|
|
|
}
|
2014-01-19 20:21:11 +01:00
|
|
|
return cur - dst;
|
|
|
|
} else {
|
|
|
|
if (s->buf_pos >= s->buf_len)
|
|
|
|
stream_fill_buffer(s);
|
|
|
|
uint8_t *src = s->buffer + s->buf_pos;
|
|
|
|
int src_len = s->buf_len - s->buf_pos;
|
|
|
|
uint8_t *end = memchr(src, '\n', src_len);
|
|
|
|
int len = end ? end - src + 1 : src_len;
|
|
|
|
if (len > dstsize)
|
|
|
|
return -1; // line too long
|
|
|
|
memcpy(dst, src, len);
|
|
|
|
s->buf_pos += len;
|
|
|
|
return len;
|
2010-02-28 16:24:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-19 20:21:11 +01:00
|
|
|
// On error, or if the line is larger than max-1, return NULL and unset s->eof.
|
|
|
|
// On EOF, return NULL, and s->eof will be set.
|
|
|
|
// Otherwise, return the line (including \n or \r\n at the end of the line).
|
|
|
|
// If the return value is non-NULL, it's always the same as mem.
|
|
|
|
// utf16: 0: UTF8 or 8 bit legacy, 1: UTF16-LE, 2: UTF16-BE
|
2013-01-24 17:43:07 +01:00
|
|
|
unsigned char *stream_read_line(stream_t *s, unsigned char *mem, int max,
|
|
|
|
int utf16)
|
|
|
|
{
|
|
|
|
if (max < 1)
|
|
|
|
return NULL;
|
2014-01-19 20:21:11 +01:00
|
|
|
int read = 0;
|
|
|
|
while (1) {
|
|
|
|
// Reserve 1 byte of ptr for terminating \0.
|
|
|
|
int l = read_characters(s, &mem[read], max - read - 1, utf16);
|
2014-01-19 20:33:37 +01:00
|
|
|
if (l < 0 || memchr(&mem[read], '\0', l)) {
|
2014-01-19 20:38:01 +01:00
|
|
|
MP_WARN(s, "error reading line\n");
|
2014-01-19 20:21:11 +01:00
|
|
|
s->eof = false;
|
|
|
|
return NULL;
|
2013-01-24 17:43:07 +01:00
|
|
|
}
|
2014-01-19 20:21:11 +01:00
|
|
|
read += l;
|
|
|
|
if (l == 0 || (read > 0 && mem[read - 1] == '\n'))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
mem[read] = '\0';
|
|
|
|
if (s->eof && read == 0) // legitimate EOF
|
2013-01-24 17:43:07 +01:00
|
|
|
return NULL;
|
|
|
|
return mem;
|
2010-02-28 14:54:55 +01:00
|
|
|
}
|
2011-02-25 17:10:00 +01:00
|
|
|
|
2013-08-25 20:40:21 +02:00
|
|
|
static const char *bom[3] = {"\xEF\xBB\xBF", "\xFF\xFE", "\xFE\xFF"};
|
|
|
|
|
|
|
|
// Return utf16 argument for stream_read_line
|
|
|
|
int stream_skip_bom(struct stream *s)
|
|
|
|
{
|
|
|
|
bstr data = stream_peek(s, 4);
|
|
|
|
for (int n = 0; n < 3; n++) {
|
|
|
|
if (bstr_startswith0(data, bom[n])) {
|
|
|
|
stream_skip(s, strlen(bom[n]));
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1; // default to 8 bit codepages
|
|
|
|
}
|
|
|
|
|
2013-06-11 12:16:42 +02:00
|
|
|
// Read the rest of the stream into memory (current pos to EOF), and return it.
|
|
|
|
// talloc_ctx: used as talloc parent for the returned allocation
|
|
|
|
// max_size: must be set to >0. If the file is larger than that, it is treated
|
|
|
|
// as error. This is a minor robustness measure.
|
|
|
|
// returns: stream contents, or .start/.len set to NULL on error
|
|
|
|
// If the file was empty, but no error happened, .start will be non-NULL and
|
|
|
|
// .len will be 0.
|
|
|
|
// For convenience, the returned buffer is padded with a 0 byte. The padding
|
|
|
|
// is not included in the returned length.
|
2011-02-25 17:10:00 +01:00
|
|
|
struct bstr stream_read_complete(struct stream *s, void *talloc_ctx,
|
2013-06-11 12:16:42 +02:00
|
|
|
int max_size)
|
2011-02-25 17:10:00 +01:00
|
|
|
{
|
|
|
|
if (max_size > 1000000000)
|
|
|
|
abort();
|
|
|
|
|
|
|
|
int bufsize;
|
|
|
|
int total_read = 0;
|
2013-06-11 12:16:42 +02:00
|
|
|
int padding = 1;
|
2011-02-25 17:10:00 +01:00
|
|
|
char *buf = NULL;
|
|
|
|
if (s->end_pos > max_size)
|
2013-06-11 12:16:42 +02:00
|
|
|
return (struct bstr){NULL, 0};
|
2011-02-25 17:10:00 +01:00
|
|
|
if (s->end_pos > 0)
|
|
|
|
bufsize = s->end_pos + padding;
|
|
|
|
else
|
|
|
|
bufsize = 1000;
|
|
|
|
while (1) {
|
|
|
|
buf = talloc_realloc_size(talloc_ctx, buf, bufsize);
|
|
|
|
int readsize = stream_read(s, buf + total_read, bufsize - total_read);
|
|
|
|
total_read += readsize;
|
|
|
|
if (total_read < bufsize)
|
|
|
|
break;
|
|
|
|
if (bufsize > max_size) {
|
|
|
|
talloc_free(buf);
|
2013-06-11 12:16:42 +02:00
|
|
|
return (struct bstr){NULL, 0};
|
2011-02-25 17:10:00 +01:00
|
|
|
}
|
|
|
|
bufsize = FFMIN(bufsize + (bufsize >> 1), max_size + padding);
|
|
|
|
}
|
|
|
|
buf = talloc_realloc_size(talloc_ctx, buf, total_read + padding);
|
2013-06-11 12:16:42 +02:00
|
|
|
memset(&buf[total_read], 0, padding);
|
|
|
|
return (struct bstr){buf, total_read};
|
2011-02-25 17:10:00 +01:00
|
|
|
}
|
2013-05-03 19:52:28 +02:00
|
|
|
|
|
|
|
bool stream_manages_timeline(struct stream *s)
|
|
|
|
{
|
|
|
|
return stream_control(s, STREAM_CTRL_MANAGES_TIMELINE, NULL) == STREAM_OK;
|
|
|
|
}
|