1 /*****************************************************************************
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 /*****************************************************************************
26 *****************************************************************************/
34 #include <sys/types.h>
40 # include <io.h> /* setmode() */
43 #include <vlc_common.h>
44 #include <vlc_plugin.h>
46 #include <vlc_block.h>
48 #include <vlc_network.h>
49 #include <vlc_strings.h>
50 #include <vlc_dialog.h>
53 # define O_LARGEFILE 0
55 #ifndef _POSIX_REALTIME_SIGNALS
56 # define _POSIX_REALTIME_SIGNALS (-1)
59 #define SOUT_CFG_PREFIX "sout-file-"
61 /*****************************************************************************
62 * Read: standard read on a file descriptor.
63 *****************************************************************************/
64 static ssize_t
Read( sout_access_out_t
*p_access
, block_t
*p_buffer
)
66 int *fdp
= p_access
->p_sys
, fd
= *fdp
;
70 val
= read(fd
, p_buffer
->p_buffer
, p_buffer
->i_buffer
);
71 while (val
== -1 && errno
== EINTR
);
75 /*****************************************************************************
76 * Write: standard write on a file descriptor.
77 *****************************************************************************/
78 static ssize_t
Write( sout_access_out_t
*p_access
, block_t
*p_buffer
)
80 int *fdp
= p_access
->p_sys
, fd
= *fdp
;
85 ssize_t val
= write(fd
, p_buffer
->p_buffer
, p_buffer
->i_buffer
);
90 block_ChainRelease (p_buffer
);
91 msg_Err( p_access
, "cannot write: %s", vlc_strerror_c(errno
) );
95 if ((size_t)val
>= p_buffer
->i_buffer
)
97 block_t
*p_next
= p_buffer
->p_next
;
98 block_Release (p_buffer
);
103 p_buffer
->p_buffer
+= val
;
104 p_buffer
->i_buffer
-= val
;
111 static ssize_t
WritePipe(sout_access_out_t
*access
, block_t
*block
)
113 int *fdp
= access
->p_sys
, fd
= *fdp
;
116 while (block
!= NULL
)
118 if (block
->i_buffer
== 0)
120 block_t
*next
= block
->p_next
;
121 block_Release(block
);
126 /* TODO: vectorized I/O with writev() */
127 ssize_t val
= vlc_write(fd
, block
->p_buffer
, block
->i_buffer
);
133 block_ChainRelease(block
);
134 msg_Err(access
, "cannot write: %s", vlc_strerror_c(errno
));
141 assert((size_t)val
<= block
->i_buffer
);
142 block
->p_buffer
+= val
;
143 block
->i_buffer
-= val
;
150 static ssize_t
Send(sout_access_out_t
*access
, block_t
*block
)
152 int *fdp
= access
->p_sys
, fd
= *fdp
;
155 while (block
!= NULL
)
157 if (block
->i_buffer
== 0)
159 block_t
*next
= block
->p_next
;
160 block_Release(block
);
165 /* TODO: vectorized I/O with sendmsg() */
166 ssize_t val
= vlc_send(fd
, block
->p_buffer
, block
->i_buffer
, 0);
168 { /* FIXME: errno is meaningless if val is zero */
171 block_ChainRelease(block
);
172 msg_Err(access
, "cannot write: %s", vlc_strerror_c(errno
));
178 assert((size_t)val
<= block
->i_buffer
);
179 block
->p_buffer
+= val
;
180 block
->i_buffer
-= val
;
186 /*****************************************************************************
187 * Seek: seek to a specific location in a file
188 *****************************************************************************/
189 static int Seek( sout_access_out_t
*p_access
, off_t i_pos
)
191 int *fdp
= p_access
->p_sys
, fd
= *fdp
;
193 return lseek(fd
, i_pos
, SEEK_SET
);
196 static int Control( sout_access_out_t
*p_access
, int i_query
, va_list args
)
200 case ACCESS_OUT_CONTROLS_PACE
:
202 bool *pb
= va_arg( args
, bool * );
203 *pb
= strcmp( p_access
->psz_access
, "stream" );
207 case ACCESS_OUT_CAN_SEEK
:
209 bool *pb
= va_arg( args
, bool * );
210 *pb
= p_access
->pf_seek
!= NULL
;
220 static const char *const ppsz_sout_options
[] = {
230 /*****************************************************************************
231 * Open: open the file
232 *****************************************************************************/
233 static int Open( vlc_object_t
*p_this
)
235 sout_access_out_t
*p_access
= (sout_access_out_t
*)p_this
;
237 int *fdp
= vlc_obj_malloc(p_this
, sizeof (*fdp
));
239 if (unlikely(fdp
== NULL
))
242 config_ChainParse( p_access
, SOUT_CFG_PREFIX
, ppsz_sout_options
, p_access
->p_cfg
);
244 bool overwrite
= var_GetBool (p_access
, SOUT_CFG_PREFIX
"overwrite");
245 bool append
= var_GetBool( p_access
, SOUT_CFG_PREFIX
"append" );
247 if (!strcmp (p_access
->psz_access
, "fd"))
251 fd
= strtol (p_access
->psz_path
, &end
, 0);
252 if (!*p_access
->psz_path
|| *end
)
254 msg_Err (p_access
, "invalid file descriptor: %s",
261 msg_Err (p_access
, "cannot use file descriptor: %s",
262 vlc_strerror_c(errno
));
267 if( !strcmp( p_access
->psz_path
, "-" ) )
269 #if defined( _WIN32 ) || defined( __OS2__ )
270 setmode (STDOUT_FILENO
, O_BINARY
);
272 fd
= vlc_dup (STDOUT_FILENO
);
275 msg_Err (p_access
, "cannot use standard output: %s",
276 vlc_strerror_c(errno
));
279 msg_Dbg( p_access
, "using stdout" );
283 const char *path
= p_access
->psz_path
;
286 if (var_InheritBool (p_access
, SOUT_CFG_PREFIX
"format"))
288 buf
= vlc_strftime (path
);
292 int flags
= O_RDWR
| O_CREAT
| O_LARGEFILE
;
298 if (var_GetBool (p_access
, SOUT_CFG_PREFIX
"sync"))
303 fd
= vlc_open (path
, flags
, 0666);
307 msg_Err (p_access
, "cannot create %s: %s", path
,
308 vlc_strerror_c(errno
));
309 if (overwrite
|| errno
!= EEXIST
)
313 while (vlc_dialog_wait_question (p_access
, VLC_DIALOG_QUESTION_NORMAL
,
314 _("Keep existing file"),
315 _("Overwrite"), NULL
, path
,
316 _("The output file already exists. "
317 "If recording continues, the file will be "
318 "overridden and its content will be lost.")) == 1);
325 p_access
->p_sys
= fdp
;
331 msg_Err (p_access
, "write error: %s", vlc_strerror_c(errno
));
336 p_access
->pf_read
= Read
;
338 if (S_ISREG(st
.st_mode
) || S_ISBLK(st
.st_mode
))
340 p_access
->pf_write
= Write
;
341 p_access
->pf_seek
= Seek
;
344 else if (S_ISSOCK(st
.st_mode
))
346 p_access
->pf_write
= Send
;
347 p_access
->pf_seek
= NULL
;
352 p_access
->pf_write
= WritePipe
;
353 p_access
->pf_seek
= NULL
;
355 p_access
->pf_control
= Control
;
357 msg_Dbg( p_access
, "file access output opened (%s)", p_access
->psz_path
);
359 lseek (fd
, 0, SEEK_END
);
364 /*****************************************************************************
365 * Close: close the target
366 *****************************************************************************/
367 static void Close( vlc_object_t
* p_this
)
369 sout_access_out_t
*p_access
= (sout_access_out_t
*)p_this
;
370 int *fdp
= p_access
->p_sys
, fd
= *fdp
;
373 msg_Dbg( p_access
, "file access output closed" );
376 #define OVERWRITE_TEXT N_("Overwrite existing file")
377 #define OVERWRITE_LONGTEXT N_( \
378 "If the file already exists, it will be overwritten.")
379 #define APPEND_TEXT N_("Append to file")
380 #define APPEND_LONGTEXT N_( "Append to file if it exists instead " \
382 #define FORMAT_TEXT N_("Format time and date")
383 #define FORMAT_LONGTEXT N_("Perform ISO C time and date formatting " \
385 #define SYNC_TEXT N_("Synchronous writing")
386 #define SYNC_LONGTEXT N_( "Open the file with synchronous writing.")
389 set_description( N_("File stream output") )
390 set_shortname( N_("File" ))
391 set_capability( "sout access", 50 )
392 set_category( CAT_SOUT
)
393 set_subcategory( SUBCAT_SOUT_ACO
)
394 add_shortcut( "file", "stream", "fd" )
395 add_bool( SOUT_CFG_PREFIX
"overwrite", true, OVERWRITE_TEXT
,
396 OVERWRITE_LONGTEXT
, true )
397 add_bool( SOUT_CFG_PREFIX
"append", false, APPEND_TEXT
,APPEND_LONGTEXT
,
399 add_bool( SOUT_CFG_PREFIX
"format", false, FORMAT_TEXT
, FORMAT_LONGTEXT
,
402 add_bool( SOUT_CFG_PREFIX
"sync", false, SYNC_TEXT
,SYNC_LONGTEXT
,
405 set_callbacks( Open
, Close
)