diff options
Diffstat (limited to 'stream')
-rw-r--r-- | stream/ai_alsa1x.c | 6 | ||||
-rw-r--r-- | stream/ai_oss.c | 9 | ||||
-rw-r--r-- | stream/ai_sndio.c | 5 | ||||
-rw-r--r-- | stream/audio_in.c | 14 | ||||
-rw-r--r-- | stream/stream_libarchive.c | 197 | ||||
-rw-r--r-- | stream/stream_libarchive.h | 2 |
6 files changed, 202 insertions, 31 deletions
diff --git a/stream/ai_alsa1x.c b/stream/ai_alsa1x.c index c5dc84cfcc..8f2b774faf 100644 --- a/stream/ai_alsa1x.c +++ b/stream/ai_alsa1x.c @@ -134,7 +134,11 @@ int ai_alsa_init(audio_in_t *ai) { int err; - err = snd_pcm_open(&ai->alsa.handle, ai->alsa.device, SND_PCM_STREAM_CAPTURE, 0); + const char *device = ai->alsa.device; + if (!device) + device = "default"; + + err = snd_pcm_open(&ai->alsa.handle, device, SND_PCM_STREAM_CAPTURE, 0); if (err < 0) { MP_ERR(ai, "Error opening audio: %s\n", snd_strerror(err)); return -1; diff --git a/stream/ai_oss.c b/stream/ai_oss.c index 0362f207dc..d1ef701e6e 100644 --- a/stream/ai_oss.c +++ b/stream/ai_oss.c @@ -87,11 +87,14 @@ int ai_oss_init(audio_in_t *ai) int err; int ioctl_param; - ai->oss.audio_fd = open(ai->oss.device, O_RDONLY | O_CLOEXEC); + const char *device = ai->oss.device; + if (!device) + device = "/dev/dsp"; + + ai->oss.audio_fd = open(device, O_RDONLY | O_CLOEXEC); if (ai->oss.audio_fd < 0) { - MP_ERR(ai, "Unable to open '%s': %s\n", - ai->oss.device, mp_strerror(errno)); + MP_ERR(ai, "Unable to open '%s': %s\n", device, mp_strerror(errno)); return -1; } diff --git a/stream/ai_sndio.c b/stream/ai_sndio.c index 2bb47955a4..10e95cea62 100644 --- a/stream/ai_sndio.c +++ b/stream/ai_sndio.c @@ -38,7 +38,10 @@ int ai_sndio_init(audio_in_t *ai) { int err; - if ((ai->sndio.hdl = sio_open(ai->sndio.device, SIO_REC, 0)) == NULL) { + const char *device = ai->sndio.device; + if (!device) + device = "default"; + if ((ai->sndio.hdl = sio_open(device, SIO_REC, 0)) == NULL) { MP_ERR(ai, "could not open sndio audio"); return -1; } diff --git a/stream/audio_in.c b/stream/audio_in.c index 90b036f814..8ed92767c1 100644 --- a/stream/audio_in.c +++ b/stream/audio_in.c @@ -45,19 +45,19 @@ int audio_in_init(audio_in_t *ai, struct mp_log *log, int type) case AUDIO_IN_ALSA: ai->alsa.handle = NULL; ai->alsa.log = NULL; - ai->alsa.device = strdup("default"); + ai->alsa.device = NULL; return 0; #endif #if HAVE_OSS_AUDIO case AUDIO_IN_OSS: ai->oss.audio_fd = -1; - ai->oss.device = strdup("/dev/dsp"); + ai->oss.device = NULL; return 0; #endif #if HAVE_SNDIO case AUDIO_IN_SNDIO: ai->sndio.hdl = NULL; - ai->sndio.device = strdup("default"); + ai->sndio.device = NULL; return 0; #endif default: @@ -161,9 +161,11 @@ int audio_in_set_device(audio_in_t *ai, char *device) case AUDIO_IN_ALSA: free(ai->alsa.device); ai->alsa.device = strdup(device); - /* mplayer cannot handle colons in arguments */ - for (i = 0; i < (int)strlen(ai->alsa.device); i++) { - if (ai->alsa.device[i] == '.') ai->alsa.device[i] = ':'; + if (ai->alsa.device) { + /* mplayer could not handle colons in arguments */ + for (i = 0; i < (int)strlen(ai->alsa.device); i++) { + if (ai->alsa.device[i] == '.') ai->alsa.device[i] = ':'; + } } return 0; #endif diff --git a/stream/stream_libarchive.c b/stream/stream_libarchive.c index 116488d551..a164da85b8 100644 --- a/stream/stream_libarchive.c +++ b/stream/stream_libarchive.c @@ -18,47 +18,112 @@ #include <archive.h> #include <archive_entry.h> +#include "misc/bstr.h" #include "common/common.h" #include "stream.h" #include "stream_libarchive.h" +struct mp_archive_volume { + struct mp_archive *mpa; + struct stream *src; + int64_t seek_to; + char *url; +}; + +static bool volume_seek(struct mp_archive_volume *vol) +{ + if (vol->seek_to < 0) + return true; + bool r = stream_seek(vol->src, vol->seek_to); + vol->seek_to = -1; + return r; +} + static ssize_t read_cb(struct archive *arch, void *priv, const void **buffer) { - struct mp_archive *mpa = priv; - int res = stream_read_partial(mpa->src, mpa->buffer, sizeof(mpa->buffer)); - *buffer = mpa->buffer; + struct mp_archive_volume *vol = priv; + if (!volume_seek(vol)) + return -1; + int res = stream_read_partial(vol->src, vol->mpa->buffer, + sizeof(vol->mpa->buffer)); + *buffer = vol->mpa->buffer; return MPMAX(res, 0); } +// lazy seek to avoid problems with end seeking over http static int64_t seek_cb(struct archive *arch, void *priv, int64_t offset, int whence) { - struct mp_archive *mpa = priv; + struct mp_archive_volume *vol = priv; switch (whence) { case SEEK_SET: + vol->seek_to = offset; break; case SEEK_CUR: - offset += mpa->src->pos; + if (vol->seek_to < 0) + vol->seek_to = stream_tell(vol->src); + vol->seek_to += offset; break; case SEEK_END: ; - int64_t size = stream_get_size(mpa->src); + int64_t size = stream_get_size(vol->src); if (size < 0) return -1; - offset += size; + vol->seek_to = size + offset; break; default: return -1; } - return stream_seek(mpa->src, offset) ? offset : -1; + return vol->seek_to; } static int64_t skip_cb(struct archive *arch, void *priv, int64_t request) { - struct mp_archive *mpa = priv; - int64_t old = stream_tell(mpa->src); - stream_skip(mpa->src, request); - return stream_tell(mpa->src) - old; + struct mp_archive_volume *vol = priv; + if (!volume_seek(vol)) + return -1; + int64_t old = stream_tell(vol->src); + stream_skip(vol->src, request); + return stream_tell(vol->src) - old; +} + +static int open_cb(struct archive *arch, void *priv) +{ + struct mp_archive_volume *vol = priv; + vol->seek_to = -1; + if (!vol->src) { + vol->src = stream_create(vol->url, STREAM_READ, + vol->mpa->primary_src->cancel, + vol->mpa->primary_src->global); + return vol->src ? ARCHIVE_OK : ARCHIVE_FATAL; + } + + // just rewind the primary stream + return stream_seek(vol->src, 0) ? ARCHIVE_OK : ARCHIVE_FATAL; +} + +static void volume_close(struct mp_archive_volume *vol) +{ + // don't close the primary stream + if (vol->src && vol->src != vol->mpa->primary_src) { + free_stream(vol->src); + vol->src = NULL; + } +} + +static int close_cb(struct archive *arch, void *priv) +{ + struct mp_archive_volume *vol = priv; + volume_close(vol); + talloc_free(vol); + return ARCHIVE_OK; +} + +static int switch_cb(struct archive *arch, void *oldpriv, void *newpriv) +{ + struct mp_archive_volume *oldvol = oldpriv; + volume_close(oldvol); + return open_cb(arch, newpriv); } void mp_archive_free(struct mp_archive *mpa) @@ -70,16 +135,108 @@ void mp_archive_free(struct mp_archive *mpa) talloc_free(mpa); } +static char *standard_volume_url(void *ctx, const char *format, + struct bstr base, int index) +{ + return talloc_asprintf(ctx, format, BSTR_P(base), index); +} + +static char *old_rar_volume_url(void *ctx, const char *format, + struct bstr base, int index) +{ + return talloc_asprintf(ctx, format, BSTR_P(base), + 'r' + index / 100, index % 100); +} + +struct file_pattern { + const char *match; + const char *format; + char *(*volume_url)(void *ctx, const char *format, + struct bstr base, int index); + int start; + int stop; +}; + +static const struct file_pattern patterns[] = { + { ".part1.rar", "%.*s.part%.1d.rar", standard_volume_url, 2, 9 }, + { ".part01.rar", "%.*s.part%.2d.rar", standard_volume_url, 2, 99 }, + { ".part001.rar", "%.*s.part%.3d.rar", standard_volume_url, 2, 999 }, + { ".part0001.rar", "%.*s.part%.4d.rar", standard_volume_url, 2, 9999 }, + { ".rar", "%.*s.%c%.2d", old_rar_volume_url, 0, 9999 }, + { ".001", "%.*s.%.3d", standard_volume_url, 2, 9999 }, + { NULL, NULL, NULL, 0, 0 }, +}; + +static char **find_volumes(struct stream *primary_stream) +{ + char **res = talloc_new(NULL); + int num = 0; + struct bstr primary_url = bstr0(primary_stream->url); + + const struct file_pattern *pattern = patterns; + while (pattern->match) { + if (bstr_endswith0(primary_url, pattern->match)) + break; + pattern++; + } + + if (!pattern->match) + goto done; + + struct bstr base = bstr_splice(primary_url, 0, -strlen(pattern->match)); + for (int i = pattern->start; i <= pattern->stop; i++) { + char* url = pattern->volume_url(res, pattern->format, base, i); + struct stream *s = stream_create(url, STREAM_READ | STREAM_SAFE_ONLY, + primary_stream->cancel, + primary_stream->global); + if (!s) { + talloc_free(url); + goto done; + } + free_stream(s); + MP_TARRAY_APPEND(res, res, num, url); + } + +done: + MP_TARRAY_APPEND(res, res, num, NULL); + return res; +} + + +static bool add_volume(struct mp_log *log, struct mp_archive *mpa, + struct stream *src, const char* url) +{ + struct mp_archive_volume *vol = talloc_zero(mpa, struct mp_archive_volume); + mp_verbose(log, "Adding volume %s\n", url); + vol->mpa = mpa; + vol->src = src; + vol->url = talloc_strdup(vol, url); + return archive_read_append_callback_data(mpa->arch, vol) == ARCHIVE_OK; +} + struct mp_archive *mp_archive_new(struct mp_log *log, struct stream *src, int flags) { struct mp_archive *mpa = talloc_zero(NULL, struct mp_archive); - mpa->src = src; - stream_seek(mpa->src, 0); mpa->arch = archive_read_new(); + mpa->primary_src = src; if (!mpa->arch) goto err; + // first volume is the primary streame + if (!add_volume(log ,mpa, src, src->url)) + goto err; + + // try to open other volumes + char** volumes = find_volumes(src); + for (int i = 0; volumes[i]; i++) { + if (!add_volume(log, mpa, NULL, volumes[i])) { + talloc_free(volumes); + goto err; + } + } + talloc_free(volumes); + archive_read_support_format_7zip(mpa->arch); archive_read_support_format_iso9660(mpa->arch); archive_read_support_format_rar(mpa->arch); @@ -92,10 +249,12 @@ struct mp_archive *mp_archive_new(struct mp_log *log, struct stream *src, archive_read_support_format_tar(mpa->arch); } - archive_read_set_callback_data(mpa->arch, mpa); archive_read_set_read_callback(mpa->arch, read_cb); archive_read_set_skip_callback(mpa->arch, skip_cb); - if (mpa->src->seekable) + archive_read_set_switch_callback(mpa->arch, switch_cb); + archive_read_set_open_callback(mpa->arch, open_cb); + archive_read_set_close_callback(mpa->arch, close_cb); + if (mpa->primary_src->seekable) archive_read_set_seek_callback(mpa->arch, seek_cb); if (archive_read_open1(mpa->arch) < ARCHIVE_OK) goto err; @@ -132,7 +291,7 @@ static int reopen_archive(stream_t *s) goto error; } if (r < ARCHIVE_OK) - MP_ERR(s, "libarchive: %s\n", archive_error_string(mpa->arch)); + MP_ERR(s, "%s\n", archive_error_string(mpa->arch)); if (r < ARCHIVE_WARN) goto error; if (archive_entry_filetype(entry) != AE_IFREG) @@ -166,7 +325,7 @@ static int archive_entry_fill_buffer(stream_t *s, char *buffer, int max_len) return 0; int r = archive_read_data(p->mpa->arch, buffer, max_len); if (r < 0) - MP_ERR(s, "libarchive: %s\n", archive_error_string(p->mpa->arch)); + MP_ERR(s, "%s\n", archive_error_string(p->mpa->arch)); return r; } @@ -194,7 +353,7 @@ static int archive_entry_seek(stream_t *s, int64_t newpos) int size = MPMIN(newpos - s->pos, sizeof(buffer)); int r = archive_read_data(p->mpa->arch, buffer, size); if (r < 0) { - MP_ERR(s, "libarchive: %s\n", archive_error_string(p->mpa->arch)); + MP_ERR(s, "%s\n", archive_error_string(p->mpa->arch)); return -1; } s->pos += r; diff --git a/stream/stream_libarchive.h b/stream/stream_libarchive.h index f69faade72..ebded5b5ba 100644 --- a/stream/stream_libarchive.h +++ b/stream/stream_libarchive.h @@ -2,7 +2,7 @@ struct mp_log; struct mp_archive { struct archive *arch; - struct stream *src; + struct stream *primary_src; char buffer[4096]; }; |