]> git.sesse.net Git - vlc/blob - modules/access_output/file.c
macosx: CAS: added ui skeleton for to customize a profile
[vlc] / modules / access_output / file.c
1 /*****************************************************************************
2  * file.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Eric Petit <titer@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
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 General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <sys/types.h>
34 #include <time.h>
35 #include <fcntl.h>
36 #include <errno.h>
37
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
40 #include <vlc_sout.h>
41 #include <vlc_block.h>
42 #include <vlc_fs.h>
43 #include <vlc_strings.h>
44
45 #if defined( WIN32 ) || defined( __OS2__ )
46 #   include <io.h>
47 #else
48 #   include <unistd.h>
49 #endif
50
51 #ifndef O_LARGEFILE
52 #   define O_LARGEFILE 0
53 #endif
54
55 /*****************************************************************************
56  * Module descriptor
57  *****************************************************************************/
58 static int  Open ( vlc_object_t * );
59 static void Close( vlc_object_t * );
60
61 #define SOUT_CFG_PREFIX "sout-file-"
62 #define APPEND_TEXT N_("Append to file")
63 #define APPEND_LONGTEXT N_( "Append to file if it exists instead " \
64                             "of replacing it.")
65 #define SYNC_TEXT N_("Synchronous writing")
66 #define SYNC_LONGTEXT N_( "Open the file with synchronous writing.")
67
68 vlc_module_begin ()
69     set_description( N_("File stream output") )
70     set_shortname( N_("File" ))
71     set_capability( "sout access", 50 )
72     set_category( CAT_SOUT )
73     set_subcategory( SUBCAT_SOUT_ACO )
74     add_shortcut( "file", "stream", "fd" )
75     add_bool( SOUT_CFG_PREFIX "append", false, APPEND_TEXT,APPEND_LONGTEXT,
76               true )
77 #ifdef O_SYNC
78     add_bool( SOUT_CFG_PREFIX "sync", false, SYNC_TEXT,SYNC_LONGTEXT,
79               false )
80 #endif
81     set_callbacks( Open, Close )
82 vlc_module_end ()
83
84
85 /*****************************************************************************
86  * Exported prototypes
87  *****************************************************************************/
88 static const char *const ppsz_sout_options[] = {
89     "append",
90 #ifdef O_SYNC
91     "sync",
92 #endif
93     NULL
94 };
95
96 static ssize_t Write( sout_access_out_t *, block_t * );
97 static int Seek ( sout_access_out_t *, off_t  );
98 static ssize_t Read ( sout_access_out_t *, block_t * );
99 static int Control( sout_access_out_t *, int, va_list );
100
101 /*****************************************************************************
102  * Open: open the file
103  *****************************************************************************/
104 static int Open( vlc_object_t *p_this )
105 {
106     sout_access_out_t   *p_access = (sout_access_out_t*)p_this;
107     int                 fd;
108
109     config_ChainParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg );
110
111     if( !p_access->psz_path )
112     {
113         msg_Err( p_access, "no file name specified" );
114         return VLC_EGENERIC;
115     }
116
117     bool append = var_GetBool( p_access, SOUT_CFG_PREFIX "append" );
118
119     if (!strcmp (p_access->psz_access, "fd"))
120     {
121         char *end;
122
123         fd = strtol (p_access->psz_path, &end, 0);
124         if (!*p_access->psz_path || *end)
125         {
126             msg_Err (p_access, "invalid file descriptor: %s",
127                      p_access->psz_path);
128             return VLC_EGENERIC;
129         }
130         fd = vlc_dup (fd);
131         if (fd == -1)
132         {
133             msg_Err (p_access, "cannot use file descriptor: %m");
134             return VLC_EGENERIC;
135         }
136     }
137 #ifndef UNDER_CE
138     else
139     if( !strcmp( p_access->psz_path, "-" ) )
140     {
141 #if defined( WIN32 ) || defined( __OS2__ )
142         setmode (fileno (stdout), O_BINARY);
143 #endif
144         fd = vlc_dup (fileno (stdout));
145         if (fd == -1)
146         {
147             msg_Err (p_access, "cannot use standard output: %m");
148             return VLC_EGENERIC;
149         }
150         msg_Dbg( p_access, "using stdout" );
151     }
152 #endif
153     else
154     {
155         char *psz_tmp = str_format( p_access, p_access->psz_path );
156         path_sanitize( psz_tmp );
157
158         fd = vlc_open( psz_tmp, O_RDWR | O_CREAT | O_LARGEFILE |
159 #ifdef O_SYNC
160                 (var_GetBool( p_access, SOUT_CFG_PREFIX "sync" ) ? O_SYNC : 0) |
161 #endif
162                 (append ? 0 : O_TRUNC), 0666 );
163         free( psz_tmp );
164         if (fd == -1)
165         {
166             msg_Err (p_access, "cannot create %s: %m", p_access->psz_path);
167             return VLC_EGENERIC;
168         }
169     }
170
171     p_access->pf_write = Write;
172     p_access->pf_read  = Read;
173     p_access->pf_seek  = Seek;
174     p_access->pf_control = Control;
175     p_access->p_sys    = (void *)(intptr_t)fd;
176
177     msg_Dbg( p_access, "file access output opened (%s)", p_access->psz_path );
178     if (append)
179         lseek (fd, 0, SEEK_END);
180
181     return VLC_SUCCESS;
182 }
183
184 /*****************************************************************************
185  * Close: close the target
186  *****************************************************************************/
187 static void Close( vlc_object_t * p_this )
188 {
189     sout_access_out_t *p_access = (sout_access_out_t*)p_this;
190
191     close( (intptr_t)p_access->p_sys );
192
193     msg_Dbg( p_access, "file access output closed" );
194 }
195
196 static int Control( sout_access_out_t *p_access, int i_query, va_list args )
197 {
198     switch( i_query )
199     {
200         case ACCESS_OUT_CONTROLS_PACE:
201         {
202             bool *pb = va_arg( args, bool * );
203             *pb = strcmp( p_access->psz_access, "stream" );
204             break;
205         }
206
207         default:
208             return VLC_EGENERIC;
209     }
210     return VLC_SUCCESS;
211 }
212
213 /*****************************************************************************
214  * Read: standard read on a file descriptor.
215  *****************************************************************************/
216 static ssize_t Read( sout_access_out_t *p_access, block_t *p_buffer )
217 {
218     ssize_t val;
219
220     do
221         val = read( (intptr_t)p_access->p_sys, p_buffer->p_buffer,
222                     p_buffer->i_buffer );
223     while (val == -1 && errno == EINTR);
224     return val;
225 }
226
227 /*****************************************************************************
228  * Write: standard write on a file descriptor.
229  *****************************************************************************/
230 static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
231 {
232     size_t i_write = 0;
233
234     while( p_buffer )
235     {
236         ssize_t val = write ((intptr_t)p_access->p_sys,
237                              p_buffer->p_buffer, p_buffer->i_buffer);
238         if (val == -1)
239         {
240             if (errno == EINTR)
241                 continue;
242             block_ChainRelease (p_buffer);
243             return -1;
244         }
245
246         if ((size_t)val >= p_buffer->i_buffer)
247         {
248             block_t *p_next = p_buffer->p_next;
249             block_Release (p_buffer);
250             p_buffer = p_next;
251         }
252         else
253         {
254             p_buffer->p_buffer += val;
255             p_buffer->i_buffer -= val;
256         }
257         i_write += val;
258     }
259     return i_write;
260 }
261
262 /*****************************************************************************
263  * Seek: seek to a specific location in a file
264  *****************************************************************************/
265 static int Seek( sout_access_out_t *p_access, off_t i_pos )
266 {
267     return lseek( (intptr_t)p_access->p_sys, i_pos, SEEK_SET );
268 }