Imported Debian version 2.4.3~trusty1
[deb_ffmpeg.git] / ffmpeg / libavformat / cache.c
CommitLineData
2ba45a60
DM
1/*
2 * Input cache protocol.
3 * Copyright (c) 2011 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 non continuous caching
27 * support keeping files
28 * support filling with a background thread
29 */
30
31#include "libavutil/avassert.h"
32#include "libavutil/avstring.h"
33#include "libavutil/file.h"
34#include "avformat.h"
35#include <fcntl.h>
36#if HAVE_IO_H
37#include <io.h>
38#endif
39#if HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42#include <sys/stat.h>
43#include <stdlib.h>
44#include "os_support.h"
45#include "url.h"
46
47typedef struct Context {
48 int fd;
49 int64_t end;
50 int64_t pos;
51 URLContext *inner;
52} Context;
53
54static int cache_open(URLContext *h, const char *arg, int flags)
55{
56 char *buffername;
57 Context *c= h->priv_data;
58
59 av_strstart(arg, "cache:", &arg);
60
61 c->fd = av_tempfile("ffcache", &buffername, 0, h);
62 if (c->fd < 0){
63 av_log(h, AV_LOG_ERROR, "Failed to create tempfile\n");
64 return c->fd;
65 }
66
67 unlink(buffername);
68 av_freep(&buffername);
69
70 return ffurl_open(&c->inner, arg, flags, &h->interrupt_callback, NULL);
71}
72
73static int cache_read(URLContext *h, unsigned char *buf, int size)
74{
75 Context *c= h->priv_data;
76 int r;
77
78 if(c->pos<c->end){
79 r = read(c->fd, buf, FFMIN(size, c->end - c->pos));
80 if(r>0)
81 c->pos += r;
82 return (-1 == r)?AVERROR(errno):r;
83 }else{
84 r = ffurl_read(c->inner, buf, size);
85 if(r > 0){
86 int r2= write(c->fd, buf, r);
87 av_assert0(r2==r); // FIXME handle cache failure
88 c->pos += r;
89 c->end += r;
90 }
91 return r;
92 }
93}
94
95static int64_t cache_seek(URLContext *h, int64_t pos, int whence)
96{
97 Context *c= h->priv_data;
98
99 if (whence == AVSEEK_SIZE) {
100 pos= ffurl_seek(c->inner, pos, whence);
101 if(pos <= 0){
102 pos= ffurl_seek(c->inner, -1, SEEK_END);
103 ffurl_seek(c->inner, c->end, SEEK_SET);
104 if(pos <= 0)
105 return c->end;
106 }
107 return pos;
108 }
109
110 pos= lseek(c->fd, pos, whence);
111 if(pos<0){
112 return pos;
113 }else if(pos <= c->end){
114 c->pos= pos;
115 return pos;
116 }else{
117 if(lseek(c->fd, c->pos, SEEK_SET) < 0) {
118 av_log(h, AV_LOG_ERROR, "Failure to seek in cache\n");
119 }
120 return AVERROR(EPIPE);
121 }
122}
123
124static int cache_close(URLContext *h)
125{
126 Context *c= h->priv_data;
127 close(c->fd);
128 ffurl_close(c->inner);
129
130 return 0;
131}
132
133URLProtocol ff_cache_protocol = {
134 .name = "cache",
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),
140};