]> git.sesse.net Git - vlc/blob - modules/access/mtp.c
91cd8848ce56fa0a1894c95b9eb3224fa3fc07da
[vlc] / modules / access / mtp.c
1 /*****************************************************************************
2  * mtp.c: mtp input (mtp: access plug-in)
3  *****************************************************************************
4  * Copyright (C) 2001-2006 the VideoLAN team
5  * Copyright © 2006-2008 Rémi Denis-Courmont
6  *
7  * Authors: Fabio Ritrovato <exsephiroth87@gmail.com>
8  * Original file.c: Christophe Massiot <massiot@via.ecp.fr>
9  *                  Rémi Denis-Courmont <rem # videolan # org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_input.h>
36 #include <vlc_access.h>
37 #include <vlc_dialog.h>
38
39 #include <assert.h>
40 #include <errno.h>
41 #ifdef HAVE_SYS_TYPES_H
42 #   include <sys/types.h>
43 #endif
44 #ifdef HAVE_SYS_STAT_H
45 #   include <sys/stat.h>
46 #endif
47 #ifdef HAVE_FCNTL_H
48 #   include <fcntl.h>
49 #endif
50
51 #include <unistd.h>
52 #include <poll.h>
53
54 #include <vlc_charset.h>
55
56 #include "libmtp.h"
57
58 /*****************************************************************************
59  * Module descriptor
60  *****************************************************************************/
61
62 static int  Open ( vlc_object_t * );
63 static void Close( vlc_object_t * );
64
65 #define CACHING_TEXT N_("Caching value in ms")
66 #define CACHING_LONGTEXT N_( \
67     "Caching value for files. This " \
68     "value should be set in milliseconds." )
69
70 vlc_module_begin()
71     set_description( N_("MTP input") )
72     set_shortname( N_("MTP") )
73     set_category( CAT_INPUT )
74     set_subcategory( SUBCAT_INPUT_ACCESS )
75     set_capability( "access", 0 )
76     add_shortcut( "mtp" )
77     set_callbacks( Open, Close )
78 vlc_module_end()
79
80 /*****************************************************************************
81  * Exported prototypes
82  *****************************************************************************/
83
84 static int  Seek( access_t *, int64_t );
85 static ssize_t Read( access_t *, uint8_t *, size_t );
86 static int  Control( access_t *, int, va_list );
87
88 static int  open_file( access_t *, const char * );
89
90 struct access_sys_t
91 {
92     unsigned int i_nb_reads;
93     int fd;
94 };
95
96 /*****************************************************************************
97  * Open: open the file
98  *****************************************************************************/
99 static int Open( vlc_object_t *p_this )
100 {
101     access_t     *p_access = ( access_t* )p_this;
102     access_sys_t *p_sys;
103     uint32_t i_bus;
104     uint8_t i_dev;
105     uint16_t i_product_id;
106     int i_track_id;
107     LIBMTP_raw_device_t *p_rawdevices;
108     LIBMTP_mtpdevice_t *p_device;
109     int i_numrawdevices;
110     int i_ret;
111
112     /* Update default_pts to a suitable value for file access */
113     var_Create( p_access, "file-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
114
115     if( sscanf( p_access->psz_path, "%"SCNu32":%"SCNu8":%"SCNu16":%d", &i_bus,
116                 &i_dev, &i_product_id, &i_track_id ) != 4 )
117         return VLC_EGENERIC;
118     i_ret = LIBMTP_Detect_Raw_Devices( &p_rawdevices, &i_numrawdevices );
119     if( i_ret != 0 || i_numrawdevices <= 0 || !p_rawdevices )
120         return VLC_EGENERIC;
121
122     for( int i = 0; i < i_numrawdevices; i++ )
123     {
124         if( i_bus == p_rawdevices[i].bus_location &&
125             i_dev == p_rawdevices[i].devnum &&
126             i_product_id == p_rawdevices[i].device_entry.product_id )
127         {
128             if( ( p_device = LIBMTP_Open_Raw_Device( &p_rawdevices[i] )
129                 ) != NULL )
130             {
131                 free( p_access->psz_path );
132                 if( ( p_access->psz_path = tempnam( NULL, "vlc" ) ) == NULL )
133                 {
134                     LIBMTP_Release_Device( p_device );
135                     free( p_rawdevices );
136                     return VLC_ENOMEM;
137                 }
138                 else
139                 {
140                     msg_Dbg( p_access, "About to write %s", p_access->psz_path );
141                     LIBMTP_Get_File_To_File( p_device, i_track_id,
142                                              p_access->psz_path, NULL, NULL );
143                     LIBMTP_Release_Device( p_device );
144                     i = i_numrawdevices;
145                 }
146             }
147             else
148             {
149                 free( p_rawdevices );
150                 return VLC_EGENERIC;
151             }
152         }
153     }
154     free( p_rawdevices );
155
156     STANDARD_READ_ACCESS_INIT;
157     p_sys->i_nb_reads = 0;
158     int fd = p_sys->fd = -1;
159
160     /* Open file */
161     msg_Dbg( p_access, "opening file `%s'", p_access->psz_path );
162     fd = open_file( p_access, p_access->psz_path );
163
164     if( fd == -1 )
165     {
166         free( p_sys );
167         return VLC_EGENERIC;
168     }
169     p_sys->fd = fd;
170
171 #ifdef HAVE_SYS_STAT_H
172     struct stat st;
173     if( fstat( fd, &st ) )
174         msg_Err( p_access, "fstat(%d): %m", fd );
175     p_access->info.i_size = st.st_size;
176 #else
177 # warning File size not known!
178 #endif
179
180     return VLC_SUCCESS;
181 }
182
183 /*****************************************************************************
184  * Close: close the target
185  *****************************************************************************/
186 static void Close( vlc_object_t * p_this )
187 {
188     access_t     *p_access = ( access_t* )p_this;
189     access_sys_t *p_sys = p_access->p_sys;
190
191     close ( p_sys->fd );
192     if( utf8_unlink( p_access->psz_path ) != 0 )
193         msg_Err( p_access, "Error deleting file %s, %m", p_access->psz_path );
194     free( p_sys );
195 }
196
197 /*****************************************************************************
198  * Read: standard read on a file descriptor.
199  *****************************************************************************/
200 static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len )
201 {
202     access_sys_t *p_sys = p_access->p_sys;
203     ssize_t i_ret;
204     int fd = p_sys->fd;
205
206     i_ret = read( fd, p_buffer, i_len );
207
208     if( i_ret < 0 )
209     {
210         switch( errno )
211         {
212             case EINTR:
213             case EAGAIN:
214                 break;
215
216             default:
217                 msg_Err( p_access, "read failed (%m)" );
218                 dialog_Fatal( p_access, _( "File reading failed" ), "%s",
219                                 _( "VLC could not read the file." ) );
220                 p_access->info.b_eof = true;
221                 return 0;
222         }
223     }
224     else if( i_ret > 0 )
225         p_access->info.i_pos += i_ret;
226     else
227         p_access->info.b_eof = true;
228
229     p_sys->i_nb_reads++;
230
231     return i_ret;
232 }
233
234
235 /*****************************************************************************
236  * Seek: seek to a specific location in a file
237  *****************************************************************************/
238 static int Seek( access_t *p_access, int64_t i_pos )
239 {
240     p_access->info.i_pos = i_pos;
241     p_access->info.b_eof = false;
242
243     lseek( p_access->p_sys->fd, i_pos, SEEK_SET );
244     return VLC_SUCCESS;
245 }
246
247 /*****************************************************************************
248  * Control:
249  *****************************************************************************/
250 static int Control( access_t *p_access, int i_query, va_list args )
251 {
252     bool   *pb_bool;
253     int64_t      *pi_64;
254
255     switch( i_query )
256     {
257         /* */
258         case ACCESS_CAN_SEEK:
259         case ACCESS_CAN_FASTSEEK:
260             pb_bool = ( bool* )va_arg( args, bool* );
261             *pb_bool = true;
262             break;
263
264         case ACCESS_CAN_PAUSE:
265         case ACCESS_CAN_CONTROL_PACE:
266             pb_bool = ( bool* )va_arg( args, bool* );
267             *pb_bool = true;
268             break;
269
270         case ACCESS_GET_PTS_DELAY:
271             pi_64 = ( int64_t* )va_arg( args, int64_t * );
272             *pi_64 = var_GetInteger( p_access, "file-caching" ) * INT64_C( 1000 );
273             break;
274
275         /* */
276         case ACCESS_SET_PAUSE_STATE:
277             /* Nothing to do */
278             break;
279
280         case ACCESS_GET_TITLE_INFO:
281         case ACCESS_SET_TITLE:
282         case ACCESS_SET_SEEKPOINT:
283         case ACCESS_SET_PRIVATE_ID_STATE:
284         case ACCESS_GET_META:
285         case ACCESS_GET_PRIVATE_ID_STATE:
286         case ACCESS_GET_CONTENT_TYPE:
287             return VLC_EGENERIC;
288
289         default:
290             msg_Warn( p_access, "unimplemented query %d in control", i_query );
291             return VLC_EGENERIC;
292
293     }
294     return VLC_SUCCESS;
295 }
296
297 /*****************************************************************************
298  * open_file: Opens a specific file
299  *****************************************************************************/
300 static int open_file( access_t *p_access, const char *path )
301 {
302     int fd = utf8_open( path, O_RDONLY | O_NONBLOCK );
303     if( fd == -1 )
304     {
305         msg_Err( p_access, "cannot open file %s (%m)", path );
306         dialog_Fatal( p_access, _( "File reading failed" ),
307                         _( "VLC could not open the file \"%s\"." ), path );
308         return -1;
309     }
310
311 #if defined( HAVE_FCNTL )
312     fcntl( fd, F_SETFD, fcntl( fd, F_GETFD ) | FD_CLOEXEC );
313
314     /* We'd rather use any available memory for reading ahead
315      * than for caching what we've already seen/heard */
316 # if defined( F_RDAHEAD )
317     fcntl( fd, F_RDAHEAD, 1 );
318 # endif
319 # if defined( F_NOCACHE )
320     fcntl( fd, F_NOCACHE, 1 );
321 # endif
322 #endif
323
324     return fd;
325 }