qt: playlist: use item title if available
[vlc.git] / modules / access_output / file.c
blob9e7e5c2f6b8898a4bb029c59c614ced006faec06
1 /*****************************************************************************
2 * file.c
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 VLC authors and VideoLAN
6 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7 * Eric Petit <titer@videolan.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <assert.h>
33 #include <sys/types.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #ifdef __OS2__
39 # include <io.h> /* setmode() */
40 #endif
42 #include <vlc_common.h>
43 #include <vlc_plugin.h>
44 #include <vlc_sout.h>
45 #include <vlc_block.h>
46 #include <vlc_fs.h>
47 #include <vlc_network.h>
48 #include <vlc_strings.h>
49 #include <vlc_dialog.h>
51 #ifndef O_LARGEFILE
52 # define O_LARGEFILE 0
53 #endif
54 #ifndef _POSIX_REALTIME_SIGNALS
55 # define _POSIX_REALTIME_SIGNALS (-1)
56 #endif
58 #define SOUT_CFG_PREFIX "sout-file-"
60 /*****************************************************************************
61 * Read: standard read on a file descriptor.
62 *****************************************************************************/
63 static ssize_t Read( sout_access_out_t *p_access, block_t *p_buffer )
65 int *fdp = p_access->p_sys, fd = *fdp;
66 ssize_t val;
69 val = read(fd, p_buffer->p_buffer, p_buffer->i_buffer);
70 while (val == -1 && errno == EINTR);
71 return val;
74 /*****************************************************************************
75 * Write: standard write on a file descriptor.
76 *****************************************************************************/
77 static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
79 int *fdp = p_access->p_sys, fd = *fdp;
80 size_t i_write = 0;
82 while( p_buffer )
84 ssize_t val = write(fd, p_buffer->p_buffer, p_buffer->i_buffer);
85 if (val <= 0)
87 if (errno == EINTR)
88 continue;
89 block_ChainRelease (p_buffer);
90 msg_Err( p_access, "cannot write: %s", vlc_strerror_c(errno) );
91 return -1;
94 if ((size_t)val >= p_buffer->i_buffer)
96 block_t *p_next = p_buffer->p_next;
97 block_Release (p_buffer);
98 p_buffer = p_next;
100 else
102 p_buffer->p_buffer += val;
103 p_buffer->i_buffer -= val;
105 i_write += val;
107 return i_write;
110 static ssize_t WritePipe(sout_access_out_t *access, block_t *block)
112 int *fdp = access->p_sys, fd = *fdp;
113 ssize_t total = 0;
115 while (block != NULL)
117 if (block->i_buffer == 0)
119 block_t *next = block->p_next;
120 block_Release(block);
121 block = next;
122 continue;
125 /* TODO: vectorized I/O with writev() */
126 ssize_t val = vlc_write(fd, block->p_buffer, block->i_buffer);
127 if (val < 0)
129 if (errno == EINTR)
130 continue;
132 block_ChainRelease(block);
133 msg_Err(access, "cannot write: %s", vlc_strerror_c(errno));
134 total = -1;
135 break;
138 total += val;
140 assert((size_t)val <= block->i_buffer);
141 block->p_buffer += val;
142 block->i_buffer -= val;
145 return total;
148 #ifdef S_ISSOCK
149 static ssize_t Send(sout_access_out_t *access, block_t *block)
151 int *fdp = access->p_sys, fd = *fdp;
152 size_t total = 0;
154 while (block != NULL)
156 if (block->i_buffer == 0)
158 block_t *next = block->p_next;
159 block_Release(block);
160 block = next;
161 continue;
164 /* TODO: vectorized I/O with sendmsg() */
165 ssize_t val = vlc_send(fd, block->p_buffer, block->i_buffer, 0);
166 if (val <= 0)
167 { /* FIXME: errno is meaningless if val is zero */
168 if (errno == EINTR)
169 continue;
170 block_ChainRelease(block);
171 msg_Err(access, "cannot write: %s", vlc_strerror_c(errno));
172 return -1;
175 total += val;
177 assert((size_t)val <= block->i_buffer);
178 block->p_buffer += val;
179 block->i_buffer -= val;
181 return total;
183 #endif
185 /*****************************************************************************
186 * Seek: seek to a specific location in a file
187 *****************************************************************************/
188 static int Seek( sout_access_out_t *p_access, off_t i_pos )
190 int *fdp = p_access->p_sys, fd = *fdp;
192 return lseek(fd, i_pos, SEEK_SET);
195 static int Control( sout_access_out_t *p_access, int i_query, va_list args )
197 switch( i_query )
199 case ACCESS_OUT_CONTROLS_PACE:
201 bool *pb = va_arg( args, bool * );
202 *pb = strcmp( p_access->psz_access, "stream" );
203 break;
206 case ACCESS_OUT_CAN_SEEK:
208 bool *pb = va_arg( args, bool * );
209 *pb = p_access->pf_seek != NULL;
210 break;
213 default:
214 return VLC_EGENERIC;
216 return VLC_SUCCESS;
219 static const char *const ppsz_sout_options[] = {
220 "append",
221 "format",
222 "overwrite",
223 #ifdef O_SYNC
224 "sync",
225 #endif
226 NULL
229 /*****************************************************************************
230 * Open: open the file
231 *****************************************************************************/
232 static int Open( vlc_object_t *p_this )
234 sout_access_out_t *p_access = (sout_access_out_t*)p_this;
235 int fd;
236 int *fdp = vlc_obj_malloc(p_this, sizeof (*fdp));
238 if (unlikely(fdp == NULL))
239 return VLC_ENOMEM;
241 config_ChainParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg );
243 bool overwrite = var_GetBool (p_access, SOUT_CFG_PREFIX"overwrite");
244 bool append = var_GetBool( p_access, SOUT_CFG_PREFIX "append" );
246 if (!strcmp (p_access->psz_access, "fd"))
248 char *end;
250 fd = strtol (p_access->psz_path, &end, 0);
251 if (!*p_access->psz_path || *end)
253 msg_Err (p_access, "invalid file descriptor: %s",
254 p_access->psz_path);
255 return VLC_EGENERIC;
257 fd = vlc_dup (fd);
258 if (fd == -1)
260 msg_Err (p_access, "cannot use file descriptor: %s",
261 vlc_strerror_c(errno));
262 return VLC_EGENERIC;
265 else
266 if( !strcmp( p_access->psz_path, "-" ) )
268 #if defined( _WIN32 ) || defined( __OS2__ )
269 setmode (STDOUT_FILENO, O_BINARY);
270 #endif
271 fd = vlc_dup (STDOUT_FILENO);
272 if (fd == -1)
274 msg_Err (p_access, "cannot use standard output: %s",
275 vlc_strerror_c(errno));
276 return VLC_EGENERIC;
278 msg_Dbg( p_access, "using stdout" );
280 else
282 const char *path = p_access->psz_path;
283 char *buf = NULL;
285 if (var_InheritBool (p_access, SOUT_CFG_PREFIX"format"))
287 buf = vlc_strftime (path);
288 path = buf;
291 int flags = O_RDWR | O_CREAT | O_LARGEFILE;
292 if (!overwrite)
293 flags |= O_EXCL;
294 if (!append)
295 flags |= O_TRUNC;
296 #ifdef O_SYNC
297 if (var_GetBool (p_access, SOUT_CFG_PREFIX"sync"))
298 flags |= O_SYNC;
299 #endif
302 fd = vlc_open (path, flags, 0666);
303 if (fd != -1)
304 break;
305 if (fd == -1)
306 msg_Err (p_access, "cannot create %s: %s", path,
307 vlc_strerror_c(errno));
308 if (overwrite || errno != EEXIST)
309 break;
310 flags &= ~O_EXCL;
312 while (vlc_dialog_wait_question (p_access, VLC_DIALOG_QUESTION_NORMAL,
313 _("Keep existing file"),
314 _("Overwrite"), NULL, path,
315 _("The output file already exists. "
316 "If recording continues, the file will be "
317 "overridden and its content will be lost.")) == 1);
318 free (buf);
319 if (fd == -1)
320 return VLC_EGENERIC;
323 *fdp = fd;
324 p_access->p_sys = fdp;
326 struct stat st;
328 if (fstat (fd, &st))
330 msg_Err (p_access, "write error: %s", vlc_strerror_c(errno));
331 vlc_close (fd);
332 return VLC_EGENERIC;
335 p_access->pf_read = Read;
337 if (S_ISREG(st.st_mode) || S_ISBLK(st.st_mode))
339 p_access->pf_write = Write;
340 p_access->pf_seek = Seek;
342 #ifdef S_ISSOCK
343 else if (S_ISSOCK(st.st_mode))
345 p_access->pf_write = Send;
346 p_access->pf_seek = NULL;
348 #endif
349 else
351 p_access->pf_write = WritePipe;
352 p_access->pf_seek = NULL;
354 p_access->pf_control = Control;
356 msg_Dbg( p_access, "file access output opened (%s)", p_access->psz_path );
357 if (append)
358 lseek (fd, 0, SEEK_END);
360 return VLC_SUCCESS;
363 /*****************************************************************************
364 * Close: close the target
365 *****************************************************************************/
366 static void Close( vlc_object_t * p_this )
368 sout_access_out_t *p_access = (sout_access_out_t*)p_this;
369 int *fdp = p_access->p_sys, fd = *fdp;
371 vlc_close(fd);
372 msg_Dbg( p_access, "file access output closed" );
375 #define OVERWRITE_TEXT N_("Overwrite existing file")
376 #define OVERWRITE_LONGTEXT N_( \
377 "If the file already exists, it will be overwritten.")
378 #define APPEND_TEXT N_("Append to file")
379 #define APPEND_LONGTEXT N_( "Append to file if it exists instead " \
380 "of replacing it.")
381 #define FORMAT_TEXT N_("Format time and date")
382 #define FORMAT_LONGTEXT N_("Perform ISO C time and date formatting " \
383 "on the file path")
384 #define SYNC_TEXT N_("Synchronous writing")
385 #define SYNC_LONGTEXT N_( "Open the file with synchronous writing.")
387 vlc_module_begin ()
388 set_description( N_("File stream output") )
389 set_shortname( N_("File" ))
390 set_capability( "sout access", 50 )
391 set_category( CAT_SOUT )
392 set_subcategory( SUBCAT_SOUT_ACO )
393 add_shortcut( "file", "stream", "fd" )
394 add_bool( SOUT_CFG_PREFIX "overwrite", true, OVERWRITE_TEXT,
395 OVERWRITE_LONGTEXT, true )
396 add_bool( SOUT_CFG_PREFIX "append", false, APPEND_TEXT,APPEND_LONGTEXT,
397 true )
398 add_bool( SOUT_CFG_PREFIX "format", false, FORMAT_TEXT, FORMAT_LONGTEXT,
399 true )
400 #ifdef O_SYNC
401 add_bool( SOUT_CFG_PREFIX "sync", false, SYNC_TEXT,SYNC_LONGTEXT,
402 false )
403 #endif
404 set_callbacks( Open, Close )
405 vlc_module_end ()