2010-01-30 22:26:47 +00: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 20:28:24 +00:00
|
|
|
|
2001-08-01 09:14:02 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
2001-02-24 20:28:24 +00:00
|
|
|
|
2001-07-31 23:18:16 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2003-04-02 16:52:00 +00:00
|
|
|
#ifndef __MINGW32__
|
2001-04-22 16:56:20 +00:00
|
|
|
#include <sys/ioctl.h>
|
2002-07-26 04:04:51 +00:00
|
|
|
#include <sys/wait.h>
|
2003-04-02 16:52:00 +00:00
|
|
|
#endif
|
2001-07-31 23:18:16 +00:00
|
|
|
#include <fcntl.h>
|
2003-04-02 16:25:07 +00:00
|
|
|
#include <strings.h>
|
2011-02-10 21:25:38 +00:00
|
|
|
#include <assert.h>
|
2001-04-22 16:56:20 +00:00
|
|
|
|
2012-02-01 18:01:16 +00:00
|
|
|
#include <libavutil/intreadwrite.h>
|
|
|
|
#include <libavutil/common.h>
|
|
|
|
|
2011-02-25 16:10:00 +00:00
|
|
|
#include "talloc.h"
|
|
|
|
|
2001-08-01 09:14:02 +00:00
|
|
|
#include "config.h"
|
2003-06-11 16:48:09 +00:00
|
|
|
|
2009-02-01 13:42:27 +00:00
|
|
|
#if HAVE_WINSOCK2_H
|
2003-06-11 16:48:09 +00:00
|
|
|
#include <winsock2.h>
|
|
|
|
#endif
|
|
|
|
|
2013-05-11 20:19:33 +00:00
|
|
|
#include "core/bstr.h"
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "core/mp_msg.h"
|
2005-11-18 14:39:25 +00:00
|
|
|
#include "osdep/shmem.h"
|
2010-05-30 13:39:41 +00:00
|
|
|
#include "osdep/timer.h"
|
2008-09-01 07:31:57 +00:00
|
|
|
#include "network.h"
|
2001-04-22 16:56:20 +00:00
|
|
|
#include "stream.h"
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "demux/demux.h"
|
2001-02-24 20:28:24 +00:00
|
|
|
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "core/m_option.h"
|
|
|
|
#include "core/m_struct.h"
|
2003-04-02 16:25:07 +00:00
|
|
|
|
2012-10-13 15:09:35 +00:00
|
|
|
/// We keep these 2 for the gui atm, but they will be removed.
|
2013-01-24 16:43:07 +00:00
|
|
|
char *cdrom_device = NULL;
|
|
|
|
char *dvd_device = NULL;
|
|
|
|
int dvd_title = 0;
|
2012-10-13 15:09:35 +00:00
|
|
|
|
2008-04-30 04:15:52 +00: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 00:36:28 +00:00
|
|
|
|
2007-12-02 13:22:53 +00:00
|
|
|
extern const stream_info_t stream_info_vcd;
|
|
|
|
extern const stream_info_t stream_info_cdda;
|
|
|
|
extern const stream_info_t stream_info_asf;
|
|
|
|
extern const stream_info_t stream_info_udp;
|
|
|
|
extern const stream_info_t stream_info_http1;
|
|
|
|
extern const stream_info_t stream_info_http2;
|
|
|
|
extern const stream_info_t stream_info_dvb;
|
|
|
|
extern const stream_info_t stream_info_tv;
|
|
|
|
extern const stream_info_t stream_info_radio;
|
|
|
|
extern const stream_info_t stream_info_pvr;
|
|
|
|
extern const stream_info_t stream_info_ftp;
|
|
|
|
extern const stream_info_t stream_info_vstream;
|
|
|
|
extern const stream_info_t stream_info_smb;
|
2003-08-11 00:02:46 +00:00
|
|
|
|
2007-12-02 13:22:53 +00:00
|
|
|
extern const stream_info_t stream_info_null;
|
|
|
|
extern const stream_info_t stream_info_mf;
|
2009-11-17 16:09:17 +00: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 17:41:04 +00:00
|
|
|
extern const stream_info_t stream_info_avdevice;
|
2007-12-02 13:22:53 +00: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;
|
2010-07-05 17:04:46 +00:00
|
|
|
extern const stream_info_t stream_info_bluray;
|
2003-04-02 16:25:07 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
static const stream_info_t *const auto_open_streams[] = {
|
2008-08-03 15:21:40 +00:00
|
|
|
#ifdef CONFIG_VCD
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_vcd,
|
2003-04-09 07:31:11 +00:00
|
|
|
#endif
|
2008-08-07 08:58:07 +00:00
|
|
|
#ifdef CONFIG_CDDA
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_cdda,
|
2003-04-06 16:36:17 +00:00
|
|
|
#endif
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_ffmpeg, // use for rstp:// before http fallback
|
|
|
|
&stream_info_avdevice,
|
2010-07-17 13:14:53 +00:00
|
|
|
#ifdef CONFIG_NETWORKING
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_http1,
|
|
|
|
&stream_info_asf,
|
|
|
|
&stream_info_udp,
|
|
|
|
&stream_info_http2,
|
2003-04-03 12:00:50 +00:00
|
|
|
#endif
|
2008-08-03 15:21:40 +00:00
|
|
|
#ifdef CONFIG_DVBIN
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_dvb,
|
2003-08-11 00:02:46 +00:00
|
|
|
#endif
|
2008-07-30 12:01:30 +00:00
|
|
|
#ifdef CONFIG_TV
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_tv,
|
2006-07-31 18:36:29 +00:00
|
|
|
#endif
|
2008-07-30 12:01:30 +00:00
|
|
|
#ifdef CONFIG_RADIO
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_radio,
|
2006-08-28 17:05:18 +00:00
|
|
|
#endif
|
2008-08-03 15:21:40 +00:00
|
|
|
#ifdef CONFIG_PVR
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_pvr,
|
2006-07-10 21:32:19 +00:00
|
|
|
#endif
|
2008-08-07 08:58:07 +00:00
|
|
|
#ifdef CONFIG_FTP
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_ftp,
|
2005-02-27 04:25:12 +00:00
|
|
|
#endif
|
2008-08-07 08:58:07 +00:00
|
|
|
#ifdef CONFIG_VSTREAM
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_vstream,
|
2005-05-19 20:58:11 +00:00
|
|
|
#endif
|
2008-08-07 12:20:50 +00:00
|
|
|
#ifdef CONFIG_LIBSMBCLIENT
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_smb,
|
2003-08-15 19:13:23 +00:00
|
|
|
#endif
|
2008-07-30 12:01:30 +00:00
|
|
|
#ifdef CONFIG_DVDREAD
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_ifo,
|
|
|
|
&stream_info_dvd,
|
2005-12-14 21:52:41 +00:00
|
|
|
#endif
|
2010-07-05 17:04:46 +00:00
|
|
|
#ifdef CONFIG_LIBBLURAY
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_bluray,
|
2010-07-05 17:04:46 +00:00
|
|
|
#endif
|
2005-05-19 19:50:39 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
&stream_info_null,
|
|
|
|
&stream_info_mf,
|
|
|
|
&stream_info_file,
|
|
|
|
NULL
|
2003-04-02 16:25:07 +00: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 16:49:09 +00:00
|
|
|
static stream_t *new_stream(void);
|
2013-05-24 15:47:01 +00:00
|
|
|
|
2010-03-09 23:46:46 +00:00
|
|
|
static stream_t *open_stream_plugin(const stream_info_t *sinfo,
|
|
|
|
const char *filename,
|
2008-04-23 03:35:36 +00:00
|
|
|
int mode, struct MPOpts *options,
|
|
|
|
int *file_format, int *ret,
|
|
|
|
char **redirected_url)
|
|
|
|
{
|
2013-01-24 16:43:07 +00:00
|
|
|
void *arg = NULL;
|
|
|
|
stream_t *s;
|
|
|
|
m_struct_t *desc = (m_struct_t *)sinfo->opts;
|
|
|
|
|
|
|
|
// Parse options
|
|
|
|
if (desc) {
|
|
|
|
arg = m_struct_alloc(desc);
|
|
|
|
if (sinfo->opts_url) {
|
|
|
|
m_option_t url_opt = { "stream url", arg, CONF_TYPE_CUSTOM_URL, 0,
|
|
|
|
0, 0, (void *)sinfo->opts };
|
|
|
|
if (m_option_parse(&url_opt, bstr0("stream url"), bstr0(filename),
|
|
|
|
arg) < 0)
|
|
|
|
{
|
|
|
|
mp_tmsg(MSGT_OPEN, MSGL_ERR, "URL parsing failed on url %s\n",
|
|
|
|
filename);
|
|
|
|
m_struct_free(desc, arg);
|
|
|
|
*ret = STREAM_ERROR;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2003-04-02 16:25:07 +00: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 16:49:09 +00:00
|
|
|
s = new_stream();
|
2013-01-24 16:43:07 +00:00
|
|
|
s->opts = options;
|
|
|
|
s->url = strdup(filename);
|
|
|
|
s->flags |= mode;
|
|
|
|
*ret = sinfo->open(s, mode, arg, file_format);
|
|
|
|
if ((*ret) != STREAM_OK) {
|
2010-07-17 13:14:53 +00:00
|
|
|
#ifdef CONFIG_NETWORKING
|
2013-01-24 16:43:07 +00:00
|
|
|
if (*ret == STREAM_REDIRECTED && redirected_url) {
|
|
|
|
if (s->streaming_ctrl && s->streaming_ctrl->url
|
|
|
|
&& s->streaming_ctrl->url->url)
|
|
|
|
*redirected_url = strdup(s->streaming_ctrl->url->url);
|
|
|
|
else
|
|
|
|
*redirected_url = NULL;
|
|
|
|
}
|
|
|
|
streaming_ctrl_free(s->streaming_ctrl);
|
2007-11-26 00:41:21 +00:00
|
|
|
#endif
|
2013-01-24 16:43:07 +00:00
|
|
|
free(s->url);
|
|
|
|
talloc_free(s);
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-11-17 17:12:13 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
if (s->streaming && !s->cache_size) {
|
|
|
|
// Set default cache size to use if user does not specify it.
|
|
|
|
s->cache_size = 320;
|
|
|
|
}
|
2012-11-17 17:12:13 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
if (s->type <= -2)
|
|
|
|
mp_msg(MSGT_OPEN, MSGL_WARN, "Warning streams need a type !!!!\n");
|
2013-06-05 00:00:13 +00:00
|
|
|
if (!s->seek)
|
2013-01-24 16:43:07 +00:00
|
|
|
s->flags &= ~MP_STREAM_SEEK;
|
|
|
|
if (s->seek && !(s->flags & MP_STREAM_SEEK))
|
|
|
|
s->flags |= MP_STREAM_SEEK;
|
2009-07-06 23:26:13 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
s->mode = mode;
|
2003-04-02 16:25:07 +00: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 16:49:09 +00:00
|
|
|
s->uncached_type = s->type;
|
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
mp_msg(MSGT_OPEN, MSGL_V, "STREAM: [%s] %s\n", sinfo->name, filename);
|
|
|
|
mp_msg(MSGT_OPEN, MSGL_V, "STREAM: Description: %s\n", sinfo->info);
|
|
|
|
mp_msg(MSGT_OPEN, MSGL_V, "STREAM: Author: %s\n", sinfo->author);
|
|
|
|
mp_msg(MSGT_OPEN, MSGL_V, "STREAM: Comment: %s\n", sinfo->comment);
|
2009-07-06 23:26:13 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
if (s->mime_type)
|
|
|
|
mp_msg(MSGT_OPEN, MSGL_V, "Mime-type: '%s'\n", s->mime_type);
|
2012-12-10 00:28:20 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
return s;
|
2003-04-02 16:25:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-17 17:12:13 +00:00
|
|
|
static stream_t *open_stream_full(const char *filename, int mode,
|
|
|
|
struct MPOpts *options, int *file_format)
|
2008-04-23 03:35:36 +00:00
|
|
|
{
|
2013-01-24 16:43:07 +00:00
|
|
|
int i, j, l, r;
|
|
|
|
const stream_info_t *sinfo;
|
|
|
|
stream_t *s;
|
|
|
|
char *redirected_url = NULL;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
|
|
|
|
int dummy;
|
|
|
|
if (!file_format)
|
|
|
|
file_format = &dummy;
|
|
|
|
|
|
|
|
*file_format = DEMUXER_TYPE_UNKNOWN;
|
|
|
|
|
|
|
|
for (i = 0; auto_open_streams[i]; i++) {
|
|
|
|
sinfo = auto_open_streams[i];
|
|
|
|
if (!sinfo->protocols) {
|
|
|
|
mp_msg(MSGT_OPEN, MSGL_WARN,
|
|
|
|
"Stream type %s has protocols == NULL, it's a bug\n",
|
|
|
|
sinfo->name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (j = 0; sinfo->protocols[j]; j++) {
|
|
|
|
l = strlen(sinfo->protocols[j]);
|
|
|
|
// l == 0 => Don't do protocol matching (ie network and filenames)
|
|
|
|
if ((l == 0 && !strstr(filename, "://")) ||
|
|
|
|
((strncasecmp(sinfo->protocols[j], filename, l) == 0) &&
|
|
|
|
(strncmp("://", filename + l, 3) == 0))) {
|
|
|
|
*file_format = DEMUXER_TYPE_UNKNOWN;
|
|
|
|
s =
|
|
|
|
open_stream_plugin(sinfo, filename, mode, options,
|
|
|
|
file_format,
|
|
|
|
&r,
|
|
|
|
&redirected_url);
|
|
|
|
if (s)
|
|
|
|
return s;
|
|
|
|
if (r == STREAM_REDIRECTED && redirected_url) {
|
|
|
|
mp_msg(MSGT_OPEN, MSGL_V, "[%s] open %s redirected to %s\n",
|
|
|
|
sinfo->info, filename, redirected_url);
|
|
|
|
s = open_stream_full(redirected_url, mode, options,
|
|
|
|
file_format);
|
|
|
|
free(redirected_url);
|
|
|
|
return s;
|
|
|
|
} else if (r != STREAM_UNSUPPORTED) {
|
|
|
|
mp_tmsg(MSGT_OPEN, MSGL_ERR, "Failed to open %s.\n",
|
|
|
|
filename);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2003-04-02 16:25:07 +00:00
|
|
|
}
|
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
mp_tmsg(MSGT_OPEN, MSGL_ERR, "No stream found to handle url %s\n", filename);
|
|
|
|
return NULL;
|
2003-04-02 16:25:07 +00:00
|
|
|
}
|
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
stream_t *open_stream(const char *filename, struct MPOpts *options,
|
2012-10-13 15:09:35 +00:00
|
|
|
int *file_format)
|
|
|
|
{
|
2013-01-24 16:43:07 +00:00
|
|
|
return open_stream_full(filename, STREAM_READ, options, file_format);
|
2012-10-13 15:09:35 +00:00
|
|
|
}
|
|
|
|
|
2010-03-09 23:46:46 +00:00
|
|
|
stream_t *open_output_stream(const char *filename, struct MPOpts *options)
|
2008-04-23 03:35:36 +00:00
|
|
|
{
|
2013-01-24 16:43:07 +00:00
|
|
|
return open_stream_full(filename, STREAM_WRITE, options, NULL);
|
2006-12-18 20:56:24 +00:00
|
|
|
}
|
|
|
|
|
2001-04-22 16:56:20 +00:00
|
|
|
//=================== STREAMER =========================
|
2001-02-24 20:28:24 +00:00
|
|
|
|
2012-04-22 12:10:49 +00:00
|
|
|
static int stream_reconnect(stream_t *s)
|
|
|
|
{
|
|
|
|
#define MAX_RECONNECT_RETRIES 5
|
|
|
|
#define RECONNECT_SLEEP_MS 1000
|
2013-01-24 17:45:24 +00:00
|
|
|
if (!s->streaming)
|
|
|
|
return 0;
|
2012-11-18 19:46:12 +00:00
|
|
|
int64_t pos = s->pos;
|
2013-01-24 17:45:24 +00:00
|
|
|
for (int retry = 0; retry < MAX_RECONNECT_RETRIES; retry++) {
|
|
|
|
mp_msg(MSGT_STREAM, MSGL_WARN,
|
|
|
|
"Connection lost! Attempting to reconnect...\n");
|
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
if (retry)
|
2013-05-25 17:56:52 +00:00
|
|
|
mp_sleep_us(RECONNECT_SLEEP_MS * 1000);
|
2013-01-24 17:45:24 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
s->eof = 1;
|
2012-04-22 12:10:49 +00:00
|
|
|
stream_reset(s);
|
2013-01-24 17:45:24 +00:00
|
|
|
|
|
|
|
// Some streams (internal http.c) don't support STREAM_CTRL_RECONNECT,
|
|
|
|
// but do it when trying to seek.
|
|
|
|
if (s->control) {
|
|
|
|
if (s->control(s, STREAM_CTRL_RECONNECT, NULL) == STREAM_ERROR)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
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 16:49:09 +00:00
|
|
|
if (stream_seek_unbuffered(s, pos) < 0 && s->pos == pos)
|
2013-01-24 17:45:24 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2012-04-22 12:10:49 +00:00
|
|
|
}
|
|
|
|
|
2013-05-11 20:19:33 +00: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 {
|
|
|
|
mp_tmsg(MSGT_GLOBAL, MSGL_ERR,
|
|
|
|
"Error opening capture file: %s\n", strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void stream_capture_write(stream_t *s)
|
|
|
|
{
|
|
|
|
if (s->capture_file) {
|
|
|
|
if (fwrite(s->buffer, s->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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 16:49:09 +00: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.
|
|
|
|
int stream_read_unbuffered(stream_t *s, void *buf, int len)
|
2010-10-27 19:04:04 +00:00
|
|
|
{
|
2013-01-24 16:43:07 +00:00
|
|
|
int orig_len = len;
|
|
|
|
// we will retry even if we already reached EOF previously.
|
|
|
|
switch (s->type) {
|
|
|
|
case STREAMTYPE_STREAM:
|
|
|
|
if (s->streaming_ctrl != NULL && s->streaming_ctrl->streaming_read) {
|
|
|
|
len = s->streaming_ctrl->streaming_read(s->fd, buf, len,
|
|
|
|
s->streaming_ctrl);
|
|
|
|
if (s->streaming_ctrl->status == streaming_stopped_e &&
|
|
|
|
(!s->end_pos || s->pos == s->end_pos))
|
|
|
|
s->eof = 1;
|
|
|
|
} else {
|
|
|
|
if (s->fill_buffer)
|
|
|
|
len = s->fill_buffer(s, buf, len);
|
|
|
|
else
|
|
|
|
len = read(s->fd, buf, len);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
len = s->fill_buffer ? s->fill_buffer(s, buf, len) : 0;
|
|
|
|
}
|
|
|
|
if (len <= 0) {
|
|
|
|
// 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 19:14:06 +00: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 16:49:09 +00:00
|
|
|
return stream_read_unbuffered(s, buf, orig_len);
|
2011-07-04 19:21:59 +00:00
|
|
|
|
|
|
|
eof_out:
|
2013-01-24 16:43:07 +00:00
|
|
|
s->eof = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// When reading succeeded we are obviously not at eof.
|
|
|
|
// This e.g. avoids issues with eof getting stuck when lavf seeks in MPEG-TS
|
|
|
|
s->eof = 0;
|
|
|
|
s->pos += len;
|
|
|
|
return len;
|
2010-10-27 19:04:04 +00:00
|
|
|
}
|
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
int stream_fill_buffer(stream_t *s)
|
|
|
|
{
|
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 16:49:09 +00:00
|
|
|
int len = stream_read_unbuffered(s, s->buffer, STREAM_BUFFER_SIZE);
|
2013-01-24 16:43:07 +00:00
|
|
|
if (len <= 0)
|
|
|
|
return 0;
|
|
|
|
s->buf_pos = 0;
|
|
|
|
s->buf_len = len;
|
2001-02-24 20:28:24 +00:00
|
|
|
// printf("[%d]",len);fflush(stdout);
|
2013-05-11 20:19:33 +00:00
|
|
|
stream_capture_write(s);
|
2013-01-24 16:43:07 +00:00
|
|
|
return len;
|
2001-02-24 20:28:24 +00:00
|
|
|
}
|
|
|
|
|
2013-05-24 09:56:49 +00:00
|
|
|
int stream_read(stream_t *s, char *mem, int total)
|
|
|
|
{
|
|
|
|
int len = total;
|
|
|
|
while (len > 0) {
|
|
|
|
int x;
|
|
|
|
x = s->buf_len - s->buf_pos;
|
|
|
|
if (x == 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 16:49:09 +00:00
|
|
|
if (!stream_fill_buffer(s))
|
2013-05-24 09:56:49 +00:00
|
|
|
return total - len; // EOF
|
|
|
|
x = s->buf_len - s->buf_pos;
|
|
|
|
}
|
|
|
|
if (s->buf_pos > s->buf_len)
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_WARN,
|
|
|
|
"stream_read: WARNING! s->buf_pos>s->buf_len\n");
|
|
|
|
if (x > len)
|
|
|
|
x = len;
|
|
|
|
memcpy(mem, &s->buffer[s->buf_pos], x);
|
|
|
|
s->buf_pos += x;
|
|
|
|
mem += x;
|
|
|
|
len -= x;
|
|
|
|
}
|
|
|
|
return total;
|
|
|
|
}
|
|
|
|
|
2013-01-24 16:43:07 +00: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 20:56:24 +00: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 16:49:09 +00:00
|
|
|
// Seek function bypassing the local stream buffer.
|
|
|
|
int stream_seek_unbuffered(stream_t *s, int64_t newpos)
|
2010-10-27 19:04:04 +00:00
|
|
|
{
|
2013-01-24 16:43:07 +00:00
|
|
|
if (newpos == 0 || newpos != s->pos) {
|
|
|
|
switch (s->type) {
|
|
|
|
case STREAMTYPE_STREAM:
|
|
|
|
//s->pos=newpos; // real seek
|
|
|
|
// Some streaming protocol allow to seek backward and forward
|
|
|
|
// A function call that return -1 can tell that the protocol
|
|
|
|
// doesn't support seeking.
|
2010-07-17 13:14:53 +00:00
|
|
|
#ifdef CONFIG_NETWORKING
|
2013-01-24 16:43:07 +00:00
|
|
|
if (s->seek) { // new stream seek is much cleaner than streaming_ctrl one
|
|
|
|
if (!s->seek(s, newpos)) {
|
|
|
|
mp_tmsg(MSGT_STREAM, MSGL_ERR, "Seek failed\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s->streaming_ctrl != NULL &&
|
|
|
|
s->streaming_ctrl->streaming_seek) {
|
|
|
|
if (s->streaming_ctrl->streaming_seek(s->fd, newpos,
|
|
|
|
s->streaming_ctrl) < 0) {
|
|
|
|
mp_tmsg(MSGT_STREAM, MSGL_INFO, "Stream not seekable!\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2009-11-17 18:08:18 +00:00
|
|
|
#endif
|
2013-01-24 16:43:07 +00:00
|
|
|
if (newpos < s->pos) {
|
|
|
|
mp_tmsg(MSGT_STREAM, MSGL_INFO,
|
|
|
|
"Cannot seek backward in linear streams!\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// This should at the beginning as soon as all streams are converted
|
|
|
|
if (!s->seek)
|
|
|
|
return 0;
|
|
|
|
// Now seek
|
|
|
|
if (!s->seek(s, newpos)) {
|
|
|
|
mp_tmsg(MSGT_STREAM, MSGL_ERR, "Seek failed\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2001-02-24 20:28:24 +00:00
|
|
|
// putchar('.');fflush(stdout);
|
|
|
|
//} else {
|
|
|
|
// putchar('%');fflush(stdout);
|
2013-01-24 16:43:07 +00:00
|
|
|
}
|
|
|
|
return -1;
|
2010-10-27 19:04:04 +00: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 16:49:09 +00: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 16:43:07 +00:00
|
|
|
{
|
|
|
|
int res;
|
|
|
|
int64_t newpos = 0;
|
2010-10-27 19:04:04 +00:00
|
|
|
|
|
|
|
// if( mp_msg_test(MSGT_STREAM,MSGL_DBG3) ) printf("seek_long to 0x%X\n",(unsigned int)pos);
|
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
s->buf_pos = s->buf_len = 0;
|
2010-10-27 19:04:04 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
if (s->mode == STREAM_WRITE) {
|
|
|
|
if (!s->seek || !s->seek(s, pos))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
2010-10-27 19:04:04 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
if (s->sector_size)
|
|
|
|
newpos = (pos / s->sector_size) * s->sector_size;
|
|
|
|
else
|
|
|
|
newpos = pos & (~((int64_t)STREAM_BUFFER_SIZE - 1));
|
|
|
|
|
2013-06-05 00:08:56 +00:00
|
|
|
mp_msg(MSGT_STREAM, MSGL_DBG3, "s->pos=%" PRIX64 " newpos=%" PRIX64
|
|
|
|
" new_bufpos=%" PRIX64 " buflen=%X \n",
|
|
|
|
(int64_t)s->pos, (int64_t)newpos, (int64_t)pos, s->buf_len);
|
2013-01-24 16:43:07 +00:00
|
|
|
pos -= newpos;
|
2010-10-27 19:04:04 +00: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 16:49:09 +00:00
|
|
|
res = stream_seek_unbuffered(s, newpos);
|
2013-01-24 16:43:07 +00:00
|
|
|
if (res >= 0)
|
|
|
|
return res;
|
2010-10-27 19:04:04 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
while (s->pos < newpos) {
|
|
|
|
if (stream_fill_buffer(s) <= 0)
|
|
|
|
break; // EOF
|
|
|
|
}
|
2001-02-24 20:28:24 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
s->eof = 0; // EOF reset when seek succeeds.
|
|
|
|
while (stream_fill_buffer(s) > 0) {
|
|
|
|
if (pos <= s->buf_len) {
|
|
|
|
s->buf_pos = pos; // byte position in sector
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
pos -= s->buf_len;
|
|
|
|
}
|
2010-01-18 12:38:56 +00:00
|
|
|
// Fill failed, but seek still is a success.
|
2013-01-24 16:43:07 +00:00
|
|
|
s->pos += pos;
|
|
|
|
s->buf_pos = 0;
|
|
|
|
s->buf_len = 0;
|
2010-01-18 12:38:56 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
mp_msg(MSGT_STREAM, MSGL_V,
|
|
|
|
"stream_seek: Seek to/past EOF: no buffer preloaded.\n");
|
|
|
|
return 1;
|
2001-02-24 20:28:24 +00:00
|
|
|
}
|
|
|
|
|
2013-05-24 09:56:49 +00:00
|
|
|
int stream_seek(stream_t *s, int64_t pos)
|
|
|
|
{
|
|
|
|
|
|
|
|
mp_dbg(MSGT_DEMUX, MSGL_DBG3, "seek to 0x%llX\n", (long long)pos);
|
|
|
|
|
|
|
|
if (pos < 0) {
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_ERR,
|
|
|
|
"Invalid seek to negative position %llx!\n",
|
|
|
|
(long long)pos);
|
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
if (pos < s->pos) {
|
|
|
|
int64_t x = pos - (s->pos - s->buf_len);
|
|
|
|
if (x >= 0) {
|
|
|
|
s->buf_pos = x;
|
|
|
|
s->eof = 0;
|
|
|
|
// putchar('*');fflush(stdout);
|
|
|
|
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 16:49:09 +00:00
|
|
|
return stream_seek_long(s, pos);
|
2013-05-24 09:56:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int stream_skip(stream_t *s, int64_t len)
|
|
|
|
{
|
|
|
|
if (len < 0 ||
|
|
|
|
(len > 2 * STREAM_BUFFER_SIZE && (s->flags & MP_STREAM_SEEK_FW))) {
|
|
|
|
// negative or big skip!
|
|
|
|
return stream_seek(s, stream_tell(s) + len);
|
|
|
|
}
|
|
|
|
while (len > 0) {
|
|
|
|
int x = s->buf_len - s->buf_pos;
|
|
|
|
if (x == 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 16:49:09 +00:00
|
|
|
if (!stream_fill_buffer(s))
|
2013-05-24 09:56:49 +00:00
|
|
|
return 0; // EOF
|
|
|
|
x = s->buf_len - s->buf_pos;
|
|
|
|
}
|
|
|
|
if (x > len)
|
|
|
|
x = len;
|
|
|
|
//memcpy(mem,&s->buf[s->buf_pos],x);
|
|
|
|
s->buf_pos += x;
|
|
|
|
len -= x;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2001-02-24 20:28:24 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
void stream_reset(stream_t *s)
|
|
|
|
{
|
|
|
|
if (s->eof) {
|
|
|
|
s->pos = 0;
|
|
|
|
s->buf_pos = s->buf_len = 0;
|
|
|
|
s->eof = 0;
|
|
|
|
}
|
2001-02-24 20:28:24 +00:00
|
|
|
}
|
|
|
|
|
2013-01-24 16:43:07 +00: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 21:06:47 +00:00
|
|
|
}
|
|
|
|
|
2012-11-18 20:23:17 +00:00
|
|
|
void stream_update_size(stream_t *s)
|
|
|
|
{
|
|
|
|
uint64_t size;
|
|
|
|
if (stream_control(s, STREAM_CTRL_GET_SIZE, &size) == STREAM_OK) {
|
|
|
|
if (size > s->end_pos)
|
|
|
|
s->end_pos = 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 16:49:09 +00:00
|
|
|
static stream_t *new_stream(void)
|
2013-01-24 16:43:07 +00:00
|
|
|
{
|
|
|
|
stream_t *s = talloc_zero(NULL, stream_t);
|
2003-06-11 16:48:09 +00:00
|
|
|
|
2009-02-01 13:42:27 +00:00
|
|
|
#if HAVE_WINSOCK2_H
|
2013-01-24 16:43:07 +00:00
|
|
|
{
|
|
|
|
WSADATA wsdata;
|
|
|
|
int temp = WSAStartup(0x0202, &wsdata); // there might be a better place for this (-> later)
|
|
|
|
mp_msg(MSGT_STREAM, MSGL_V, "WINSOCK2 init: %i\n", temp);
|
|
|
|
}
|
2003-06-11 16:48:09 +00:00
|
|
|
#endif
|
2009-07-06 23:26:13 +00: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 16:49:09 +00:00
|
|
|
s->fd = -2;
|
|
|
|
s->type = -2;
|
2013-01-24 16:43:07 +00:00
|
|
|
return s;
|
2001-02-24 20:28:24 +00:00
|
|
|
}
|
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
void free_stream(stream_t *s)
|
|
|
|
{
|
2013-05-11 20:19:33 +00:00
|
|
|
stream_set_capture_file(s, NULL);
|
2010-11-02 01:17:41 +00:00
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
if (s->close)
|
|
|
|
s->close(s);
|
|
|
|
if (s->fd > 0) {
|
|
|
|
/* on unix we define closesocket to close
|
|
|
|
on windows however we have to distinguish between
|
|
|
|
network socket and file */
|
|
|
|
if (s->url && strstr(s->url, "://"))
|
|
|
|
closesocket(s->fd);
|
|
|
|
else
|
|
|
|
close(s->fd);
|
|
|
|
}
|
2009-02-01 13:42:27 +00:00
|
|
|
#if HAVE_WINSOCK2_H
|
2013-01-24 16:43:07 +00:00
|
|
|
mp_msg(MSGT_STREAM, MSGL_V, "WINSOCK2 uninit\n");
|
|
|
|
WSACleanup(); // there might be a better place for this (-> later)
|
2003-06-11 16:48:09 +00:00
|
|
|
#endif
|
2013-01-24 16:43:07 +00:00
|
|
|
free(s->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 16:49:09 +00:00
|
|
|
if (s->uncached_stream)
|
|
|
|
free_stream(s->uncached_stream);
|
2013-01-24 16:43:07 +00:00
|
|
|
talloc_free(s);
|
2001-02-24 20:28:24 +00:00
|
|
|
}
|
|
|
|
|
2008-04-30 04:15:52 +00:00
|
|
|
void stream_set_interrupt_callback(int (*cb)(struct input_ctx *, int),
|
|
|
|
struct input_ctx *ctx)
|
|
|
|
{
|
2008-04-09 00:36:28 +00:00
|
|
|
stream_check_interrupt_cb = cb;
|
2008-04-30 04:15:52 +00:00
|
|
|
stream_check_interrupt_ctx = ctx;
|
2008-04-09 00:36:28 +00:00
|
|
|
}
|
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
int stream_check_interrupt(int time)
|
|
|
|
{
|
|
|
|
if (!stream_check_interrupt_cb) {
|
2013-05-25 17:56:52 +00:00
|
|
|
mp_sleep_us(time * 1000);
|
2010-05-28 18:49:02 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2008-04-30 04:15:52 +00:00
|
|
|
return stream_check_interrupt_cb(stream_check_interrupt_ctx, time);
|
2008-04-09 00:36:28 +00:00
|
|
|
}
|
2010-02-28 13:54:55 +00: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 16:49:09 +00:00
|
|
|
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 *
|
|
|
|
(stream_cache_min_percent / 100.0),
|
|
|
|
stream_cache_size * 1024 *
|
|
|
|
(stream_cache_seek_min_percent / 100.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \return 1 on success, 0 if the function was interrupted and -1 on error, or
|
|
|
|
* if the cache is disabled
|
|
|
|
*/
|
|
|
|
int stream_enable_cache(stream_t **stream, int64_t size, int64_t min,
|
|
|
|
int64_t seek_limit)
|
|
|
|
{
|
|
|
|
stream_t *orig = *stream;
|
|
|
|
|
|
|
|
if (orig->mode != STREAM_READ)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
// Can't handle a loaded buffer.
|
|
|
|
orig->buf_len = orig->buf_pos = 0;
|
|
|
|
|
|
|
|
stream_t *cache = new_stream();
|
|
|
|
cache->type = STREAMTYPE_CACHE;
|
|
|
|
cache->uncached_type = orig->type;
|
|
|
|
cache->uncached_stream = orig;
|
|
|
|
cache->flags |= MP_STREAM_SEEK;
|
|
|
|
cache->mode = STREAM_READ;
|
|
|
|
|
|
|
|
cache->read_chunk = orig->read_chunk;
|
|
|
|
cache->url = strdup(orig->url);
|
|
|
|
cache->mime_type = talloc_strdup(cache, orig->mime_type);
|
|
|
|
cache->lavf_type = orig->lavf_type;
|
|
|
|
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;
|
|
|
|
|
|
|
|
int res = -1;
|
|
|
|
|
|
|
|
#ifdef CONFIG_STREAM_CACHE
|
|
|
|
res = stream_cache_init(cache, orig, size, min, seek_limit);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (res <= 0) {
|
|
|
|
cache->uncached_stream = NULL; // don't free original stream
|
|
|
|
free_stream(cache);
|
|
|
|
} else {
|
|
|
|
*stream = cache;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2010-02-28 15:24:30 +00:00
|
|
|
/**
|
|
|
|
* Helper function to read 16 bits little-endian and advance pointer
|
|
|
|
*/
|
|
|
|
static uint16_t get_le16_inc(const uint8_t **buf)
|
|
|
|
{
|
2013-01-24 16:43:07 +00:00
|
|
|
uint16_t v = AV_RL16(*buf);
|
|
|
|
*buf += 2;
|
|
|
|
return v;
|
2010-02-28 15:24:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper function to read 16 bits big-endian and advance pointer
|
|
|
|
*/
|
|
|
|
static uint16_t get_be16_inc(const uint8_t **buf)
|
|
|
|
{
|
2013-01-24 16:43:07 +00:00
|
|
|
uint16_t v = AV_RB16(*buf);
|
|
|
|
*buf += 2;
|
|
|
|
return v;
|
2010-02-28 15:24:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find a newline character in buffer
|
|
|
|
* \param buf buffer to search
|
|
|
|
* \param len amount of bytes to search in buffer, may not overread
|
|
|
|
* \param utf16 chose between UTF-8/ASCII/other and LE and BE UTF-16
|
|
|
|
* 0 = UTF-8/ASCII/other, 1 = UTF-16-LE, 2 = UTF-16-BE
|
|
|
|
*/
|
|
|
|
static const uint8_t *find_newline(const uint8_t *buf, int len, int utf16)
|
|
|
|
{
|
2013-01-24 16:43:07 +00:00
|
|
|
uint32_t c;
|
|
|
|
const uint8_t *end = buf + len;
|
|
|
|
switch (utf16) {
|
|
|
|
case 0:
|
|
|
|
return (uint8_t *)memchr(buf, '\n', len);
|
|
|
|
case 1:
|
|
|
|
while (buf < end - 1) {
|
2013-03-19 00:27:48 +00:00
|
|
|
GET_UTF16(c, buf < end - 1 ? get_le16_inc(&buf) : 0, return NULL;)
|
2013-01-24 16:43:07 +00:00
|
|
|
if (buf <= end && c == '\n')
|
|
|
|
return buf - 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
while (buf < end - 1) {
|
2013-03-19 00:27:48 +00:00
|
|
|
GET_UTF16(c, buf < end - 1 ? get_be16_inc(&buf) : 0, return NULL;)
|
2013-01-24 16:43:07 +00:00
|
|
|
if (buf <= end && c == '\n')
|
|
|
|
return buf - 1;
|
|
|
|
}
|
|
|
|
break;
|
2010-02-28 15:24:30 +00:00
|
|
|
}
|
2013-01-24 16:43:07 +00:00
|
|
|
return NULL;
|
2010-02-28 15:24:30 +00:00
|
|
|
}
|
|
|
|
|
2013-03-19 00:27:48 +00:00
|
|
|
#define EMPTY_STMT do{}while(0);
|
|
|
|
|
2010-02-28 15:24:30 +00:00
|
|
|
/**
|
|
|
|
* Copy a number of bytes, converting to UTF-8 if input is UTF-16
|
|
|
|
* \param dst buffer to copy to
|
|
|
|
* \param dstsize size of dst buffer
|
|
|
|
* \param src buffer to copy from
|
|
|
|
* \param len amount of bytes to copy from src
|
|
|
|
* \param utf16 chose between UTF-8/ASCII/other and LE and BE UTF-16
|
|
|
|
* 0 = UTF-8/ASCII/other, 1 = UTF-16-LE, 2 = UTF-16-BE
|
|
|
|
*/
|
|
|
|
static int copy_characters(uint8_t *dst, int dstsize,
|
|
|
|
const uint8_t *src, int *len, int utf16)
|
|
|
|
{
|
2013-01-24 16:43:07 +00:00
|
|
|
uint32_t c;
|
|
|
|
uint8_t *dst_end = dst + dstsize;
|
|
|
|
const uint8_t *end = src + *len;
|
|
|
|
switch (utf16) {
|
|
|
|
case 0:
|
|
|
|
if (*len > dstsize)
|
|
|
|
*len = dstsize;
|
|
|
|
memcpy(dst, src, *len);
|
|
|
|
return *len;
|
|
|
|
case 1:
|
|
|
|
while (src < end - 1 && dst_end - dst > 8) {
|
|
|
|
uint8_t tmp;
|
2013-03-19 00:27:48 +00:00
|
|
|
GET_UTF16(c, src < end - 1 ? get_le16_inc(&src) : 0, EMPTY_STMT)
|
|
|
|
PUT_UTF8(c, tmp, *dst++ = tmp; EMPTY_STMT)
|
2013-01-24 16:43:07 +00:00
|
|
|
}
|
|
|
|
*len -= end - src;
|
|
|
|
return dstsize - (dst_end - dst);
|
|
|
|
case 2:
|
|
|
|
while (src < end - 1 && dst_end - dst > 8) {
|
|
|
|
uint8_t tmp;
|
2013-03-19 00:27:48 +00:00
|
|
|
GET_UTF16(c, src < end - 1 ? get_be16_inc(&src) : 0, EMPTY_STMT)
|
|
|
|
PUT_UTF8(c, tmp, *dst++ = tmp; EMPTY_STMT)
|
2013-01-24 16:43:07 +00:00
|
|
|
}
|
|
|
|
*len -= end - src;
|
|
|
|
return dstsize - (dst_end - dst);
|
2010-02-28 15:24:30 +00:00
|
|
|
}
|
2013-01-24 16:43:07 +00:00
|
|
|
return 0;
|
2010-02-28 15:24:30 +00:00
|
|
|
}
|
|
|
|
|
2013-01-24 16:43:07 +00:00
|
|
|
unsigned char *stream_read_line(stream_t *s, unsigned char *mem, int max,
|
|
|
|
int utf16)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
const unsigned char *end;
|
|
|
|
unsigned char *ptr = mem;
|
|
|
|
if (max < 1)
|
|
|
|
return NULL;
|
|
|
|
max--; // reserve one for 0-termination
|
|
|
|
do {
|
|
|
|
len = s->buf_len - s->buf_pos;
|
|
|
|
// try to fill the buffer
|
|
|
|
if (len <= 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 16:49:09 +00:00
|
|
|
(!stream_fill_buffer(s) ||
|
2013-01-24 16:43:07 +00:00
|
|
|
(len = s->buf_len - s->buf_pos) <= 0))
|
|
|
|
break;
|
|
|
|
end = find_newline(s->buffer + s->buf_pos, len, utf16);
|
|
|
|
if (end)
|
|
|
|
len = end - (s->buffer + s->buf_pos) + 1;
|
|
|
|
if (len > 0 && max > 0) {
|
|
|
|
int l = copy_characters(ptr, max, s->buffer + s->buf_pos, &len,
|
|
|
|
utf16);
|
|
|
|
max -= l;
|
|
|
|
ptr += l;
|
|
|
|
if (!len)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
s->buf_pos += len;
|
|
|
|
} while (!end);
|
|
|
|
ptr[0] = 0;
|
|
|
|
if (s->eof && ptr == mem)
|
|
|
|
return NULL;
|
|
|
|
return mem;
|
2010-02-28 13:54:55 +00:00
|
|
|
}
|
2011-02-25 16:10:00 +00:00
|
|
|
|
|
|
|
struct bstr stream_read_complete(struct stream *s, void *talloc_ctx,
|
|
|
|
int max_size, int padding_bytes)
|
|
|
|
{
|
|
|
|
if (max_size > 1000000000)
|
|
|
|
abort();
|
|
|
|
|
|
|
|
int bufsize;
|
|
|
|
int total_read = 0;
|
|
|
|
int padding = FFMAX(padding_bytes, 1);
|
|
|
|
char *buf = NULL;
|
|
|
|
if (s->end_pos > max_size)
|
2013-01-24 16:43:07 +00:00
|
|
|
return (struct bstr){
|
|
|
|
NULL, 0
|
|
|
|
};
|
2011-02-25 16:10:00 +00: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-01-24 16:43:07 +00:00
|
|
|
return (struct bstr){
|
|
|
|
NULL, 0
|
|
|
|
};
|
2011-02-25 16:10:00 +00:00
|
|
|
}
|
|
|
|
bufsize = FFMIN(bufsize + (bufsize >> 1), max_size + padding);
|
|
|
|
}
|
|
|
|
buf = talloc_realloc_size(talloc_ctx, buf, total_read + padding);
|
2013-01-24 16:43:07 +00:00
|
|
|
return (struct bstr){
|
|
|
|
buf, total_read
|
|
|
|
};
|
2011-02-25 16:10:00 +00:00
|
|
|
}
|
2013-05-03 17:52:28 +00:00
|
|
|
|
|
|
|
bool stream_manages_timeline(struct stream *s)
|
|
|
|
{
|
|
|
|
return stream_control(s, STREAM_CTRL_MANAGES_TIMELINE, NULL) == STREAM_OK;
|
|
|
|
}
|