1 /*
2 * Input cache protocol.
3 * Copyright (c) 2011,2014 Michael Niedermayer
4 *
5 * This file is part of FFmpeg.
6 *
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.
11 *
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.
16 *
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
20 *
21 * Based on file.c by Fabrice Bellard
22 */
23
24 /**
25 * @TODO
26 * support keeping files
27 * support filling with a background thread
28 */
29
36 #include <fcntl.h>
37 #if HAVE_IO_H
38 #include <io.h>
39 #endif
40 #if HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #include <sys/stat.h>
44 #include <stdlib.h>
47
53
67
68 static int cmp(
const void *key,
const void *node)
69 {
71 }
72
74 {
75 char *buffername;
77
79
84 }
85
86 unlink(buffername);
88
91 }
92
94 {
96 int64_t pos = -1;
97 int ret;
101
102 //FIXME avoid lseek
103 pos = lseek(c->
fd, 0, SEEK_END);
104 if (pos < 0) {
108 }
110
111 ret = write(c->
fd, buf, size);
112 if (ret < 0) {
116 }
118
120
121 if (!entry)
122 entry = next[0];
123
124 if (!entry ||
127 ) {
130 if (!entry || !node) {
133 }
137
139 if (entry_ret && entry_ret != entry) {
140 ret = -1;
143 }
144 } else
146
147 return 0;
149 //we could truncate the file to pos here if pos >=0 but ftruncate isn't available in VS so
150 //for simplicty we just leave the file a bit larger
153 return ret;
154 }
155
157 {
161
163
164 if (!entry)
165 entry = next[0];
166
167 if (entry) {
170 if (in_block_pos < entry->size) {
171 int64_t physical_target = entry->
physical_pos + in_block_pos;
172
174 r = lseek(c->
fd, physical_target, SEEK_SET);
175 } else
177
178 if (r >= 0) {
180 r = read(c->
fd, buf,
FFMIN(size, entry->
size - in_block_pos));
181 }
182
183 if (r > 0) {
188 }
189 }
190 }
191
192 // Cache miss or some kind of fault with the cache
193
196 if (r<0) {
199 }
201 }
202
204 if (r == 0 && size>0) {
207 }
208 if (r<=0)
211
213
217
219 }
220
222 {
224 int64_t ret;
225
228 if(pos <= 0){
232 }
233 if (pos > 0)
236 return pos;
237 }
238
239 if (whence == SEEK_CUR) {
240 whence = SEEK_SET;
243 resolve_eof:
244 whence = SEEK_SET;
246 }
247
248 if (whence == SEEK_SET && pos >= 0 && pos < c->
end) {
249 //Seems within filesize, assume it will not fail.
251 return pos;
252 }
253
254 //cache miss
256 if ((whence == SEEK_SET && pos >= c->
logical_pos ||
257 whence == SEEK_END && pos <= 0) && ret < 0) {
261 while (c->
logical_pos < pos || whence == SEEK_END) {
263 if (whence == SEEK_SET)
266 if (ret == 0 && whence == SEEK_END) {
268 goto resolve_eof;
269 }
270 if (ret < 0) {
271 return ret;
272 }
273 }
275 }
276 }
277
278 if (ret >= 0) {
281 }
282
283 return ret;
284 }
285
287 {
289 return 0;
290 }
291
293 {
295
296 av_log(h,
AV_LOG_INFO,
"Statistics, cache hits:%"PRId64
" cache misses:%"PRId64
"\n",
298
303
304 return 0;
305 }
306
307 #define OFFSET(x) offsetof(Context, x)
308 #define D AV_OPT_FLAG_DECODING_PARAM
309
311 {
"read_ahead_limit",
"Amount in bytes that may be read ahead when seeking isn't supported, -1 for unlimited",
OFFSET(read_ahead_limit),
AV_OPT_TYPE_INT, { .i64 = 65536 }, -1, INT_MAX,
D },
313 };
314
320 };
321
328 .priv_data_size =
sizeof(
Context),
329 .priv_data_class = &cache_context_class,
330 };
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist, const char *blacklist, URLContext *parent)
Create an URLContext for accessing to the resource indicated by url, and open it. ...
support keeping files support filling with a background thread
#define LIBAVUTIL_VERSION_INT
AVIOInterruptCB interrupt_callback
static const AVClass cache_context_class
int avpriv_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx)
Wrapper to work around the lack of mkstemp() on mingw.
void * av_tree_find(const AVTreeNode *t, void *key, int(*cmp)(const void *key, const void *b), void *next[2])
static const AVOption options[]
struct AVTreeNode * av_tree_node_alloc(void)
Allocate an AVTreeNode.
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
#define av_assert0(cond)
assert() equivalent, that is always enabled.
const URLProtocol ff_cache_protocol
static int enu_free(void *opaque, void *elem)
miscellaneous OS support macros and functions.
static av_cold int end(AVCodecContext *avctx)
void av_tree_destroy(AVTreeNode *t)
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
const char * protocol_whitelist
simple assert() macros that are a bit more flexible than ISO C assert().
static int cache_open(URLContext *h, const char *arg, int flags, AVDictionary **options)
#define FFDIFFSIGN(x, y)
Comparator.
common internal API header
static int cache_close(URLContext *h)
static int cmp(const void *key, const void *node)
static int64_t cache_seek(URLContext *h, int64_t pos, int whence)
#define AV_LOG_INFO
Standard information.
const char * protocol_blacklist
static int cache_read(URLContext *h, unsigned char *buf, int size)
Describe the class of an AVClass context structure.
int ffurl_close(URLContext *h)
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
Change the position that will be used by the next read/write operation on the resource accessed by h...
#define AVSEEK_SIZE
ORing this as the "whence" parameter to a seek function causes it to return the filesize without seek...
static int add_entry(URLContext *h, const unsigned char *buf, int size)
void * av_tree_insert(AVTreeNode **tp, void *key, int(*cmp)(const void *key, const void *b), AVTreeNode **next)
Insert or remove an element.
unbuffered private I/O API
void av_tree_enumerate(AVTreeNode *t, void *opaque, int(*cmp)(void *opaque, void *elem), int(*enu)(void *opaque, void *elem))
Apply enu(opaque, &elem) to all the elements in the tree in a given range.
int ffurl_read(URLContext *h, unsigned char *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf...