3 * Copyright (c) 2001 Fabrice Bellard
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
22 #include "libavutil/avstring.h"
23 #include "libavutil/internal.h"
24 #include "libavutil/opt.h"
35 #include "os_support.h"
38 /* Some systems may not have S_ISFIFO */
41 # define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
43 # define S_ISFIFO(m) 0
47 /* standard file protocol */
49 typedef struct FileContext
{
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
},
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
},
67 static const AVClass file_class
= {
69 .item_name
= av_default_item_name
,
70 .option
= file_options
,
71 .version
= LIBAVUTIL_VERSION_INT
,
74 static const AVClass pipe_class
= {
76 .item_name
= av_default_item_name
,
77 .option
= pipe_options
,
78 .version
= LIBAVUTIL_VERSION_INT
,
81 static int file_read(URLContext
*h
, unsigned char *buf
, int size
)
83 FileContext
*c
= h
->priv_data
;
85 size
= FFMIN(size
, c
->blocksize
);
86 r
= read(c
->fd
, buf
, size
);
87 return (-1 == r
)?AVERROR(errno
):r
;
90 static int file_write(URLContext
*h
, const unsigned char *buf
, int size
)
92 FileContext
*c
= h
->priv_data
;
94 size
= FFMIN(size
, c
->blocksize
);
95 r
= write(c
->fd
, buf
, size
);
96 return (-1 == r
)?AVERROR(errno
):r
;
99 static int file_get_handle(URLContext
*h
)
101 FileContext
*c
= h
->priv_data
;
105 static int file_check(URLContext
*h
, int mask
)
108 const char *filename
= h
->filename
;
109 av_strstart(filename
, "file:", &filename
);
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
;
123 ret
= stat(filename
, &st
);
125 return AVERROR(errno
);
127 ret
|= st
.st_mode
&S_IRUSR
? mask
&AVIO_FLAG_READ
: 0;
128 ret
|= st
.st_mode
&S_IWUSR
? mask
&AVIO_FLAG_WRITE
: 0;
134 #if CONFIG_FILE_PROTOCOL
136 static int file_open(URLContext
*h
, const char *filename
, int flags
)
138 FileContext
*c
= h
->priv_data
;
143 av_strstart(filename
, "file:", &filename
);
145 if (flags
& AVIO_FLAG_WRITE
&& flags
& AVIO_FLAG_READ
) {
146 access
= O_CREAT
| O_RDWR
;
149 } else if (flags
& AVIO_FLAG_WRITE
) {
150 access
= O_CREAT
| O_WRONLY
;
159 fd
= avpriv_open(filename
, access
, 0666);
161 return AVERROR(errno
);
164 h
->is_streamed
= !fstat(fd
, &st
) && S_ISFIFO(st
.st_mode
);
169 /* XXX: use llseek */
170 static int64_t file_seek(URLContext
*h
, int64_t pos
, int whence
)
172 FileContext
*c
= h
->priv_data
;
175 if (whence
== AVSEEK_SIZE
) {
177 ret
= fstat(c
->fd
, &st
);
178 return ret
< 0 ? AVERROR(errno
) : (S_ISFIFO(st
.st_mode
) ? 0 : st
.st_size
);
181 ret
= lseek(c
->fd
, pos
, whence
);
183 return ret
< 0 ? AVERROR(errno
) : ret
;
186 static int file_close(URLContext
*h
)
188 FileContext
*c
= h
->priv_data
;
192 URLProtocol ff_file_protocol
= {
194 .url_open
= file_open
,
195 .url_read
= file_read
,
196 .url_write
= file_write
,
197 .url_seek
= file_seek
,
198 .url_close
= file_close
,
199 .url_get_file_handle
= file_get_handle
,
200 .url_check
= file_check
,
201 .priv_data_size
= sizeof(FileContext
),
202 .priv_data_class
= &file_class
,
205 #endif /* CONFIG_FILE_PROTOCOL */
207 #if CONFIG_PIPE_PROTOCOL
209 static int pipe_open(URLContext
*h
, const char *filename
, int flags
)
211 FileContext
*c
= h
->priv_data
;
214 av_strstart(filename
, "pipe:", &filename
);
216 fd
= strtol(filename
, &final
, 10);
217 if((filename
== final
) || *final
) {/* No digits found, or something like 10ab */
218 if (flags
& AVIO_FLAG_WRITE
) {
225 setmode(fd
, O_BINARY
);
232 URLProtocol ff_pipe_protocol
= {
234 .url_open
= pipe_open
,
235 .url_read
= file_read
,
236 .url_write
= file_write
,
237 .url_get_file_handle
= file_get_handle
,
238 .url_check
= file_check
,
239 .priv_data_size
= sizeof(FileContext
),
240 .priv_data_class
= &pipe_class
,
243 #endif /* CONFIG_PIPE_PROTOCOL */