]> git.sesse.net Git - vlc/blob - src/input/input_netlist.c
fc8dc0d09d476968023891e4012f94eed4b72931
[vlc] / src / input / input_netlist.c
1 /*****************************************************************************
2  * input_netlist.c: netlist management
3  *****************************************************************************
4  * Copyright (C) 1998, 1999, 2000 VideoLAN
5  * $Id: input_netlist.c,v 1.28 2001/01/07 03:56:40 henri Exp $
6  *
7  * Authors: Henri Fallon <henri@videolan.org>
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 "defs.h"
28
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <sys/uio.h>                                         /* struct iovec */
32 #include <unistd.h>
33
34 #include "config.h"
35 #include "common.h"
36 #include "threads.h"                                                /* mutex */
37 #include "mtime.h"
38 #include "intf_msg.h"                                           /* intf_*Msg */
39
40 #include "stream_control.h"
41 #include "input_ext-intf.h"
42 #include "input_ext-dec.h"
43
44 #include "input_netlist.h"
45 #include "input.h"
46
47 /*****************************************************************************
48  * Local prototypes
49  *****************************************************************************/
50
51 /*****************************************************************************
52  * input_NetlistInit: allocates netlist buffers and init indexes
53  *****************************************************************************/
54 int input_NetlistInit( input_thread_t * p_input, int i_nb_data, int i_nb_pes,
55                        size_t i_buffer_size )
56 {
57     unsigned int i_loop;
58     netlist_t * p_netlist;
59
60     /* First we allocate and initialise our netlist struct */
61     p_input->p_method_data = malloc(sizeof(netlist_t));
62     if ( p_input->p_method_data == NULL )
63     {
64         intf_ErrMsg("Unable to malloc the netlist struct");
65         return (-1);
66     }
67     
68     p_netlist = (netlist_t *) p_input->p_method_data;
69     
70     /* allocate the buffers */ 
71     p_netlist->p_buffers = 
72         (byte_t *) malloc(i_buffer_size* i_nb_data );
73     if ( p_netlist->p_buffers == NULL )
74     {
75         intf_ErrMsg ("Unable to malloc in netlist initialization (1)");
76         return (-1);
77     }
78     
79     p_netlist->p_data = 
80         (data_packet_t *) malloc(sizeof(data_packet_t)*(i_nb_data));
81     if ( p_netlist->p_data == NULL )
82     {
83         intf_ErrMsg ("Unable to malloc in netlist initialization (2)");
84         return (-1);
85     }
86     
87     p_netlist->p_pes = 
88         (pes_packet_t *) malloc(sizeof(pes_packet_t)*(i_nb_pes));
89     if ( p_netlist->p_pes == NULL )
90     {
91         intf_ErrMsg ("Unable to malloc in netlist initialization (3)");
92         return (-1);
93     }
94     
95     /* allocate the FIFOs */
96     p_netlist->pp_free_data = 
97         (data_packet_t **) malloc (i_nb_data * sizeof(data_packet_t *) );
98     if ( p_netlist->pp_free_data == NULL )
99     {
100         intf_ErrMsg ("Unable to malloc in netlist initialization (4)");
101     }
102     p_netlist->pp_free_pes = 
103         (pes_packet_t **) malloc (i_nb_pes * sizeof(pes_packet_t *) );
104     if ( p_netlist->pp_free_pes == NULL )
105     {
106         intf_ErrMsg ("Unable to malloc in netlist initialization (5)");
107     }
108     
109     p_netlist->p_free_iovec = ( struct iovec * )
110         malloc( (i_nb_data + INPUT_READ_ONCE) * sizeof(struct iovec) );
111     if ( p_netlist->p_free_iovec == NULL )
112     {
113         intf_ErrMsg ("Unable to malloc in netlist initialization (6)");
114     }
115     
116     /* Fill the data FIFO */
117     for ( i_loop = 0; i_loop < i_nb_data; i_loop++ )
118     {
119         p_netlist->pp_free_data[i_loop] = 
120             p_netlist->p_data + i_loop;
121
122         p_netlist->pp_free_data[i_loop]->p_buffer = 
123             p_netlist->p_buffers + i_loop * i_buffer_size;
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 - 1;
153
154     p_netlist->i_nb_data = i_nb_data;
155     p_netlist->i_nb_pes = i_nb_pes;
156     p_netlist->i_buffer_size = i_buffer_size;
157
158     return (0); /* Everything went all right */
159 }
160
161 /*****************************************************************************
162  * input_NetlistGetiovec: returns an iovec pointer for a readv() operation
163  *****************************************************************************/
164 struct iovec * input_NetlistGetiovec( void * p_method_data )
165 {
166     netlist_t * p_netlist;
167
168     /* cast */
169     p_netlist = ( netlist_t * ) p_method_data;
170     
171     /* check */
172     if ( 
173      (p_netlist->i_data_end - p_netlist->i_data_start + p_netlist->i_nb_data)
174      %p_netlist->i_nb_data < INPUT_READ_ONCE )
175     {
176         intf_ErrMsg("Empty iovec FIFO. Unable to allocate memory");
177         return (NULL);
178     }
179
180     /* readv only takes contiguous buffers 
181      * so, as a solution, we chose to have a FIFO a bit longer
182      * than i_nb_data, and copy the begining of the FIFO to its end
183      * if the readv needs to go after the end */
184     if( p_netlist->i_nb_data - p_netlist->i_data_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_data_start)
188                 * sizeof(struct iovec *)
189               );
190  
191     /* Initialize payload start and end */
192     p_netlist->pp_free_data[p_netlist->i_data_start]->p_payload_start 
193         = p_netlist->pp_free_data[p_netlist->i_data_start]->p_buffer;
194  
195     p_netlist->pp_free_data[p_netlist->i_data_start]->p_payload_end 
196         = p_netlist->pp_free_data[p_netlist->i_data_start]->p_payload_start
197         + p_netlist->i_buffer_size;
198
199     return &p_netlist->p_free_iovec[p_netlist->i_data_start];
200
201 }
202
203 /*****************************************************************************
204  * input_NetlistMviovec: move the iovec pointer after a readv() operation
205  *****************************************************************************/
206 void input_NetlistMviovec( void * p_method_data, size_t i_nb_iovec )
207 {
208     netlist_t * p_netlist;
209
210     /* cast */
211     p_netlist = (netlist_t *) p_method_data;
212     
213     /* lock */
214     vlc_mutex_lock ( &p_netlist->lock );
215     
216     p_netlist->i_data_start += i_nb_iovec;
217     p_netlist->i_data_start %= p_netlist->i_nb_data;
218
219     /* unlock */
220     vlc_mutex_unlock (&p_netlist->lock);
221     
222 }
223
224 /*****************************************************************************
225  * input_NetlistNewPacket: returns a free data_packet_t
226  *****************************************************************************/
227 struct data_packet_s * input_NetlistNewPacket( void * p_method_data,
228                                                size_t i_buffer_size )
229 {    
230     netlist_t * p_netlist; 
231     struct data_packet_s * p_return;
232     
233     /* cast */
234     p_netlist = ( netlist_t * ) p_method_data; 
235
236 #ifdef DEBUG
237     if( i_buffer_size > p_netlist->i_buffer_size )
238     {
239         /* This should not happen */
240         intf_ErrMsg( "Netlist packet too small !" );
241         return NULL;
242     }
243 #endif
244
245     /* lock */
246     vlc_mutex_lock ( &p_netlist->lock );
247         
248     /* check */
249     if ( p_netlist->i_data_start == p_netlist->i_data_end )
250     {
251         intf_ErrMsg("Empty Data FIFO in netlist. Unable to allocate memory");
252         return ( NULL );
253     }
254     
255     p_return = (p_netlist->pp_free_data[p_netlist->i_data_start]);
256     p_netlist->i_data_start++;
257     p_netlist->i_data_start %= p_netlist->i_nb_data;
258
259     /* unlock */
260     vlc_mutex_unlock (&p_netlist->lock);
261
262     if (i_buffer_size < p_netlist->i_buffer_size) 
263     {
264         p_return->p_payload_end = p_return->p_payload_start + i_buffer_size;
265     }
266    
267     /* initialize data */
268     p_return->p_next = NULL;
269     p_return->b_discard_payload = 0;
270     
271     p_return->p_payload_start = p_return->p_buffer;
272     p_return->p_payload_end = p_return->p_payload_start + i_buffer_size;
273     
274     return ( p_return );
275 }
276
277 /*****************************************************************************
278  * input_NetlistNewPES: returns a free pes_packet_t
279  *****************************************************************************/
280 struct pes_packet_s * input_NetlistNewPES( void * p_method_data )
281 {
282     netlist_t * p_netlist;
283     pes_packet_t * p_return;
284     
285     /* cast */ 
286     p_netlist = (netlist_t *) p_method_data;
287     
288     /* lock */
289     vlc_mutex_lock ( &p_netlist->lock );
290     
291     /* check */
292     if ( p_netlist->i_pes_start == p_netlist->i_pes_end )
293     {
294         intf_ErrMsg("Empty PES FIFO in netlist - Unable to allocate memory");
295         return ( NULL );
296     }
297
298     /* allocate */
299     p_return = p_netlist->pp_free_pes[p_netlist->i_pes_start];
300     p_netlist->i_pes_start++;
301     p_netlist->i_pes_start %= p_netlist->i_nb_pes; 
302    
303     /* unlock */
304     vlc_mutex_unlock (&p_netlist->lock);
305     
306     /* initialize PES */
307     p_return->b_messed_up = 
308         p_return->b_data_alignment = 
309         p_return->b_discontinuity = 
310         p_return->i_pts = p_return->i_dts = 0;
311     p_return->i_pes_size = 0;
312     p_return->p_first = NULL;
313    
314     return ( p_return );
315 }
316
317 /*****************************************************************************
318  * input_NetlistDeletePacket: puts a data_packet_t back into the netlist
319  *****************************************************************************/
320 void input_NetlistDeletePacket( void * p_method_data, data_packet_t * p_data )
321 {
322     netlist_t * p_netlist;
323     
324     /* cast */
325     p_netlist = (netlist_t *) p_method_data;
326
327     /* lock */
328     vlc_mutex_lock ( &p_netlist->lock );
329
330     /* Delete data_packet */
331     p_netlist->i_data_end ++;
332     p_netlist->i_data_end %= p_netlist->i_nb_data;
333     p_netlist->pp_free_data[p_netlist->i_data_end] = p_data;
334     
335     p_netlist->p_free_iovec[p_netlist->i_data_end].iov_base = p_data->p_buffer;
336     
337     /* unlock */
338     vlc_mutex_unlock (&p_netlist->lock);
339 }
340
341 /*****************************************************************************
342  * input_NetlistDeletePES: puts a pes_packet_t back into the netlist
343  *****************************************************************************/
344 void input_NetlistDeletePES( void * p_method_data, pes_packet_t * p_pes )
345 {
346     netlist_t * p_netlist; 
347     data_packet_t * p_current_packet;
348     
349     /* cast */
350     p_netlist = (netlist_t *)p_method_data;
351
352     /* lock */
353     vlc_mutex_lock ( &p_netlist->lock );
354
355     /* delete free  p_pes->p_first, p_next ... */
356     p_current_packet = p_pes->p_first;
357     while ( p_current_packet != NULL )
358     {
359         /* copy of NetListDeletePacket, duplicate code avoid many locks */
360
361         p_netlist->i_data_end ++;
362         p_netlist->i_data_end %= p_netlist->i_nb_data;
363         p_netlist->pp_free_data[p_netlist->i_data_end] = p_current_packet;
364         
365         p_netlist->p_free_iovec[p_netlist->i_data_end].iov_base 
366             = p_netlist->p_data->p_buffer;
367     
368         p_current_packet = p_current_packet->p_next;
369     }
370  
371     /* delete our current PES packet */
372     p_netlist->i_pes_end ++;
373     p_netlist->i_pes_end %= p_netlist->i_nb_pes;
374     p_netlist->pp_free_pes[p_netlist->i_pes_end] = p_pes;
375     
376     /* unlock */
377     vlc_mutex_unlock (&p_netlist->lock);
378 }
379
380 /*****************************************************************************
381  * input_NetlistEnd: frees all allocated structures
382  *****************************************************************************/
383 void input_NetlistEnd( input_thread_t * p_input)
384 {
385     netlist_t * p_netlist;
386
387     /* cast */
388     p_netlist = ( netlist_t * ) p_input->p_method_data;
389     
390     /* destroy the mutex lock */
391     vlc_mutex_destroy (&p_netlist->lock);
392     
393     /* free the FIFO, the buffer, and the netlist structure */
394     free (p_netlist->pp_free_data);
395     free (p_netlist->pp_free_pes);
396     free (p_netlist->p_pes);
397     free (p_netlist->p_data);
398     free (p_netlist->p_buffers);
399
400     /* free the netlist */
401     free (p_netlist);
402 }