]> git.sesse.net Git - vlc/blob - plugins/dvd/dvd_netlist.c
a197015d4bb50f343e93c4d1790b0e4639e8fd2e
[vlc] / plugins / dvd / dvd_netlist.c
1 /*****************************************************************************
2  * dvd_netlist.c: Specific netlist for DVD packets
3  * ---
4  * The original is in src/input.
5  * There is only one major change from input_netlist.c : data is now a
6  * pointer to an offset in iovec ; and iovec has a reference counter. It
7  * will only be given back to netlist when refcount is zero.
8  *****************************************************************************
9  * Copyright (C) 1998, 1999, 2000, 2001 VideoLAN
10  * $Id: dvd_netlist.c,v 1.1 2001/03/02 03:32:46 stef Exp $
11  *
12  * Authors: Henri Fallon <henri@videolan.org>
13  *          Stéphane Borel <stef@videolan.org>
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  * 
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
28  *****************************************************************************/
29
30 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #include "defs.h"
34
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <sys/uio.h>                                         /* struct iovec */
38 #include <unistd.h>
39
40 #include "config.h"
41 #include "common.h"
42 #include "threads.h"                                                /* mutex */
43 #include "mtime.h"
44 #include "intf_msg.h"                                           /* intf_*Msg */
45
46 #include "stream_control.h"
47 #include "input_ext-intf.h"
48 #include "input_ext-dec.h"
49
50 #include "input.h"
51 #include "dvd_netlist.h"
52
53 /*****************************************************************************
54  * Local prototypes
55  *****************************************************************************/
56
57 /*****************************************************************************
58  * DVDNetlistInit: allocates netlist buffers and init indexes
59  * ---
60  * Changes from input_NetList: we have to give the length of the buffer which
61  * is different from i_nb_data now, since we may have several data pointers
62  * in one iovec. Thus we can only delete an iovec when its refcount is 0.
63  * We only received a buffer with a GetIovec whereas NewPacket gives a pointer.
64  *
65  * Warning: i_nb_iovec, i_nb_data, i_nb_pes have to be 2^x
66  *****************************************************************************/
67 int DVDNetlistInit( input_thread_t * p_input,
68                     int i_nb_iovec, int i_nb_data, int i_nb_pes,
69                     size_t i_buffer_size, int i_read_once )
70 {
71     unsigned int i_loop;
72     netlist_t * p_netlist;
73
74     /* First we allocate and initialise our netlist struct */
75     p_input->p_method_data = malloc(sizeof(netlist_t));
76     if ( p_input->p_method_data == NULL )
77     {
78         intf_ErrMsg("Unable to malloc the DVD netlist struct");
79         return (-1);
80     }
81     
82     p_netlist = (netlist_t *) p_input->p_method_data;
83
84     /* Nb of packets read once by input */
85     p_netlist->i_read_once = i_read_once;
86     
87     /* allocate the buffers */ 
88     p_netlist->p_buffers = malloc( i_nb_iovec *i_buffer_size );
89     if ( p_netlist->p_buffers == NULL )
90     {
91         intf_ErrMsg ("Unable to malloc in DVD netlist initialization (1)");
92         return (-1);
93     }
94     
95     /* table of pointers to data packets */
96     p_netlist->p_data = malloc( i_nb_data *sizeof(data_packet_t) );
97     if ( p_netlist->p_data == NULL )
98     {
99         intf_ErrMsg ("Unable to malloc in DVD netlist initialization (2)");
100         return (-1);
101     }
102     
103     /* table of pointer to PES packets */
104     p_netlist->p_pes = malloc( i_nb_pes *sizeof(pes_packet_t) );
105     if ( p_netlist->p_pes == NULL )
106     {
107         intf_ErrMsg ("Unable to malloc in DVD netlist initialization (3)");
108         return (-1);
109     }
110     
111     /* allocate the FIFOs : tables of free pointers */
112     p_netlist->pp_free_data = 
113                         malloc( i_nb_data *sizeof(data_packet_t *) );
114     if ( p_netlist->pp_free_data == NULL )
115     {
116         intf_ErrMsg ("Unable to malloc in DVD netlist initialization (4)");
117     }
118     p_netlist->pp_free_pes = 
119                         malloc( i_nb_pes *sizeof(pes_packet_t *) );
120     if ( p_netlist->pp_free_pes == NULL )
121     {
122         intf_ErrMsg ("Unable to malloc in DVD netlist initialization (5)");
123     }
124     
125     p_netlist->p_free_iovec =
126         malloc( (i_nb_iovec + p_netlist->i_read_once) * sizeof(struct iovec) );
127     if ( p_netlist->p_free_iovec == NULL )
128     {
129         intf_ErrMsg ("Unable to malloc in DVD netlist initialization (6)");
130     }
131
132     /* table for reference counter of iovecs */
133     p_netlist->pi_refcount = malloc( i_nb_iovec *sizeof(int) );
134     if ( p_netlist->pi_refcount == NULL )
135     {
136         intf_ErrMsg ("Unable to malloc in DVD netlist initialization (7)");
137         return (-1);
138     }
139
140     /* Fill the data FIFO */
141     for ( i_loop = 0; i_loop < i_nb_data; i_loop++ )
142     {
143         p_netlist->pp_free_data[i_loop] = 
144             p_netlist->p_data + i_loop;
145     }
146
147     /* Fill the PES FIFO */
148     for ( i_loop = 0; i_loop < i_nb_pes ; i_loop++ )
149     {
150         p_netlist->pp_free_pes[i_loop] = 
151             p_netlist->p_pes + i_loop;
152     }
153    
154     /* Deal with the iovec */
155     for ( i_loop = 0; i_loop < i_nb_iovec; i_loop++ )
156     {
157         p_netlist->p_free_iovec[i_loop].iov_base = 
158             p_netlist->p_buffers + i_loop * i_buffer_size;
159    
160         p_netlist->p_free_iovec[i_loop].iov_len = i_buffer_size;
161     }
162
163     /* initialize reference counters */
164     memset( p_netlist->pi_refcount, 0, i_nb_iovec *sizeof(int) );
165    
166     /* vlc_mutex_init */
167     vlc_mutex_init (&p_netlist->lock);
168     
169     /* initialize indexes */
170     p_netlist->i_iovec_start = 0;
171     p_netlist->i_iovec_end = i_nb_iovec - 1;
172
173     p_netlist->i_data_start = 0;
174     p_netlist->i_data_end = i_nb_data - 1;
175
176     p_netlist->i_pes_start = 0;
177     p_netlist->i_pes_end = i_nb_pes - 1;
178
179     /* we give (nb - 1) to use & instead of %
180      * if you really need nb you have to add 1 */
181     p_netlist->i_nb_iovec = i_nb_iovec - 1;
182     p_netlist->i_nb_data = i_nb_data - 1;
183     p_netlist->i_nb_pes = i_nb_pes - 1;
184     p_netlist->i_buffer_size = i_buffer_size;
185
186     return (0); /* Everything went all right */
187 }
188
189 /*****************************************************************************
190  * DVDGetiovec: returns an iovec pointer for a readv() operation
191  *****************************************************************************
192  * We return an iovec vector, so that readv can read many packets at a time,
193  * and we set pp_data to direct to the fifo pointer, which will allow us
194  * to get the corresponding data_packet.
195  *****************************************************************************/
196 struct iovec * DVDGetiovec( void * p_method_data )
197 {
198     netlist_t * p_netlist;
199
200     /* cast */
201     p_netlist = ( netlist_t * ) p_method_data;
202     
203     /* check */
204     if( (
205      (p_netlist->i_iovec_end - p_netlist->i_iovec_start)
206         & p_netlist->i_nb_iovec ) < p_netlist->i_read_once )
207     {
208         intf_ErrMsg("Empty iovec FIFO. Unable to allocate memory");
209         return (NULL);
210     }
211
212     /* readv only takes contiguous buffers 
213      * so, as a solution, we chose to have a FIFO a bit longer
214      * than i_nb_data, and copy the begining of the FIFO to its end
215      * if the readv needs to go after the end */
216     if( p_netlist->i_nb_iovec - p_netlist->i_iovec_start + 1 <
217                                                     p_netlist->i_read_once )
218     {
219         memcpy( &p_netlist->p_free_iovec[p_netlist->i_nb_iovec + 1], 
220                 p_netlist->p_free_iovec, 
221                 (p_netlist->i_read_once -
222                     (p_netlist->i_nb_iovec + 1 - p_netlist->i_iovec_start))
223                     * sizeof(struct iovec)
224               );
225
226     }
227
228     return p_netlist->p_free_iovec + p_netlist->i_iovec_start;
229
230 }
231
232 /*****************************************************************************
233  * DVDMviovec: move the iovec pointer by one after a readv() operation and
234  * gives a data_packet corresponding to iovec in p_data
235  *****************************************************************************/
236 void DVDMviovec( void * p_method_data, int i_nb_iovec,
237                  struct data_packet_s ** pp_data )
238 {
239     netlist_t * p_netlist;
240     unsigned int i_loop = 0;
241
242     /* cast */
243     p_netlist = (netlist_t *)p_method_data;
244     
245     /* lock */
246     vlc_mutex_lock( &p_netlist->lock );
247
248     /* Fills a table of pointers to packets associated with the io_vec's */
249     while( i_loop < i_nb_iovec )
250     {
251         pp_data[i_loop] = p_netlist->pp_free_data[p_netlist->i_data_start];
252         
253         pp_data[i_loop]->p_buffer =
254                     p_netlist->p_free_iovec[p_netlist->i_iovec_start].iov_base;
255         
256         pp_data[i_loop]->pi_refcount = p_netlist->pi_refcount +
257                                        p_netlist->i_iovec_start;
258         p_netlist->i_iovec_start ++;
259         p_netlist->i_iovec_start &= p_netlist->i_nb_iovec;
260
261         p_netlist->i_data_start ++;
262         p_netlist->i_data_start &= p_netlist->i_nb_data;
263
264         i_loop ++;
265     }
266
267     /* unlock */
268     vlc_mutex_unlock( &p_netlist->lock );
269     
270 }
271
272 /*****************************************************************************
273  * DVDNewPtr: returns a free data_packet_t
274  * Gives a pointer ; its fields need to be initialized
275  *****************************************************************************/
276 struct data_packet_s * DVDNewPtr( void * p_method_data )
277 {    
278     netlist_t * p_netlist; 
279     struct data_packet_s * p_return;
280     
281     /* cast */
282     p_netlist = ( netlist_t * ) p_method_data; 
283
284 #ifdef DEBUG
285     if( i_buffer_size > p_netlist->i_buffer_size )
286     {
287         /* This should not happen */
288         intf_ErrMsg( "Netlist packet too small !" );
289         return NULL;
290     }
291 #endif
292
293     /* lock */
294     vlc_mutex_lock ( &p_netlist->lock );
295         
296     /* check */
297     if ( p_netlist->i_data_start == p_netlist->i_data_end )
298     {
299         intf_ErrMsg("Empty Data FIFO in netlist. Unable to allocate memory");
300         return ( NULL );
301     }
302     
303     p_return = (p_netlist->pp_free_data[p_netlist->i_data_start]);
304
305     p_netlist->i_data_start++;
306     p_netlist->i_data_start &= p_netlist->i_nb_data;
307
308     /* unlock */
309     vlc_mutex_unlock (&p_netlist->lock);
310
311     return ( p_return );
312 }
313
314 /*****************************************************************************
315  * DVDNewPacket: returns a free data_packet_t, and takes a corresponding
316  * storage iovec
317  *****************************************************************************/
318 struct data_packet_s * DVDNewPacket( void * p_method_data,
319                                      size_t i_buffer_size )
320 {
321     netlist_t *             p_netlist;
322     struct data_packet_s *  p_packet;
323
324     /* cast */
325     p_netlist = (netlist_t *)p_method_data;
326     
327     /* lock */
328     vlc_mutex_lock( &p_netlist->lock );
329
330      /* check */
331     if ( p_netlist->i_iovec_start == p_netlist->i_iovec_end )
332     {
333         intf_ErrMsg("Empty io_vec FIFO in netlist. Unable to allocate memory");
334         return ( NULL );
335     }
336
337     if ( p_netlist->i_data_start == p_netlist->i_data_end )
338     {
339         intf_ErrMsg("Empty Data FIFO in netlist. Unable to allocate memory");
340         return ( NULL );
341     }
342
343
344     /* Gives an io_vec and associated data */
345     p_packet = p_netlist->pp_free_data[p_netlist->i_data_start];
346         
347     p_packet->p_buffer =
348                p_netlist->p_free_iovec[p_netlist->i_iovec_start].iov_base;
349         
350     p_packet->p_payload_start = p_packet->p_buffer;
351         
352     p_packet->p_payload_end =
353                p_packet->p_buffer + i_buffer_size;
354
355     p_packet->pi_refcount = p_netlist->pi_refcount + p_netlist->i_iovec_start;
356
357     p_netlist->i_iovec_start ++;
358     p_netlist->i_iovec_start &= p_netlist->i_nb_iovec;
359
360     p_netlist->i_data_start ++;
361     p_netlist->i_data_start &= p_netlist->i_nb_data;
362
363     /* unlock */
364     vlc_mutex_unlock( &p_netlist->lock );
365
366     return p_packet;
367 }
368
369 /*****************************************************************************
370  * DVDNewPES: returns a free pes_packet_t
371  *****************************************************************************/
372 struct pes_packet_s * DVDNewPES( void * p_method_data )
373 {
374     netlist_t * p_netlist;
375     pes_packet_t * p_return;
376     
377     /* cast */ 
378     p_netlist = (netlist_t *) p_method_data;
379     
380     /* lock */
381     vlc_mutex_lock ( &p_netlist->lock );
382     
383     /* check */
384     if ( p_netlist->i_pes_start == p_netlist->i_pes_end )
385     {
386         intf_ErrMsg("Empty PES FIFO in netlist - Unable to allocate memory");
387         return ( NULL );
388     }
389
390     /* allocate */
391     p_return = p_netlist->pp_free_pes[p_netlist->i_pes_start];
392     p_netlist->i_pes_start++;
393     p_netlist->i_pes_start &= p_netlist->i_nb_pes; 
394    
395     /* unlock */
396     vlc_mutex_unlock (&p_netlist->lock);
397     
398     /* initialize PES */
399     p_return->b_data_alignment = 
400         p_return->b_discontinuity = 
401         p_return->i_pts = p_return->i_dts = 0;
402     p_return->i_pes_size = 0;
403     p_return->p_first = NULL;
404    
405     return ( p_return );
406 }
407
408 /*****************************************************************************
409  * DVDDeletePacket: puts a data_packet_t back into the netlist
410  *****************************************************************************/
411 void DVDDeletePacket( void * p_method_data, data_packet_t * p_data )
412 {
413     netlist_t * p_netlist;
414     
415     /* cast */
416     p_netlist = (netlist_t *) p_method_data;
417
418     /* lock */
419     vlc_mutex_lock ( &p_netlist->lock );
420
421
422    /* Delete data_packet */
423     p_netlist->i_data_end ++;
424     p_netlist->i_data_end &= p_netlist->i_nb_data;
425     
426     p_netlist->pp_free_data[p_netlist->i_data_end] = p_data;
427
428     /* Update reference counter */
429     (*p_data->pi_refcount)--;
430
431     if( (*p_data->pi_refcount) == 0 )
432     {
433
434         p_netlist->i_iovec_end++;
435         p_netlist->i_iovec_end &= p_netlist->i_nb_iovec;
436         p_netlist->p_free_iovec[p_netlist->i_iovec_end].iov_base =
437                                                             p_data->p_buffer;
438     }
439
440     /* re initialize for next time */
441     p_data->p_next = NULL;
442     p_data->b_discard_payload = 0;
443  
444     /* unlock */
445     vlc_mutex_unlock (&p_netlist->lock);
446 }
447
448 /*****************************************************************************
449  * DVDDeletePES: puts a pes_packet_t back into the netlist
450  *****************************************************************************/
451 void DVDDeletePES( void * p_method_data, pes_packet_t * p_pes )
452 {
453     netlist_t * p_netlist; 
454     data_packet_t * p_current_packet,* p_next_packet;
455     
456     /* cast */
457     p_netlist = (netlist_t *)p_method_data;
458
459     /* lock */
460     vlc_mutex_lock ( &p_netlist->lock );
461
462     /* delete free  p_pes->p_first, p_next ... */
463     p_current_packet = p_pes->p_first;
464     while ( p_current_packet != NULL )
465     {
466         /* copy of NetListDeletePacket, duplicate code avoid many locks */
467
468         p_netlist->i_data_end ++;
469         p_netlist->i_data_end &= p_netlist->i_nb_data;
470
471         /* re initialize*/
472         p_current_packet->p_payload_start = p_current_packet->p_buffer;
473         
474         p_netlist->pp_free_data[p_netlist->i_data_end] = p_current_packet;
475
476         /* Update reference counter */
477         (*p_current_packet->pi_refcount)--;
478
479         if( (*p_current_packet->pi_refcount) == 0 )
480         {
481             p_netlist->i_iovec_end++;
482             p_netlist->i_iovec_end &= p_netlist->i_nb_iovec;
483             p_netlist->p_free_iovec[p_netlist->i_iovec_end].iov_base =
484                     p_current_packet->p_buffer;
485         }
486     
487         p_next_packet = p_current_packet->p_next;
488         p_current_packet->p_next = NULL;
489         p_current_packet = p_next_packet;
490     }
491  
492     /* delete our current PES packet */
493     p_netlist->i_pes_end ++;
494     p_netlist->i_pes_end &= p_netlist->i_nb_pes;
495     p_netlist->pp_free_pes[p_netlist->i_pes_end] = p_pes;
496     
497     /* unlock */
498     vlc_mutex_unlock (&p_netlist->lock);
499
500 }
501
502 /*****************************************************************************
503  * DVDNetlistEnd: frees all allocated structures
504  *****************************************************************************/
505 void DVDNetlistEnd( input_thread_t * p_input)
506 {
507     netlist_t * p_netlist;
508
509     /* cast */
510     p_netlist = ( netlist_t * ) p_input->p_method_data;
511     
512     /* destroy the mutex lock */
513     vlc_mutex_destroy (&p_netlist->lock);
514     
515     /* free the FIFO, the buffer, and the netlist structure */
516     free (p_netlist->pp_free_data);
517     free (p_netlist->pp_free_pes);
518     free (p_netlist->pi_refcount);
519     free (p_netlist->p_pes);
520     free (p_netlist->p_data);
521     free (p_netlist->p_buffers);
522
523     /* free the netlist */
524     free (p_netlist);
525 }