1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 VLC authors and VideoLAN
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Eric Petit <titer@videolan.org>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
35 #include <sys/types.h>
41 # include <io.h> /* setmode() */
44 #include <vlc_common.h>
45 #include <vlc_plugin.h>
47 #include <vlc_block.h>
49 #include <vlc_network.h>
50 #include <vlc_strings.h>
51 #include <vlc_dialog.h>
54 # define O_LARGEFILE 0
56 #ifndef _POSIX_REALTIME_SIGNALS
57 # define _POSIX_REALTIME_SIGNALS (-1)
60 #define SOUT_CFG_PREFIX "sout-file-"
62 /*****************************************************************************
63 * Read: standard read on a file descriptor.
64 *****************************************************************************/
65 static ssize_t
Read( sout_access_out_t
*p_access
, block_t
*p_buffer
)
67 int *fdp
= p_access
->p_sys
, fd
= *fdp
;
71 val
= read(fd
, p_buffer
->p_buffer
, p_buffer
->i_buffer
);
72 while (val
== -1 && errno
== EINTR
);
76 /*****************************************************************************
77 * Write: standard write on a file descriptor.
78 *****************************************************************************/
79 static ssize_t
Write( sout_access_out_t
*p_access
, block_t
*p_buffer
)
81 int *fdp
= p_access
->p_sys
, fd
= *fdp
;
86 ssize_t val
= write(fd
, p_buffer
->p_buffer
, p_buffer
->i_buffer
);
91 block_ChainRelease (p_buffer
);
92 msg_Err( p_access
, "cannot write: %s", vlc_strerror_c(errno
) );
96 if ((size_t)val
>= p_buffer
->i_buffer
)
98 block_t
*p_next
= p_buffer
->p_next
;
99 block_Release (p_buffer
);
104 p_buffer
->p_buffer
+= val
;
105 p_buffer
->i_buffer
-= val
;
112 static ssize_t
WritePipe(sout_access_out_t
*access
, block_t
*block
)
114 int *fdp
= access
->p_sys
, fd
= *fdp
;
117 while (block
!= NULL
)
119 if (block
->i_buffer
== 0)
121 block_t
*next
= block
->p_next
;
122 block_Release(block
);
127 /* TODO: vectorized I/O with writev() */
128 ssize_t val
= vlc_write(fd
, block
->p_buffer
, block
->i_buffer
);
134 block_ChainRelease(block
);
135 msg_Err(access
, "cannot write: %s", vlc_strerror_c(errno
));
142 assert((size_t)val
<= block
->i_buffer
);
143 block
->p_buffer
+= val
;
144 block
->i_buffer
-= val
;
151 static ssize_t
Send(sout_access_out_t
*access
, block_t
*block
)
153 int *fdp
= access
->p_sys
, fd
= *fdp
;
156 while (block
!= NULL
)
158 if (block
->i_buffer
== 0)
160 block_t
*next
= block
->p_next
;
161 block_Release(block
);
166 /* TODO: vectorized I/O with sendmsg() */
167 ssize_t val
= send(fd
, block
->p_buffer
, block
->i_buffer
, MSG_NOSIGNAL
);
169 { /* FIXME: errno is meaningless if val is zero */
172 block_ChainRelease(block
);
173 msg_Err(access
, "cannot write: %s", vlc_strerror_c(errno
));
179 assert((size_t)val
<= block
->i_buffer
);
180 block
->p_buffer
+= val
;
181 block
->i_buffer
-= val
;
187 /*****************************************************************************
188 * Seek: seek to a specific location in a file
189 *****************************************************************************/
190 static int Seek( sout_access_out_t
*p_access
, off_t i_pos
)
192 int *fdp
= p_access
->p_sys
, fd
= *fdp
;
194 return lseek(fd
, i_pos
, SEEK_SET
);
197 static int Control( sout_access_out_t
*p_access
, int i_query
, va_list args
)
201 case ACCESS_OUT_CONTROLS_PACE
:
203 bool *pb
= va_arg( args
, bool * );
204 *pb
= strcmp( p_access
->psz_access
, "stream" );
208 case ACCESS_OUT_CAN_SEEK
:
210 bool *pb
= va_arg( args
, bool * );
211 *pb
= p_access
->pf_seek
!= NULL
;
221 static const char *const ppsz_sout_options
[] = {
231 /*****************************************************************************
232 * Open: open the file
233 *****************************************************************************/
234 static int Open( vlc_object_t
*p_this
)
236 sout_access_out_t
*p_access
= (sout_access_out_t
*)p_this
;
238 int *fdp
= vlc_obj_malloc(p_this
, sizeof (*fdp
));
240 if (unlikely(fdp
== NULL
))
243 config_ChainParse( p_access
, SOUT_CFG_PREFIX
, ppsz_sout_options
, p_access
->p_cfg
);
245 bool overwrite
= var_GetBool (p_access
, SOUT_CFG_PREFIX
"overwrite");
246 bool append
= var_GetBool( p_access
, SOUT_CFG_PREFIX
"append" );
248 if (!strcmp (p_access
->psz_access
, "fd"))
252 fd
= strtol (p_access
->psz_path
, &end
, 0);
253 if (!*p_access
->psz_path
|| *end
)
255 msg_Err (p_access
, "invalid file descriptor: %s",
262 msg_Err (p_access
, "cannot use file descriptor: %s",
263 vlc_strerror_c(errno
));
268 if( !strcmp( p_access
->psz_path
, "-" ) )
270 #if defined( _WIN32 ) || defined( __OS2__ )
271 setmode (STDOUT_FILENO
, O_BINARY
);
273 fd
= vlc_dup (STDOUT_FILENO
);
276 msg_Err (p_access
, "cannot use standard output: %s",
277 vlc_strerror_c(errno
));
280 msg_Dbg( p_access
, "using stdout" );
284 const char *path
= p_access
->psz_path
;
287 if (var_InheritBool (p_access
, SOUT_CFG_PREFIX
"format"))
289 buf
= vlc_strftime (path
);
293 int flags
= O_RDWR
| O_CREAT
| O_LARGEFILE
;
299 if (var_GetBool (p_access
, SOUT_CFG_PREFIX
"sync"))
304 fd
= vlc_open (path
, flags
, 0666);
308 msg_Err (p_access
, "cannot create %s: %s", path
,
309 vlc_strerror_c(errno
));
310 if (overwrite
|| errno
!= EEXIST
)
314 while (vlc_dialog_wait_question (p_access
, VLC_DIALOG_QUESTION_NORMAL
,
315 _("Keep existing file"),
316 _("Overwrite"), NULL
, path
,
317 _("The output file already exists. "
318 "If recording continues, the file will be "
319 "overridden and its content will be lost.")) == 1);
326 p_access
->p_sys
= fdp
;
332 msg_Err (p_access
, "write error: %s", vlc_strerror_c(errno
));
337 p_access
->pf_read
= Read
;
339 if (S_ISREG(st
.st_mode
) || S_ISBLK(st
.st_mode
))
341 p_access
->pf_write
= Write
;
342 p_access
->pf_seek
= Seek
;
345 else if (S_ISSOCK(st
.st_mode
))
347 p_access
->pf_write
= Send
;
348 p_access
->pf_seek
= NULL
;
353 p_access
->pf_write
= WritePipe
;
354 p_access
->pf_seek
= NULL
;
356 p_access
->pf_control
= Control
;
358 msg_Dbg( p_access
, "file access output opened (%s)", p_access
->psz_path
);
360 lseek (fd
, 0, SEEK_END
);
365 /*****************************************************************************
366 * Close: close the target
367 *****************************************************************************/
368 static void Close( vlc_object_t
* p_this
)
370 sout_access_out_t
*p_access
= (sout_access_out_t
*)p_this
;
371 int *fdp
= p_access
->p_sys
, fd
= *fdp
;
374 msg_Dbg( p_access
, "file access output closed" );
377 #define OVERWRITE_TEXT N_("Overwrite existing file")
378 #define OVERWRITE_LONGTEXT N_( \
379 "If the file already exists, it will be overwritten.")
380 #define APPEND_TEXT N_("Append to file")
381 #define APPEND_LONGTEXT N_( "Append to file if it exists instead " \
383 #define FORMAT_TEXT N_("Format time and date")
384 #define FORMAT_LONGTEXT N_("Perform ISO C time and date formatting " \
386 #define SYNC_TEXT N_("Synchronous writing")
387 #define SYNC_LONGTEXT N_( "Open the file with synchronous writing.")
390 set_description( N_("File stream output") )
391 set_shortname( N_("File" ))
392 set_capability( "sout access", 50 )
393 set_category( CAT_SOUT
)
394 set_subcategory( SUBCAT_SOUT_ACO
)
395 add_shortcut( "file", "stream", "fd" )
396 add_bool( SOUT_CFG_PREFIX
"overwrite", true, OVERWRITE_TEXT
,
397 OVERWRITE_LONGTEXT
, true )
398 add_bool( SOUT_CFG_PREFIX
"append", false, APPEND_TEXT
,APPEND_LONGTEXT
,
400 add_bool( SOUT_CFG_PREFIX
"format", false, FORMAT_TEXT
, FORMAT_LONGTEXT
,
403 add_bool( SOUT_CFG_PREFIX
"sync", false, SYNC_TEXT
,SYNC_LONGTEXT
,
406 set_callbacks( Open
, Close
)