]> git.sesse.net Git - vlc/blob - src/input/input_netlist.c
Added netlist support.
[vlc] / src / input / input_netlist.c
1 /*****************************************************************************
2  * input_netlist.c: netlist management
3  *****************************************************************************
4  * Copyright (C) 1998, 1999, 2000 VideoLAN
5  *
6  * Authors: Henri Fallon <henri@videolan.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #include "defs.h"
27
28 #include <stdlib.h>
29 #include <sys/uio.h>                                         /* struct iovec */
30
31 #include "config.h"
32 #include "common.h"
33 #include "threads.h"                                                /* mutex */
34 #include "mtime.h"
35 #include "intf_msg.h"                                           /* intf_*Msg */
36
37 #include "stream_control.h"
38 #include "input_ext-intf.h"
39 #include "input_ext-dec.h"
40
41 #include "input_netlist.h"
42 #include "input.h"
43
44 /*****************************************************************************
45  * Local prototypes
46  *****************************************************************************/
47
48 /*****************************************************************************
49  * input_NetlistInit: allocates netlist buffers and init indexes
50  *****************************************************************************/
51 int input_NetlistInit( input_thread_t * p_input, int i_nb_data, int i_nb_pes,
52                        size_t i_buffer_size )
53 {
54     unsigned int i_loop;
55     netlist_t * p_netlist;
56
57     /* First we allocate and initialise our netlist struct */
58     p_input->p_method_data = malloc(sizeof(netlist_t));
59     if ( p_input->p_method_data == NULL )
60     {
61         intf_ErrMsg("Unable to malloc the netlist struct\n");
62         return (-1);
63     }
64     
65     p_netlist = (netlist_t *) p_input->p_method_data;
66     
67     /* allocate the buffers */ 
68     p_netlist->p_buffers = 
69         (byte_t *) malloc(i_buffer_size* i_nb_data );
70     if ( p_netlist->p_buffers == NULL )
71     {
72         intf_ErrMsg ("Unable to malloc in netlist initialization (1)\n");
73         return (-1);
74     }
75     
76     p_netlist->p_data = 
77         (data_packet_t *) malloc(sizeof(data_packet_t)*(i_nb_data));
78     if ( p_netlist->p_data == NULL )
79     {
80         intf_ErrMsg ("Unable to malloc in netlist initialization (2)\n");
81         return (-1);
82     }
83     
84     p_netlist->p_pes = 
85         (pes_packet_t *) malloc(sizeof(pes_packet_t)*(i_nb_pes));
86     if ( p_netlist->p_pes == NULL )
87     {
88         intf_ErrMsg ("Unable to malloc in netlist initialization (3)\n");
89         return (-1);
90     }
91     
92     /* allocate the FIFOs */
93     p_netlist->pp_free_data = 
94         (data_packet_t **) malloc (i_nb_data * sizeof(data_packet_t *) );
95     if ( p_netlist->pp_free_data == NULL )
96     {
97         intf_ErrMsg ("Unable to malloc in netlist initialization (4)\n");
98     }
99     p_netlist->pp_free_pes = 
100         (pes_packet_t **) malloc (i_nb_pes * sizeof(pes_packet_t *) );
101     if ( p_netlist->pp_free_pes == NULL )
102     {
103         intf_ErrMsg ("Unable to malloc in netlist initialization (5)\n");
104     }
105     
106     p_netlist->p_free_iovec = ( struct iovec * )
107         malloc( (i_nb_data + INPUT_READ_ONCE) * sizeof(struct iovec) );
108     if ( p_netlist->p_free_iovec == NULL )
109     {
110         intf_ErrMsg ("Unable to malloc in netlist initialization (6)\n");
111     }
112     
113     /* Fill the data FIFO */
114     for ( i_loop = 0; i_loop < i_nb_data; i_loop++ )
115     {
116         p_netlist->pp_free_data[i_loop] = 
117             p_netlist->p_data + i_loop;
118
119         p_netlist->pp_free_data[i_loop]->p_buffer = 
120             p_netlist->p_buffers + i_loop * i_buffer_size;
121         
122         p_netlist->pp_free_data[i_loop]->p_payload_start = 
123             p_netlist->pp_free_data[i_loop]->p_buffer;
124
125         p_netlist->pp_free_data[i_loop]->p_payload_end =
126             p_netlist->pp_free_data[i_loop]->p_buffer + i_buffer_size;
127     }
128     /* Fill the PES FIFO */
129     for ( i_loop = 0; i_loop < i_nb_pes ; i_loop++ )
130     {
131         p_netlist->pp_free_pes[i_loop] = 
132             p_netlist->p_pes + i_loop;
133     }
134    
135     /* Deal with the iovec */
136     for ( i_loop = 0; i_loop < i_nb_data; i_loop++ )
137     {
138         p_netlist->p_free_iovec[i_loop].iov_base = 
139             p_netlist->p_buffers + i_loop * i_buffer_size;
140    
141         p_netlist->p_free_iovec[i_loop].iov_len = i_buffer_size;
142     }
143     
144     /* vlc_mutex_init */
145     vlc_mutex_init (&p_netlist->lock);
146     
147     /* initialize indexes */
148     p_netlist->i_data_start = 0;
149     p_netlist->i_data_end = i_nb_data - 1;
150
151     p_netlist->i_pes_start = 0;
152     p_netlist->i_pes_end = i_nb_pes + INPUT_READ_ONCE - 1;
153
154     p_netlist->i_iovec_start = 0;
155     p_netlist->i_iovec_end = i_nb_data - 1;
156     
157     p_netlist->i_nb_data = i_nb_data;
158     p_netlist->i_nb_pes = i_nb_pes;
159     p_netlist->i_buffer_size = i_buffer_size;
160
161     return (0); /* Everything went all right */
162 }
163
164 /*****************************************************************************
165  * input_NetlistGetiovec: returns an iovec pointer for a readv() operation
166  *****************************************************************************/
167 struct iovec * input_NetlistGetiovec( void * p_method_data )
168 {
169     netlist_t * p_netlist;
170
171     /* cast */
172     p_netlist = ( netlist_t * ) p_method_data;
173     
174     /* check */
175     if ( 
176      (p_netlist->i_iovec_end - p_netlist->i_iovec_start)%p_netlist->i_nb_data 
177      < INPUT_READ_ONCE )
178     {
179         intf_ErrMsg("Empty iovec FIFO. Unable to allocate memory\n");
180         return (NULL);
181     }
182
183     /* readv only takes contiguous buffers */
184     if( p_netlist->i_nb_data - p_netlist->i_iovec_start < INPUT_READ_ONCE )
185         memcpy( &p_netlist->p_free_iovec[p_netlist->i_nb_data], 
186                 p_netlist->p_free_iovec, 
187                 INPUT_READ_ONCE-(p_netlist->i_nb_data-p_netlist->i_iovec_start)
188               );
189
190     p_netlist->i_iovec_start += INPUT_READ_ONCE;
191     p_netlist->i_iovec_start %= p_netlist->i_nb_data;
192     
193     return &p_netlist->p_free_iovec[p_netlist->i_iovec_start];
194 }
195
196 /*****************************************************************************
197  * input_NetlistMviovec: move the iovec pointer after a readv() operation
198  *****************************************************************************/
199 void input_NetlistMviovec( void * p_method_data, size_t i_nb_iovec )
200 {
201     netlist_t * p_netlist;
202
203     /* cast */
204     p_netlist = (netlist_t *) p_method_data;
205     
206     p_netlist->i_iovec_start += i_nb_iovec;
207     p_netlist->i_iovec_start %= p_netlist->i_nb_data;
208 }
209
210 /*****************************************************************************
211  * input_NetlistNewPacket: returns a free data_packet_t
212  *****************************************************************************/
213 struct data_packet_s * input_NetlistNewPacket( void * p_method_data,
214                                                size_t i_buffer_size )
215 {    
216     netlist_t * p_netlist; 
217     struct data_packet_s * p_return;
218     
219     /* cast */
220     p_netlist = ( netlist_t * ) p_method_data; 
221
222 #ifdef DEBUG
223     if( i_buffer_size > p_netlist->i_buffer_size )
224     {
225         /* This should not happen */
226         intf_ErrMsg( "Netlist packet too small !" );
227         return NULL;
228     }
229 #endif
230
231     /* lock */
232     vlc_mutex_lock ( &p_netlist->lock );
233         
234     /* check */
235     if ( p_netlist->i_data_start == p_netlist->i_data_end )
236     {
237         intf_ErrMsg("Empty Data FIFO in netlist. Unable to allocate memory\n");
238         return ( NULL );
239     }
240     
241     p_return = (p_netlist->pp_free_data[p_netlist->i_data_start]);
242     p_netlist->i_data_start++;
243     p_netlist->i_data_start %= p_netlist->i_nb_data;
244     
245     p_netlist->i_iovec_start++; 
246     p_netlist->i_iovec_start %= p_netlist->i_nb_data;
247
248     /* unlock */
249     vlc_mutex_unlock (&p_netlist->lock);
250
251     if (i_buffer_size < p_netlist->i_buffer_size) 
252     {
253         p_return->p_payload_end = p_return->p_payload_start + i_buffer_size;
254     }
255    
256     /* initialize data */
257     p_return->p_next = NULL;
258     p_return->b_discard_payload = 0;
259     
260     return ( p_return );
261 }
262
263 /*****************************************************************************
264  * input_NetlistNewPES: returns a free pes_packet_t
265  *****************************************************************************/
266 struct pes_packet_s * input_NetlistNewPES( void * p_method_data )
267 {
268     netlist_t * p_netlist;
269     pes_packet_t * p_return;
270     
271     /* cast */ 
272     p_netlist = (netlist_t *) p_method_data;
273     
274     /* lock */
275     vlc_mutex_lock ( &p_netlist->lock );
276     
277     /* check */
278     if ( p_netlist->i_pes_start == p_netlist->i_pes_end )
279     {
280         intf_ErrMsg("Empty PES FIFO in netlist - Unable to allocate memory\n");
281         return ( NULL );
282     }
283
284     /* allocate */
285     p_return = p_netlist->pp_free_pes[p_netlist->i_pes_start];
286     p_netlist->i_pes_start++;
287     p_netlist->i_pes_start %= p_netlist->i_nb_pes; 
288    
289     /* unlock */
290     vlc_mutex_unlock (&p_netlist->lock);
291     
292     /* initialize PES */
293     p_return->b_messed_up = 
294         p_return->b_data_alignment = 
295         p_return->b_discontinuity = 
296         p_return->b_has_pts = 0;
297     p_return->i_pes_size = 0;
298     p_return->p_first = NULL;
299    
300     return ( p_return );
301 }
302
303 /*****************************************************************************
304  * input_NetlistDeletePacket: puts a data_packet_t back into the netlist
305  *****************************************************************************/
306 void input_NetlistDeletePacket( void * p_method_data, data_packet_t * p_data )
307 {
308     netlist_t * p_netlist;
309     
310     /* cast */
311     p_netlist = (netlist_t *) p_method_data;
312
313     /* lock */
314     vlc_mutex_lock ( &p_netlist->lock );
315
316     /* Delete data_packet */
317     p_netlist->i_data_end ++;
318     p_netlist->i_data_end %= p_netlist->i_nb_data;
319     p_netlist->pp_free_data[p_netlist->i_data_end] = p_data;
320     
321     /* Delete the corresponding iovec */
322     p_netlist->i_iovec_end++; 
323     p_netlist->i_iovec_end %= p_netlist->i_nb_data;
324     p_netlist->p_free_iovec[p_netlist->i_iovec_end].iov_base = 
325         p_data->p_buffer;
326     
327     /* unlock */
328     vlc_mutex_unlock (&p_netlist->lock);    
329 }
330
331 /*****************************************************************************
332  * input_NetlistDeletePES: puts a pes_packet_t back into the netlist
333  *****************************************************************************/
334 void input_NetlistDeletePES( void * p_method_data, pes_packet_t * p_pes )
335 {
336     netlist_t * p_netlist; 
337     data_packet_t * p_current_packet;
338     
339     /* cast */
340     p_netlist = (netlist_t *)p_method_data;
341
342     /* lock */
343     vlc_mutex_lock ( &p_netlist->lock );
344
345     /* delete free  p_pes->p_first, p_next ... */
346     p_current_packet = p_pes->p_first;
347     while ( p_current_packet != NULL )
348     {
349         /* copy of NetListDeletePacket, duplicate code avoid many locks */
350
351         p_netlist->i_data_end ++;
352         p_netlist->i_data_end %= p_netlist->i_nb_data;
353         p_netlist->pp_free_data[p_netlist->i_data_end] = p_current_packet;
354         
355         p_netlist->i_iovec_end++; 
356         p_netlist->i_iovec_end %= p_netlist->i_nb_data;
357         p_netlist->p_free_iovec[p_netlist->i_iovec_end].iov_base = 
358             p_netlist->p_data->p_buffer;
359     
360         p_current_packet = p_current_packet->p_next;
361     }
362  
363     /* delete our current PES packet */
364     p_netlist->i_pes_end ++;
365     p_netlist->i_pes_end %= p_netlist->i_nb_pes;
366     p_netlist->pp_free_pes[p_netlist->i_pes_end] = p_pes;
367     
368     /* unlock */
369     vlc_mutex_unlock (&p_netlist->lock);
370 }
371
372 /*****************************************************************************
373  * input_NetlistEnd: frees all allocated structures
374  *****************************************************************************/
375 void input_NetlistEnd( input_thread_t * p_input)
376 {
377     netlist_t * p_netlist;
378
379     /* cast */
380     p_netlist = ( netlist_t * ) p_input->p_method_data;
381     
382     /* free the FIFO, the buffer, and the netlist structure */
383     free (p_netlist->pp_free_data);
384     free (p_netlist->pp_free_pes);
385     free (p_netlist->p_pes);
386     free (p_netlist->p_data);
387
388     /* free the netlist */
389     free (p_netlist);
390 }