2 * Input cache protocol.
3 * Copyright (c) 2011 Michael Niedermayer
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Based on file.c by Fabrice Bellard
26 * support non continuous caching
27 * support keeping files
28 * support filling with a background thread
31 #include "libavutil/avassert.h"
32 #include "libavutil/avstring.h"
33 #include "libavutil/file.h"
44 #include "os_support.h"
47 typedef struct Context {
54 static int cache_open(URLContext *h, const char *arg, int flags)
57 Context *c= h->priv_data;
59 av_strstart(arg, "cache:", &arg);
61 c->fd = av_tempfile("ffcache", &buffername, 0, h);
63 av_log(h, AV_LOG_ERROR, "Failed to create tempfile\n");
68 av_freep(&buffername);
70 return ffurl_open(&c->inner, arg, flags, &h->interrupt_callback, NULL);
73 static int cache_read(URLContext *h, unsigned char *buf, int size)
75 Context *c= h->priv_data;
79 r = read(c->fd, buf, FFMIN(size, c->end - c->pos));
82 return (-1 == r)?AVERROR(errno):r;
84 r = ffurl_read(c->inner, buf, size);
86 int r2= write(c->fd, buf, r);
87 av_assert0(r2==r); // FIXME handle cache failure
95 static int64_t cache_seek(URLContext *h, int64_t pos, int whence)
97 Context *c= h->priv_data;
99 if (whence == AVSEEK_SIZE) {
100 pos= ffurl_seek(c->inner, pos, whence);
102 pos= ffurl_seek(c->inner, -1, SEEK_END);
103 ffurl_seek(c->inner, c->end, SEEK_SET);
110 pos= lseek(c->fd, pos, whence);
113 }else if(pos <= c->end){
117 if(lseek(c->fd, c->pos, SEEK_SET) < 0) {
118 av_log(h, AV_LOG_ERROR, "Failure to seek in cache\n");
120 return AVERROR(EPIPE);
124 static int cache_close(URLContext *h)
126 Context *c= h->priv_data;
128 ffurl_close(c->inner);
133 URLProtocol ff_cache_protocol = {
135 .url_open = cache_open,
136 .url_read = cache_read,
137 .url_seek = cache_seek,
138 .url_close = cache_close,
139 .priv_data_size = sizeof(Context),