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 *****************************************************************************/
33 #include <sys/types.h>
39 # include <io.h> /* setmode() */
42 #include <vlc_common.h>
43 #include <vlc_plugin.h>
45 #include <vlc_block.h>
47 #include <vlc_network.h>
48 #include <vlc_strings.h>
49 #include <vlc_dialog.h>
52 # define O_LARGEFILE 0
54 #ifndef _POSIX_REALTIME_SIGNALS
55 # define _POSIX_REALTIME_SIGNALS (-1)
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
;
69 val
= read(fd
, p_buffer
->p_buffer
, p_buffer
->i_buffer
);
70 while (val
== -1 && errno
== EINTR
);
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
;
84 ssize_t val
= write(fd
, p_buffer
->p_buffer
, p_buffer
->i_buffer
);
89 block_ChainRelease (p_buffer
);
90 msg_Err( p_access
, "cannot write: %s", vlc_strerror_c(errno
) );
94 if ((size_t)val
>= p_buffer
->i_buffer
)
96 block_t
*p_next
= p_buffer
->p_next
;
97 block_Release (p_buffer
);
102 p_buffer
->p_buffer
+= val
;
103 p_buffer
->i_buffer
-= val
;
110 static ssize_t
WritePipe(sout_access_out_t
*access
, block_t
*block
)
112 int *fdp
= access
->p_sys
, fd
= *fdp
;
115 while (block
!= NULL
)
117 if (block
->i_buffer
== 0)
119 block_t
*next
= block
->p_next
;
120 block_Release(block
);
125 /* TODO: vectorized I/O with writev() */
126 ssize_t val
= vlc_write(fd
, block
->p_buffer
, block
->i_buffer
);
132 block_ChainRelease(block
);
133 msg_Err(access
, "cannot write: %s", vlc_strerror_c(errno
));
140 assert((size_t)val
<= block
->i_buffer
);
141 block
->p_buffer
+= val
;
142 block
->i_buffer
-= val
;
149 static ssize_t
Send(sout_access_out_t
*access
, block_t
*block
)
151 int *fdp
= access
->p_sys
, fd
= *fdp
;
154 while (block
!= NULL
)
156 if (block
->i_buffer
== 0)
158 block_t
*next
= block
->p_next
;
159 block_Release(block
);
164 /* TODO: vectorized I/O with sendmsg() */
165 ssize_t val
= vlc_send(fd
, block
->p_buffer
, block
->i_buffer
, 0);
167 { /* FIXME: errno is meaningless if val is zero */
170 block_ChainRelease(block
);
171 msg_Err(access
, "cannot write: %s", vlc_strerror_c(errno
));
177 assert((size_t)val
<= block
->i_buffer
);
178 block
->p_buffer
+= val
;
179 block
->i_buffer
-= val
;
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
)
199 case ACCESS_OUT_CONTROLS_PACE
:
201 bool *pb
= va_arg( args
, bool * );
202 *pb
= strcmp( p_access
->psz_access
, "stream" );
206 case ACCESS_OUT_CAN_SEEK
:
208 bool *pb
= va_arg( args
, bool * );
209 *pb
= p_access
->pf_seek
!= NULL
;
219 static const char *const ppsz_sout_options
[] = {
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
;
236 int *fdp
= vlc_obj_malloc(p_this
, sizeof (*fdp
));
238 if (unlikely(fdp
== NULL
))
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"))
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",
260 msg_Err (p_access
, "cannot use file descriptor: %s",
261 vlc_strerror_c(errno
));
266 if( !strcmp( p_access
->psz_path
, "-" ) )
268 #if defined( _WIN32 ) || defined( __OS2__ )
269 setmode (STDOUT_FILENO
, O_BINARY
);
271 fd
= vlc_dup (STDOUT_FILENO
);
274 msg_Err (p_access
, "cannot use standard output: %s",
275 vlc_strerror_c(errno
));
278 msg_Dbg( p_access
, "using stdout" );
282 const char *path
= p_access
->psz_path
;
285 if (var_InheritBool (p_access
, SOUT_CFG_PREFIX
"format"))
287 buf
= vlc_strftime (path
);
291 int flags
= O_RDWR
| O_CREAT
| O_LARGEFILE
;
297 if (var_GetBool (p_access
, SOUT_CFG_PREFIX
"sync"))
302 fd
= vlc_open (path
, flags
, 0666);
306 msg_Err (p_access
, "cannot create %s: %s", path
,
307 vlc_strerror_c(errno
));
308 if (overwrite
|| errno
!= EEXIST
)
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);
324 p_access
->p_sys
= fdp
;
330 msg_Err (p_access
, "write error: %s", vlc_strerror_c(errno
));
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
;
343 else if (S_ISSOCK(st
.st_mode
))
345 p_access
->pf_write
= Send
;
346 p_access
->pf_seek
= NULL
;
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
);
358 lseek (fd
, 0, SEEK_END
);
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
;
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 " \
381 #define FORMAT_TEXT N_("Format time and date")
382 #define FORMAT_LONGTEXT N_("Perform ISO C time and date formatting " \
384 #define SYNC_TEXT N_("Synchronous writing")
385 #define SYNC_LONGTEXT N_( "Open the file with synchronous writing.")
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
,
398 add_bool( SOUT_CFG_PREFIX
"format", false, FORMAT_TEXT
, FORMAT_LONGTEXT
,
401 add_bool( SOUT_CFG_PREFIX
"sync", false, SYNC_TEXT
,SYNC_LONGTEXT
,
404 set_callbacks( Open
, Close
)