diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2011-10-16 16:02:35 +0200 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2011-10-16 17:12:37 +0200 |
commit | e9f62a8b2bb7f675d21dace520e62c55bc8996a9 (patch) | |
tree | 066a686e037ba350ad95092547d6bb9e570e312d | |
parent | 5746f910362f888ecb00efb0a3706ac2ee484019 (diff) | |
download | ffmpeg-e9f62a8b2bb7f675d21dace520e62c55bc8996a9.tar.gz |
add cache protocol
This allows backward seeking on top of some non seekable streams.
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r-- | libavformat/Makefile | 1 | ||||
-rw-r--r-- | libavformat/allformats.c | 1 | ||||
-rw-r--r-- | libavformat/cache.c | 130 |
3 files changed, 132 insertions, 0 deletions
diff --git a/libavformat/Makefile b/libavformat/Makefile index fc75517e31..813ea1de51 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -333,6 +333,7 @@ OBJS-$(CONFIG_LIBNUT_MUXER) += libnut.o riff.o OBJS+= avio.o aviobuf.o OBJS-$(CONFIG_APPLEHTTP_PROTOCOL) += applehttpproto.o +OBJS-$(CONFIG_CACHE_PROTOCOL) += cache.o OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o OBJS-$(CONFIG_FILE_PROTOCOL) += file.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 7a07b44b7f..5c629149a3 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -249,6 +249,7 @@ void av_register_all(void) /* protocols */ REGISTER_PROTOCOL (APPLEHTTP, applehttp); + REGISTER_PROTOCOL (CACHE, cache); REGISTER_PROTOCOL (CONCAT, concat); REGISTER_PROTOCOL (CRYPTO, crypto); REGISTER_PROTOCOL (FILE, file); diff --git a/libavformat/cache.c b/libavformat/cache.c new file mode 100644 index 0000000000..bbc85925c2 --- /dev/null +++ b/libavformat/cache.c @@ -0,0 +1,130 @@ +/* + * Input cache protocol. + * Copyright (c) 2011 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Based on file.c by Fabrice Bellard + */ + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/file.h" +#include "avformat.h" +#include <fcntl.h> +#if HAVE_SETMODE +#include <io.h> +#endif +#include <unistd.h> +#include <sys/stat.h> +#include <stdlib.h> +#include "os_support.h" +#include "url.h" + +typedef struct Context { + int fd; + int64_t end; + int64_t pos; + URLContext *inner; +} Context; + +static int cache_open(URLContext *h, const char *arg, int flags) +{ + int access; + const char *buffername; + Context *c; + + c = av_mallocz(sizeof(Context)); + if (!c) { + return AVERROR(ENOMEM); + } + h->priv_data = c; + + av_strstart(arg, "cache:", &arg); + + c->fd = av_tempfile("ffcache", &buffername); + if (c->fd < 0){ + av_log(h, AV_LOG_ERROR, "Failed to create tempfile\n"); + return c->fd; + } + + unlink(buffername); + av_free(buffername); + + return ffurl_open(&c->inner, arg, flags); +} + +static int cache_read(URLContext *h, unsigned char *buf, int size) +{ + Context *c= h->priv_data; + int r; + + if(c->pos<c->end){ + r = read(c->fd, buf, FFMIN(size, c->end - c->pos)); + if(r>0) + c->pos += r; + return (-1 == r)?AVERROR(errno):r; + }else{ + r = ffurl_read(c->inner, buf, size); + if(r > 0){ + int r2= write(c->fd, buf, r); + av_assert0(r2==r); // FIXME handle cache failure + c->pos += r; + c->end += r; + } + return r; + } +} + +static int64_t cache_seek(URLContext *h, int64_t pos, int whence) +{ + Context *c= h->priv_data; + + if (whence == AVSEEK_SIZE) { + return ffurl_seek(c->inner, pos, whence); + } + + pos= lseek(c->fd, pos, whence); + if(pos<0){ + return pos; + }else if(pos <= c->end){ + c->pos= pos; + return pos; + }else{ + lseek(c->fd, c->pos, SEEK_SET); + return AVERROR(EPIPE); + } +} + +static int cache_close(URLContext *h) +{ + Context *c= h->priv_data; + close(c->fd); + ffurl_close(c->inner); + + av_freep(&h->priv_data); + + return 0; +} + +URLProtocol ff_cache_protocol = { + .name = "cache", + .url_open = cache_open, + .url_read = cache_read, + .url_seek = cache_seek, + .url_close = cache_close, +}; |