]> git.sesse.net Git - ffmpeg/blob - libavformat/file.c
electronicarts: move video stream properties into dedicated structure
[ffmpeg] / libavformat / file.c
1 /*
2  * buffered file I/O
3  * Copyright (c) 2001 Fabrice Bellard
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
22 #include "libavutil/avstring.h"
23 #include "libavutil/internal.h"
24 #include "libavutil/opt.h"
25 #include "avformat.h"
26 #include <fcntl.h>
27 #if HAVE_IO_H
28 #include <io.h>
29 #endif
30 #if HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #include <sys/stat.h>
34 #include <stdlib.h>
35 #include "os_support.h"
36 #include "url.h"
37
38 /* Some systems may not have S_ISFIFO */
39 #ifndef S_ISFIFO
40 #  ifdef S_IFIFO
41 #    define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
42 #  else
43 #    define S_ISFIFO(m) 0
44 #  endif
45 #endif
46
47 /* standard file protocol */
48
49 typedef struct FileContext {
50     const AVClass *class;
51     int fd;
52     int trunc;
53     int blocksize;
54 } FileContext;
55
56 static const AVOption file_options[] = {
57     { "truncate", "truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
58     { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
59     { NULL }
60 };
61
62 static const AVOption pipe_options[] = {
63     { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
64     { NULL }
65 };
66
67 static const AVClass file_class = {
68     .class_name = "file",
69     .item_name  = av_default_item_name,
70     .option     = file_options,
71     .version    = LIBAVUTIL_VERSION_INT,
72 };
73
74 static const AVClass pipe_class = {
75     .class_name = "pipe",
76     .item_name  = av_default_item_name,
77     .option     = pipe_options,
78     .version    = LIBAVUTIL_VERSION_INT,
79 };
80
81 static int file_read(URLContext *h, unsigned char *buf, int size)
82 {
83     FileContext *c = h->priv_data;
84     int r;
85     size = FFMIN(size, c->blocksize);
86     r = read(c->fd, buf, size);
87     return (-1 == r)?AVERROR(errno):r;
88 }
89
90 static int file_write(URLContext *h, const unsigned char *buf, int size)
91 {
92     FileContext *c = h->priv_data;
93     int r;
94     size = FFMIN(size, c->blocksize);
95     r = write(c->fd, buf, size);
96     return (-1 == r)?AVERROR(errno):r;
97 }
98
99 static int file_get_handle(URLContext *h)
100 {
101     FileContext *c = h->priv_data;
102     return c->fd;
103 }
104
105 static int file_check(URLContext *h, int mask)
106 {
107     int ret = 0;
108     const char *filename = h->filename;
109     av_strstart(filename, "file:", &filename);
110
111     {
112 #if HAVE_ACCESS && defined(R_OK)
113     if (access(filename, F_OK) < 0)
114         return AVERROR(errno);
115     if (mask&AVIO_FLAG_READ)
116         if (access(filename, R_OK) >= 0)
117             ret |= AVIO_FLAG_READ;
118     if (mask&AVIO_FLAG_WRITE)
119         if (access(filename, W_OK) >= 0)
120             ret |= AVIO_FLAG_WRITE;
121 #else
122     struct stat st;
123     ret = stat(filename, &st);
124     if (ret < 0)
125         return AVERROR(errno);
126
127     ret |= st.st_mode&S_IRUSR ? mask&AVIO_FLAG_READ  : 0;
128     ret |= st.st_mode&S_IWUSR ? mask&AVIO_FLAG_WRITE : 0;
129 #endif
130     }
131     return ret;
132 }
133
134 static int file_delete(URLContext *h)
135 {
136 #if HAVE_UNISTD_H
137     int ret;
138     const char *filename = h->filename;
139     av_strstart(filename, "file:", &filename);
140
141     ret = rmdir(filename);
142     if (ret < 0 && errno == ENOTDIR)
143         ret = unlink(filename);
144     if (ret < 0)
145         return AVERROR(errno);
146
147     return ret;
148 #else
149     return AVERROR(ENOSYS);
150 #endif /* HAVE_UNISTD_H */
151 }
152
153 static int file_move(URLContext *h_src, URLContext *h_dst)
154 {
155 #if HAVE_UNISTD_H
156     const char *filename_src = h_src->filename;
157     const char *filename_dst = h_dst->filename;
158     av_strstart(filename_src, "file:", &filename_src);
159     av_strstart(filename_dst, "file:", &filename_src);
160
161     if (rename(filename_src, filename_dst) < 0)
162         return AVERROR(errno);
163
164     return 0;
165 #else
166     return AVERROR(ENOSYS);
167 #endif /* HAVE_UNISTD_H */
168 }
169
170 #if CONFIG_FILE_PROTOCOL
171
172 static int file_open(URLContext *h, const char *filename, int flags)
173 {
174     FileContext *c = h->priv_data;
175     int access;
176     int fd;
177     struct stat st;
178
179     av_strstart(filename, "file:", &filename);
180
181     if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) {
182         access = O_CREAT | O_RDWR;
183         if (c->trunc)
184             access |= O_TRUNC;
185     } else if (flags & AVIO_FLAG_WRITE) {
186         access = O_CREAT | O_WRONLY;
187         if (c->trunc)
188             access |= O_TRUNC;
189     } else {
190         access = O_RDONLY;
191     }
192 #ifdef O_BINARY
193     access |= O_BINARY;
194 #endif
195     fd = avpriv_open(filename, access, 0666);
196     if (fd == -1)
197         return AVERROR(errno);
198     c->fd = fd;
199
200     h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode);
201
202     return 0;
203 }
204
205 /* XXX: use llseek */
206 static int64_t file_seek(URLContext *h, int64_t pos, int whence)
207 {
208     FileContext *c = h->priv_data;
209     int64_t ret;
210
211     if (whence == AVSEEK_SIZE) {
212         struct stat st;
213         ret = fstat(c->fd, &st);
214         return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size);
215     }
216
217     ret = lseek(c->fd, pos, whence);
218
219     return ret < 0 ? AVERROR(errno) : ret;
220 }
221
222 static int file_close(URLContext *h)
223 {
224     FileContext *c = h->priv_data;
225     return close(c->fd);
226 }
227
228 URLProtocol ff_file_protocol = {
229     .name                = "file",
230     .url_open            = file_open,
231     .url_read            = file_read,
232     .url_write           = file_write,
233     .url_seek            = file_seek,
234     .url_close           = file_close,
235     .url_get_file_handle = file_get_handle,
236     .url_check           = file_check,
237     .url_delete          = file_delete,
238     .url_move            = file_move,
239     .priv_data_size      = sizeof(FileContext),
240     .priv_data_class     = &file_class,
241 };
242
243 #endif /* CONFIG_FILE_PROTOCOL */
244
245 #if CONFIG_PIPE_PROTOCOL
246
247 static int pipe_open(URLContext *h, const char *filename, int flags)
248 {
249     FileContext *c = h->priv_data;
250     int fd;
251     char *final;
252     av_strstart(filename, "pipe:", &filename);
253
254     fd = strtol(filename, &final, 10);
255     if((filename == final) || *final ) {/* No digits found, or something like 10ab */
256         if (flags & AVIO_FLAG_WRITE) {
257             fd = 1;
258         } else {
259             fd = 0;
260         }
261     }
262 #if HAVE_SETMODE
263     setmode(fd, O_BINARY);
264 #endif
265     c->fd = fd;
266     h->is_streamed = 1;
267     return 0;
268 }
269
270 URLProtocol ff_pipe_protocol = {
271     .name                = "pipe",
272     .url_open            = pipe_open,
273     .url_read            = file_read,
274     .url_write           = file_write,
275     .url_get_file_handle = file_get_handle,
276     .url_check           = file_check,
277     .priv_data_size      = sizeof(FileContext),
278     .priv_data_class     = &pipe_class,
279 };
280
281 #endif /* CONFIG_PIPE_PROTOCOL */