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 *****************************************************************************/
33 #include <sys/types.h>
37 #include <sys/types.h>
41 #include <vlc_common.h>
42 #include <vlc_plugin.h>
44 #include <vlc_block.h>
46 #include <vlc_strings.h>
47 #include <vlc_dialog.h>
49 #if defined( _WIN32 ) || defined( __OS2__ )
58 # define O_LARGEFILE 0
61 /*****************************************************************************
63 *****************************************************************************/
64 static int Open ( vlc_object_t * );
65 static void Close( vlc_object_t * );
67 #define SOUT_CFG_PREFIX "sout-file-"
68 #define OVERWRITE_TEXT N_("Overwrite existing file")
69 #define OVERWRITE_LONGTEXT N_( \
70 "If the file already exists, it will be overwritten.")
71 #define APPEND_TEXT N_("Append to file")
72 #define APPEND_LONGTEXT N_( "Append to file if it exists instead " \
74 #define FORMAT_TEXT N_("Format time and date")
75 #define FORMAT_LONGTEXT N_("Perform ISO C time and date formatting " \
77 #define SYNC_TEXT N_("Synchronous writing")
78 #define SYNC_LONGTEXT N_( "Open the file with synchronous writing.")
81 set_description( N_("File stream output") )
82 set_shortname( N_("File" ))
83 set_capability( "sout access", 50 )
84 set_category( CAT_SOUT )
85 set_subcategory( SUBCAT_SOUT_ACO )
86 add_shortcut( "file", "stream", "fd" )
87 add_bool( SOUT_CFG_PREFIX "overwrite", true, OVERWRITE_TEXT,
88 OVERWRITE_LONGTEXT, true )
89 add_bool( SOUT_CFG_PREFIX "append", false, APPEND_TEXT,APPEND_LONGTEXT,
91 add_bool( SOUT_CFG_PREFIX "format", false, FORMAT_TEXT, FORMAT_LONGTEXT,
94 add_bool( SOUT_CFG_PREFIX "sync", false, SYNC_TEXT,SYNC_LONGTEXT,
97 set_callbacks( Open, Close )
101 /*****************************************************************************
102 * Exported prototypes
103 *****************************************************************************/
104 static const char *const ppsz_sout_options[] = {
114 static ssize_t Write( sout_access_out_t *, block_t * );
115 static int Seek ( sout_access_out_t *, off_t );
116 static ssize_t Read ( sout_access_out_t *, block_t * );
117 static int Control( sout_access_out_t *, int, va_list );
119 /*****************************************************************************
120 * Open: open the file
121 *****************************************************************************/
122 static int Open( vlc_object_t *p_this )
124 sout_access_out_t *p_access = (sout_access_out_t*)p_this;
127 config_ChainParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg );
129 if( !p_access->psz_path )
131 msg_Err( p_access, "no file name specified" );
135 bool overwrite = var_GetBool (p_access, SOUT_CFG_PREFIX"overwrite");
136 bool append = var_GetBool( p_access, SOUT_CFG_PREFIX "append" );
138 if (!strcmp (p_access->psz_access, "fd"))
142 fd = strtol (p_access->psz_path, &end, 0);
143 if (!*p_access->psz_path || *end)
145 msg_Err (p_access, "invalid file descriptor: %s",
152 msg_Err (p_access, "cannot use file descriptor: %s",
153 vlc_strerror_c(errno));
158 if( !strcmp( p_access->psz_path, "-" ) )
160 #if defined( _WIN32 ) || defined( __OS2__ )
161 setmode (STDOUT_FILENO, O_BINARY);
163 fd = vlc_dup (STDOUT_FILENO);
166 msg_Err (p_access, "cannot use standard output: %s",
167 vlc_strerror_c(errno));
170 msg_Dbg( p_access, "using stdout" );
174 const char *path = p_access->psz_path;
177 if (var_InheritBool (p_access, SOUT_CFG_PREFIX"format"))
179 buf = str_format_time (path);
184 int flags = O_RDWR | O_CREAT | O_LARGEFILE;
190 if (var_GetBool (p_access, SOUT_CFG_PREFIX"sync"))
195 fd = vlc_open (path, flags, 0666);
199 msg_Err (p_access, "cannot create %s: %s", path,
200 vlc_strerror_c(errno));
201 if (overwrite || errno != EEXIST)
205 while (dialog_Question (p_access, path,
206 _("The output file already exists. "
207 "If recording continues, the file will be "
208 "overridden and its content will be lost."),
209 _("Keep existing file"),
210 _("Overwrite"), NULL) == 2);
216 p_access->pf_write = Write;
217 p_access->pf_read = Read;
218 p_access->pf_seek = Seek;
219 p_access->pf_control = Control;
220 p_access->p_sys = (void *)(intptr_t)fd;
222 msg_Dbg( p_access, "file access output opened (%s)", p_access->psz_path );
224 lseek (fd, 0, SEEK_END);
229 /*****************************************************************************
230 * Close: close the target
231 *****************************************************************************/
232 static void Close( vlc_object_t * p_this )
234 sout_access_out_t *p_access = (sout_access_out_t*)p_this;
236 close( (intptr_t)p_access->p_sys );
238 msg_Dbg( p_access, "file access output closed" );
241 static int Control( sout_access_out_t *p_access, int i_query, va_list args )
245 case ACCESS_OUT_CONTROLS_PACE:
247 bool *pb = va_arg( args, bool * );
248 *pb = strcmp( p_access->psz_access, "stream" );
252 case ACCESS_OUT_CAN_SEEK:
254 bool *pb = va_arg( args, bool * );
256 if( fstat( (intptr_t)p_access->p_sys, &st ) == -1 )
259 *pb = S_ISREG( st.st_mode ) || S_ISBLK( st.st_mode );
269 /*****************************************************************************
270 * Read: standard read on a file descriptor.
271 *****************************************************************************/
272 static ssize_t Read( sout_access_out_t *p_access, block_t *p_buffer )
277 val = read( (intptr_t)p_access->p_sys, p_buffer->p_buffer,
278 p_buffer->i_buffer );
279 while (val == -1 && errno == EINTR);
283 /*****************************************************************************
284 * Write: standard write on a file descriptor.
285 *****************************************************************************/
286 static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
292 ssize_t val = write ((intptr_t)p_access->p_sys,
293 p_buffer->p_buffer, p_buffer->i_buffer);
298 block_ChainRelease (p_buffer);
299 msg_Err( p_access, "cannot write: %s", vlc_strerror_c(errno) );
303 if ((size_t)val >= p_buffer->i_buffer)
305 block_t *p_next = p_buffer->p_next;
306 block_Release (p_buffer);
311 p_buffer->p_buffer += val;
312 p_buffer->i_buffer -= val;
319 /*****************************************************************************
320 * Seek: seek to a specific location in a file
321 *****************************************************************************/
322 static int Seek( sout_access_out_t *p_access, off_t i_pos )
324 return lseek( (intptr_t)p_access->p_sys, i_pos, SEEK_SET );