From e9f62a8b2bb7f675d21dace520e62c55bc8996a9 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Sun, 16 Oct 2011 16:02:35 +0200 Subject: add cache protocol This allows backward seeking on top of some non seekable streams. Signed-off-by: Michael Niedermayer --- libavformat/cache.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 libavformat/cache.c (limited to 'libavformat/cache.c') 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 +#if HAVE_SETMODE +#include +#endif +#include +#include +#include +#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->posend){ + 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, +}; -- cgit v1.2.3