]> git.sesse.net Git - vlc/blob - modules/access/access2.c
4d32e5348043b9203352fb1cb1afdce2f65105d4
[vlc] / modules / access / access2.c
1 /*****************************************************************************
2  * access2 adaptation layer.
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id: demux2.c 7783 2004-05-27 00:02:43Z hartman $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31
32 /*****************************************************************************
33  * Module descriptor
34  *****************************************************************************/
35 static int  Access2Open ( vlc_object_t * );
36 static void Access2Close( vlc_object_t * );
37
38 vlc_module_begin();
39     set_description( _("Access2 adaptation layer" ) );
40     set_capability( "access", 50 );
41     set_callbacks( Access2Open, Access2Close );
42     add_shortcut( "access2" );
43     add_shortcut( "http" );
44     add_shortcut( "ftp" );
45     add_shortcut( "tcp" );
46     add_shortcut( "pvr" );
47
48     add_shortcut( "file" );
49     add_shortcut( "stream" );
50     add_shortcut( "kfir" );
51
52     add_shortcut( "udp" );
53     add_shortcut( "udp4" );
54     add_shortcut( "udp6" );
55
56     add_shortcut( "rtp" );
57     add_shortcut( "rtp4" );
58     add_shortcut( "rtp6" );
59 vlc_module_end();
60
61 /*****************************************************************************
62  * Local prototypes
63  *****************************************************************************/
64 static int  Access2Read   ( input_thread_t *, byte_t *, size_t );
65 static void Access2Seek   ( input_thread_t *, off_t );
66 static int  Access2SetArea( input_thread_t *, input_area_t * );
67 static int  Access2Control( input_thread_t *, int, va_list );
68
69 typedef struct
70 {
71     access_t  *p_access;
72     block_t   *p_block;
73
74     int i_title;
75     input_title_t **title;
76
77     vlc_bool_t b_first_read;
78
79 } access2_sys_t;
80
81 /*****************************************************************************
82  * Access2Open: initializes structures
83  *****************************************************************************/
84 static int Access2Open( vlc_object_t * p_this )
85 {
86     input_thread_t *p_input = (input_thread_t *)p_this;
87     access2_sys_t  *p_sys   = malloc( sizeof( access2_sys_t ) );
88     access_t       *p_access;
89
90     char           *psz_uri;
91     int            i_int;
92     int64_t        i_64;
93     vlc_bool_t     b_bool;
94
95     psz_uri = malloc( strlen( p_input->psz_access ) + strlen( p_input->psz_demux ) + strlen( p_input->psz_name  ) + 1 + 3 + 1 );
96     if( p_input->psz_demux && *p_input->psz_demux )
97     {
98         sprintf( psz_uri, "%s/%s://%s", p_input->psz_access, p_input->psz_demux, p_input->psz_name );
99     }
100     else if( p_input->psz_access && *p_input->psz_access )
101     {
102         sprintf( psz_uri, "%s://%s", p_input->psz_access, p_input->psz_name );
103     }
104     else
105     {
106         sprintf( psz_uri, "://%s", p_input->psz_name );
107     }
108
109     p_access = access2_New( p_input, psz_uri );
110
111     free( psz_uri );
112
113     if( !p_access )
114     {
115         free( p_sys );
116         return VLC_EGENERIC;
117     }
118
119     /* Init p_input->* */
120     p_input->pf_read           = Access2Read;
121     p_input->pf_seek           = Access2Seek;
122     p_input->pf_set_program    = input_SetProgram;
123     p_input->pf_set_area       = Access2SetArea;
124     p_input->pf_access_control = Access2Control;
125     p_input->p_access_data = (access_sys_t*)p_sys;
126     /* mtu */
127     access2_Control( p_access, ACCESS_GET_MTU, &i_int );
128     p_input->i_mtu = i_int;
129     /* pts delay */
130     access2_Control( p_access, ACCESS_GET_PTS_DELAY, &i_64 );
131     p_input->i_pts_delay = i_64;
132
133     if( p_access->psz_demux && *p_access->psz_demux )
134     {
135         if( !p_input->psz_demux || *p_input->psz_demux == '\0' )
136             p_input->psz_demux = strdup( p_access->psz_demux );
137     }
138     /* title */
139     if( access2_Control( p_access, ACCESS_GET_TITLE_INFO,
140                          &p_sys->title, &p_sys->i_title ) )
141     {
142         p_sys->i_title = 0;
143         p_sys->title   = NULL;
144     }
145
146     /* Init p_input->stream.* */
147     vlc_mutex_lock( &p_input->stream.stream_lock );
148     if( p_sys->i_title > 0 )
149     {
150         /* FIXME handle the area 0 */
151         int64_t i_start = 0;
152         int i;
153
154 #define area p_input->stream.pp_areas
155         for( i = 0 ; i <= p_sys->i_title ; i++ )
156         {
157             input_title_t *t = p_sys->title[i];
158
159             input_AddArea( p_input, i+1,
160                            t->i_seekpoint > 0 ? t->i_seekpoint : 1 );
161
162             /* Absolute start offset and size */
163             area[i]->i_start = i_start;
164             area[i]->i_size  = t->i_size;
165
166             i_start += t->i_size;
167         }
168 #undef area
169
170         /* Set the area */
171         Access2SetArea( p_input, p_input->stream.pp_areas[1] );
172     }
173
174     /* size */
175     p_input->stream.p_selected_area->i_size  = p_access->info.i_size;
176     /* seek */
177     access2_Control( p_access, ACCESS_CAN_SEEK, &b_bool );
178     p_input->stream.b_seekable = b_bool;
179     /* pace */
180     access2_Control( p_access, ACCESS_CAN_CONTROL_PACE, &b_bool );
181     p_input->stream.b_pace_control = b_bool;
182    /* End of init */
183     access2_Control( p_access, ACCESS_CAN_SEEK, &b_bool );
184     if( b_bool )
185         p_input->stream.i_method = INPUT_METHOD_FILE;   /* FIXME */
186     else
187         p_input->stream.i_method = INPUT_METHOD_NETWORK;/* FIXME */
188     p_input->stream.p_selected_area->i_tell = p_access->info.i_pos;
189     vlc_mutex_unlock( &p_input->stream.stream_lock );
190
191
192     p_sys->p_access = p_access;
193     p_sys->p_block = NULL;
194     p_sys->b_first_read = VLC_TRUE;
195
196     return VLC_SUCCESS;
197 }
198
199 /*****************************************************************************
200  * Access2Close: frees unused data
201  *****************************************************************************/
202 static void Access2Close( vlc_object_t * p_this )
203 {
204     input_thread_t *p_input = (input_thread_t*)p_this;
205     access2_sys_t  *p_sys = (access2_sys_t*)p_input->p_access_data;
206     int i;
207
208     access2_Delete( p_sys->p_access );
209
210     for( i = 0; i < p_sys->i_title; i++ )
211     {
212         vlc_input_title_Delete( p_sys->title[i] );
213     }
214     if( p_sys->title ) free( p_sys->title );
215
216     if( p_sys->p_block )
217         block_Release( p_sys->p_block );
218
219     free( p_sys );
220 }
221
222 /*****************************************************************************
223  * Access2Read: Read data
224  *****************************************************************************
225  * Returns -1 in case of error, 0 in case of EOF, size otherwise
226  *****************************************************************************/
227 static int  Access2Read( input_thread_t *p_input, byte_t *p_buffer, size_t i_len )
228 {
229     access2_sys_t *p_sys = (access2_sys_t*)p_input->p_access_data;
230     access_t      *p_access = p_sys->p_access;
231     int           i_total = 0;
232
233     /* TODO update i_size (ex: when read more than half current size and only every 100 times or ...) */
234
235     if( p_access->pf_read )
236     {
237         i_total = p_access->pf_read( p_access, (uint8_t*)p_buffer, (int)i_len );
238         goto update;
239     }
240
241     /* Should never occur */
242     if( p_access->pf_block == NULL )
243     {
244         i_total = 0;
245         goto update;
246     }
247
248     /* Emulate the read */
249     while( i_total < i_len )
250     {
251         int i_copy;
252         if( p_sys->p_block == NULL )
253         {
254             p_sys->p_block = p_access->pf_block( p_access );
255         }
256         if( p_sys->p_block == NULL )
257         {
258             if( !p_access->info.b_eof && i_total <= 0 )
259                 i_total = -1;
260             goto update;
261         }
262
263         i_copy = __MIN( i_len - i_total, p_sys->p_block->i_buffer );
264         if( i_copy > 0 )
265         {
266             memcpy( &p_buffer[i_total], p_sys->p_block->p_buffer, i_copy );
267
268             p_sys->p_block->i_buffer -= i_copy;
269             p_sys->p_block->p_buffer += i_copy;
270         }
271
272         if( p_sys->p_block->i_buffer <= 0 )
273         {
274             block_Release( p_sys->p_block );
275             p_sys->p_block = NULL;
276         }
277
278         i_total += i_copy;
279     }
280 update:
281     if( p_sys->b_first_read )
282     {
283         /* Some access update it only after first read (like udp) */
284         if( p_access->psz_demux && *p_access->psz_demux )
285         {
286             if( !p_input->psz_demux || *p_input->psz_demux == '\0' )
287                 p_input->psz_demux = strdup( p_access->psz_demux );
288         }
289         p_sys->b_first_read = VLC_FALSE;
290     }
291     if( p_access->info.i_update & INPUT_UPDATE_SIZE )
292     {
293         vlc_mutex_lock( &p_input->stream.stream_lock );
294         p_input->stream.p_selected_area->i_size  = p_access->info.i_size;
295         p_input->stream.b_changed = VLC_TRUE;
296         vlc_mutex_unlock( &p_input->stream.stream_lock );
297
298         p_access->info.i_update &= ~INPUT_UPDATE_SIZE;
299     }
300
301     if( p_access->info.i_update & INPUT_UPDATE_TITLE )
302     {
303         /* TODO */
304         msg_Err( p_input, "INPUT_UPDATE_TITLE to do" );
305     }
306     if( p_access->info.i_update & INPUT_UPDATE_SEEKPOINT )
307     {
308         /* TODO */
309         msg_Err( p_input, "INPUT_UPDATE_SEEKPOINT to do" );
310     }
311
312     return i_total;
313 }
314
315 /*****************************************************************************
316  * Access2SetArea: initialize input data for title x.
317  * It should be called for each user navigation request.
318  ****************************************************************************/
319 static int Access2SetArea( input_thread_t * p_input, input_area_t * p_area )
320 {
321 #if 0
322     access_sys_t *p_sys = p_input->p_access_data;
323     vlc_value_t  val;
324     /* we can't use the interface slider until initilization is complete */
325     p_input->stream.b_seekable = 0;
326
327     if( p_area != p_input->stream.p_selected_area )
328     {
329         /* Change the default area */
330         p_input->stream.p_selected_area = p_area;
331
332         /* Change the current track */
333         p_sys->i_track = p_area->i_id - 1;
334         p_sys->i_sector = p_sys->p_sectors[p_sys->i_track];
335
336         /* Update the navigation variables without triggering a callback */
337         val.i_int = p_area->i_id;
338         var_Change( p_input, "title", VLC_VAR_SETVALUE, &val, NULL );
339     }
340
341     p_sys->i_sector = p_sys->p_sectors[p_sys->i_track];
342
343     p_input->stream.p_selected_area->i_tell =
344         (off_t)p_sys->i_sector * (off_t)CDDA_DATA_SIZE
345          - p_input->stream.p_selected_area->i_start;
346
347     /* warn interface that something has changed */
348     p_input->stream.b_seekable = 1;
349     p_input->stream.b_changed = 1;
350 #endif
351     return VLC_EGENERIC;
352 }
353
354
355 /*****************************************************************************
356  * Access2Seek:
357  *****************************************************************************
358  * Returns VLC_EGENERIC/VLC_SUCCESS
359  *****************************************************************************/
360 static void Access2Seek( input_thread_t *p_input, off_t i_pos )
361 {
362     access2_sys_t *p_sys = (access2_sys_t*)p_input->p_access_data;
363     access_t      *p_access = p_sys->p_access;
364
365     if( p_access->pf_seek != NULL && p_input->stream.b_seekable )
366     {
367         if( !p_access->pf_seek( p_access, i_pos ) )
368         {
369             if( p_sys->p_block )
370             {
371                 block_Release( p_sys->p_block );
372                 p_sys->p_block = NULL;
373             }
374
375             vlc_mutex_lock( &p_input->stream.stream_lock );
376             p_input->stream.p_selected_area->i_tell = p_access->info.i_pos;
377             vlc_mutex_unlock( &p_input->stream.stream_lock );
378         }
379     }
380 }
381
382 /*****************************************************************************
383  * Access2Control:
384  *****************************************************************************
385  * Returns VLC_EGENERIC/VLC_SUCCESS
386  *****************************************************************************/
387 static int  Access2Control( input_thread_t *p_input, int i_query, va_list args )
388 {
389     access2_sys_t *p_sys = (access2_sys_t*)p_input->p_access_data;
390     access_t      *p_access = p_sys->p_access;
391
392     return access2_vaControl( p_access, i_query, args );
393 }