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
)
70 val
= read( (intptr_t)p_access
->p_sys
, p_buffer
->p_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
)
85 ssize_t val
= write ((intptr_t)p_access
->p_sys
,
86 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 fd
= (intptr_t)access
->p_sys
;
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 fd
= (intptr_t)access
->p_sys
;
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 return lseek( (intptr_t)p_access
->p_sys
, i_pos
, SEEK_SET
);
195 static int NoSeek(sout_access_out_t
*access
, off_t pos
)
197 (void) access
; (void) pos
;
201 static int Control( sout_access_out_t
*p_access
, int i_query
, va_list args
)
205 case ACCESS_OUT_CONTROLS_PACE
:
207 bool *pb
= va_arg( args
, bool * );
208 *pb
= strcmp( p_access
->psz_access
, "stream" );
212 case ACCESS_OUT_CAN_SEEK
:
214 bool *pb
= va_arg( args
, bool * );
215 *pb
= p_access
->pf_seek
== Seek
;
225 static const char *const ppsz_sout_options
[] = {
235 /*****************************************************************************
236 * Open: open the file
237 *****************************************************************************/
238 static int Open( vlc_object_t
*p_this
)
240 sout_access_out_t
*p_access
= (sout_access_out_t
*)p_this
;
243 config_ChainParse( p_access
, SOUT_CFG_PREFIX
, ppsz_sout_options
, p_access
->p_cfg
);
245 if( !p_access
->psz_path
)
247 msg_Err( p_access
, "no file name specified" );
251 bool overwrite
= var_GetBool (p_access
, SOUT_CFG_PREFIX
"overwrite");
252 bool append
= var_GetBool( p_access
, SOUT_CFG_PREFIX
"append" );
254 if (!strcmp (p_access
->psz_access
, "fd"))
258 fd
= strtol (p_access
->psz_path
, &end
, 0);
259 if (!*p_access
->psz_path
|| *end
)
261 msg_Err (p_access
, "invalid file descriptor: %s",
268 msg_Err (p_access
, "cannot use file descriptor: %s",
269 vlc_strerror_c(errno
));
274 if( !strcmp( p_access
->psz_path
, "-" ) )
276 #if defined( _WIN32 ) || defined( __OS2__ )
277 setmode (STDOUT_FILENO
, O_BINARY
);
279 fd
= vlc_dup (STDOUT_FILENO
);
282 msg_Err (p_access
, "cannot use standard output: %s",
283 vlc_strerror_c(errno
));
286 msg_Dbg( p_access
, "using stdout" );
290 const char *path
= p_access
->psz_path
;
293 if (var_InheritBool (p_access
, SOUT_CFG_PREFIX
"format"))
295 buf
= vlc_strftime (path
);
299 int flags
= O_RDWR
| O_CREAT
| O_LARGEFILE
;
305 if (var_GetBool (p_access
, SOUT_CFG_PREFIX
"sync"))
310 fd
= vlc_open (path
, flags
, 0666);
314 msg_Err (p_access
, "cannot create %s: %s", path
,
315 vlc_strerror_c(errno
));
316 if (overwrite
|| errno
!= EEXIST
)
320 while (vlc_dialog_wait_question (p_access
, VLC_DIALOG_QUESTION_NORMAL
,
321 _("Keep existing file"),
322 _("Overwrite"), NULL
, path
,
323 _("The output file already exists. "
324 "If recording continues, the file will be "
325 "overridden and its content will be lost.")) == 1);
335 msg_Err (p_access
, "write error: %s", vlc_strerror_c(errno
));
340 p_access
->pf_read
= Read
;
342 if (S_ISREG(st
.st_mode
) || S_ISBLK(st
.st_mode
))
344 p_access
->pf_write
= Write
;
345 p_access
->pf_seek
= Seek
;
348 else if (S_ISSOCK(st
.st_mode
))
350 p_access
->pf_write
= Send
;
351 p_access
->pf_seek
= NoSeek
;
356 p_access
->pf_write
= WritePipe
;
357 p_access
->pf_seek
= NoSeek
;
359 p_access
->pf_control
= Control
;
360 p_access
->p_sys
= (void *)(intptr_t)fd
;
362 msg_Dbg( p_access
, "file access output opened (%s)", p_access
->psz_path
);
364 lseek (fd
, 0, SEEK_END
);
369 /*****************************************************************************
370 * Close: close the target
371 *****************************************************************************/
372 static void Close( vlc_object_t
* p_this
)
374 sout_access_out_t
*p_access
= (sout_access_out_t
*)p_this
;
376 vlc_close( (intptr_t)p_access
->p_sys
);
378 msg_Dbg( p_access
, "file access output closed" );
381 #define OVERWRITE_TEXT N_("Overwrite existing file")
382 #define OVERWRITE_LONGTEXT N_( \
383 "If the file already exists, it will be overwritten.")
384 #define APPEND_TEXT N_("Append to file")
385 #define APPEND_LONGTEXT N_( "Append to file if it exists instead " \
387 #define FORMAT_TEXT N_("Format time and date")
388 #define FORMAT_LONGTEXT N_("Perform ISO C time and date formatting " \
390 #define SYNC_TEXT N_("Synchronous writing")
391 #define SYNC_LONGTEXT N_( "Open the file with synchronous writing.")
394 set_description( N_("File stream output") )
395 set_shortname( N_("File" ))
396 set_capability( "sout access", 50 )
397 set_category( CAT_SOUT
)
398 set_subcategory( SUBCAT_SOUT_ACO
)
399 add_shortcut( "file", "stream", "fd" )
400 add_bool( SOUT_CFG_PREFIX
"overwrite", true, OVERWRITE_TEXT
,
401 OVERWRITE_LONGTEXT
, true )
402 add_bool( SOUT_CFG_PREFIX
"append", false, APPEND_TEXT
,APPEND_LONGTEXT
,
404 add_bool( SOUT_CFG_PREFIX
"format", false, FORMAT_TEXT
, FORMAT_LONGTEXT
,
407 add_bool( SOUT_CFG_PREFIX
"sync", false, SYNC_TEXT
,SYNC_LONGTEXT
,
410 set_callbacks( Open
, Close
)