1 /*****************************************************************************
2 * dvd_netlist.c: netlist management v2
3 *****************************************************************************
4 * There is only one major change from input_netlist.c (1) : data is now a
5 * pointer to an offset in iovec ; and iovec has a reference counter. It
6 * will only be given back to netlist when refcount is zero.
7 *****************************************************************************
8 * Copyright (C) 1998, 1999, 2000, 2001 VideoLAN
9 * $Id: input_netlist.c,v 1.43 2001/11/11 01:32:03 stef Exp $
11 * Authors: Henri Fallon <henri@videolan.org>
12 * Stéphane Borel <stef@videolan.org>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
27 *****************************************************************************/
29 /*****************************************************************************
31 *****************************************************************************/
35 #include <string.h> /* memcpy(), memset() */
36 #include <sys/types.h>
43 # include <io.h> /* read() */
45 # include <sys/uio.h> /* struct iovec */
50 #include "threads.h" /* mutex */
52 #include "intf_msg.h" /* intf_*Msg */
55 # include "input_iovec.h"
58 #include "stream_control.h"
59 #include "input_ext-intf.h"
60 #include "input_ext-dec.h"
61 #include "input_ext-plugins.h"
63 /*****************************************************************************
65 *****************************************************************************/
67 /*****************************************************************************
68 * input_NetlistInit: allocates netlist buffers and init indexes
70 * Changes from input_NetList: we have to give the length of the buffer which
71 * is different from i_nb_data now, since we may have several data pointers
72 * in one iovec. Thus we can only delete an iovec when its refcount is 0.
73 * We only received a buffer with a GetIovec whereas NewPacket gives a pointer.
74 *****************************************************************************/
75 int input_NetlistInit( input_thread_t * p_input,
76 int i_nb_iovec, int i_nb_data, int i_nb_pes,
77 size_t i_buffer_size, int i_read_once )
80 netlist_t * p_netlist;
82 /* First we allocate and initialise our netlist struct */
83 p_input->p_method_data = malloc(sizeof(netlist_t));
84 if ( p_input->p_method_data == NULL )
86 intf_ErrMsg("Unable to malloc the netlist struct");
90 p_netlist = (netlist_t *) p_input->p_method_data;
92 /* Nb of packets read once by input */
93 p_netlist->i_read_once = i_read_once;
95 /* In order to optimize netlist, we are taking i_nb_data a 2^i
96 * so that modulo is an "&".
97 * This is not changing i_nb data outside this function except in
98 * the netlist_t struct */
99 /* As i_loop is unsigned int, and i_ns_data int, this shouldn't be a
101 for( i_loop = 1; i_loop < i_nb_data; i_loop *= 2 )
106 intf_DbgMsg( "Netlist : Required %i byte, got %u",i_nb_data,i_loop );
109 /* Same thing for i_nb_pes */
110 for( i_loop = 1; i_loop < i_nb_pes; i_loop *= 2 )
115 intf_DbgMsg( "Netlist : Required %i byte, got %u",i_nb_pes,i_loop );
118 /* Same thing for i_nb_iovec */
119 for( i_loop = 1; i_loop < i_nb_iovec; i_loop *= 2 )
124 intf_DbgMsg( "Netlist : Required %i byte, got %u",i_nb_iovec,i_loop );
127 /* allocate the buffers */
128 p_netlist->p_buffers = malloc( i_nb_iovec *i_buffer_size );
129 if ( p_netlist->p_buffers == NULL )
131 intf_ErrMsg ("Unable to malloc in netlist initialization (1)");
136 /* table of pointers to data packets */
137 p_netlist->p_data = malloc( i_nb_data *sizeof(data_packet_t) );
138 if ( p_netlist->p_data == NULL )
140 intf_ErrMsg ("Unable to malloc in netlist initialization (2)");
141 free( p_netlist->p_buffers );
146 /* table of pointer to PES packets */
147 p_netlist->p_pes = malloc( i_nb_pes *sizeof(pes_packet_t) );
148 if ( p_netlist->p_pes == NULL )
150 intf_ErrMsg ("Unable to malloc in netlist initialization (3)");
151 free( p_netlist->p_buffers );
152 free( p_netlist->p_data );
157 /* allocate the FIFOs : tables of free pointers */
158 p_netlist->pp_free_data =
159 malloc( i_nb_data *sizeof(data_packet_t *) );
160 if ( p_netlist->pp_free_data == NULL )
162 intf_ErrMsg ("Unable to malloc in netlist initialization (4)");
163 free( p_netlist->p_buffers );
164 free( p_netlist->p_data );
165 free( p_netlist->p_pes );
169 p_netlist->pp_free_pes =
170 malloc( i_nb_pes *sizeof(pes_packet_t *) );
171 if ( p_netlist->pp_free_pes == NULL )
173 intf_ErrMsg ("Unable to malloc in netlist initialization (5)");
174 free( p_netlist->p_buffers );
175 free( p_netlist->p_data );
176 free( p_netlist->p_pes );
177 free( p_netlist->pp_free_data );
182 p_netlist->p_free_iovec =
183 malloc( (i_nb_iovec + p_netlist->i_read_once) * sizeof(struct iovec) );
184 if ( p_netlist->p_free_iovec == NULL )
186 intf_ErrMsg ("Unable to malloc in DVD netlist initialization (6)");
187 free( p_netlist->p_buffers );
188 free( p_netlist->p_data );
189 free( p_netlist->p_pes );
190 free( p_netlist->pp_free_data );
191 free( p_netlist->pp_free_pes );
196 /* table for reference counter of iovecs */
197 p_netlist->pi_refcount = malloc( i_nb_iovec *sizeof(int) );
198 if ( p_netlist->pi_refcount == NULL )
200 intf_ErrMsg ("Unable to malloc in DVD netlist initialization (7)");
201 free( p_netlist->p_buffers );
202 free( p_netlist->p_data );
203 free( p_netlist->p_pes );
204 free( p_netlist->pp_free_data );
205 free( p_netlist->pp_free_pes );
206 free( p_netlist->p_free_iovec );
211 /* Fill the data FIFO */
212 for ( i_loop = 0; i_loop < i_nb_data; i_loop++ )
214 p_netlist->pp_free_data[i_loop] =
215 p_netlist->p_data + i_loop;
217 /* by default, one data packet for one buffer */
218 if( i_nb_data == i_nb_iovec )
220 p_netlist->pp_free_data[i_loop]->p_buffer =
221 p_netlist->p_buffers + i_loop * i_buffer_size;
223 p_netlist->pp_free_data[i_loop]->p_payload_start =
224 p_netlist->pp_free_data[i_loop]->p_buffer;
226 p_netlist->pp_free_data[i_loop]->p_payload_end =
227 p_netlist->pp_free_data[i_loop]->p_buffer + i_buffer_size;
231 /* Fill the PES FIFO */
232 for ( i_loop = 0; i_loop < i_nb_pes ; i_loop++ )
234 p_netlist->pp_free_pes[i_loop] =
235 p_netlist->p_pes + i_loop;
238 /* Deal with the iovec */
239 for ( i_loop = 0; i_loop < i_nb_iovec; i_loop++ )
241 p_netlist->p_free_iovec[i_loop].iov_base =
242 p_netlist->p_buffers + i_loop * i_buffer_size;
244 p_netlist->p_free_iovec[i_loop].iov_len = i_buffer_size;
247 /* initialize reference counters */
248 memset( p_netlist->pi_refcount, 0, i_nb_iovec *sizeof(int) );
251 vlc_mutex_init (&p_netlist->lock);
253 /* initialize indexes */
254 p_netlist->i_iovec_start = 0;
255 p_netlist->i_iovec_end = i_nb_iovec - 1;
257 p_netlist->i_data_start = 0;
258 p_netlist->i_data_end = i_nb_data - 1;
260 p_netlist->i_pes_start = 0;
261 p_netlist->i_pes_end = i_nb_pes - 1;
263 /* we give (nb - 1) to use & instead of %
264 * if you really need nb you have to add 1 */
265 p_netlist->i_nb_iovec = i_nb_iovec - 1;
266 p_netlist->i_nb_data = i_nb_data - 1;
267 p_netlist->i_nb_pes = i_nb_pes - 1;
268 p_netlist->i_buffer_size = i_buffer_size;
270 return 0; /* Everything went all right */
273 /*****************************************************************************
274 * input_NetlistGetiovec: returns an iovec pointer for a readv() operation
275 *****************************************************************************
276 * We return an iovec vector, so that readv can read many packets at a time.
277 * pp_data will be set to direct to the fifo pointer in DVDMviovec, which
278 * will allow us to get the corresponding data_packet.
279 *****************************************************************************/
280 struct iovec * input_NetlistGetiovec( void * p_method_data )
282 netlist_t * p_netlist;
285 p_netlist = (netlist_t *)p_method_data;
287 /* check that we have enough free iovec */
289 (p_netlist->i_iovec_end - p_netlist->i_iovec_start)
290 & p_netlist->i_nb_iovec ) < p_netlist->i_read_once )
292 intf_WarnMsg( 12, "input info: waiting for free iovec" );
293 msleep( INPUT_IDLE_SLEEP );
296 (p_netlist->i_iovec_end - p_netlist->i_iovec_start)
297 & p_netlist->i_nb_iovec ) < p_netlist->i_read_once )
299 msleep( INPUT_IDLE_SLEEP );
302 intf_WarnMsg( 12, "input info: found free iovec" );
306 (p_netlist->i_data_end - p_netlist->i_data_start)
307 & p_netlist->i_nb_data ) < p_netlist->i_read_once )
309 intf_WarnMsg( 12, "input info: waiting for free data packet" );
310 msleep( INPUT_IDLE_SLEEP );
313 (p_netlist->i_data_end - p_netlist->i_data_start)
314 & p_netlist->i_nb_data ) < p_netlist->i_read_once )
316 msleep( INPUT_IDLE_SLEEP );
319 intf_WarnMsg( 12, "input info: found free data packet" );
322 /* readv only takes contiguous buffers
323 * so, as a solution, we chose to have a FIFO a bit longer
324 * than i_nb_data, and copy the begining of the FIFO to its end
325 * if the readv needs to go after the end */
326 if( p_netlist->i_nb_iovec - p_netlist->i_iovec_start + 1 <
327 p_netlist->i_read_once )
329 memcpy( &p_netlist->p_free_iovec[p_netlist->i_nb_iovec + 1],
330 p_netlist->p_free_iovec,
331 (p_netlist->i_read_once -
332 (p_netlist->i_nb_iovec + 1 - p_netlist->i_iovec_start))
333 * sizeof(struct iovec)
338 return p_netlist->p_free_iovec + p_netlist->i_iovec_start;
342 /*****************************************************************************
343 * input_NetlistMviovec: move the iovec pointer by one after a readv()
344 * operation and gives a data_packet corresponding to iovec in p_data
345 *****************************************************************************/
346 void input_NetlistMviovec( void * p_method_data, int i_nb_iovec,
347 struct data_packet_s ** pp_data )
349 netlist_t * p_netlist;
350 unsigned int i_loop = 0;
353 p_netlist = (netlist_t *)p_method_data;
356 vlc_mutex_lock( &p_netlist->lock );
358 /* Fills a table of pointers to packets associated with the io_vec's */
359 while( i_loop < i_nb_iovec )
361 pp_data[i_loop] = p_netlist->pp_free_data[p_netlist->i_data_start];
363 pp_data[i_loop]->p_buffer =
364 p_netlist->p_free_iovec[p_netlist->i_iovec_start].iov_base;
366 pp_data[i_loop]->pi_refcount = p_netlist->pi_refcount +
367 p_netlist->i_iovec_start;
368 (*pp_data[i_loop]->pi_refcount)++;
370 p_netlist->i_iovec_start ++;
371 p_netlist->i_iovec_start &= p_netlist->i_nb_iovec;
373 p_netlist->i_data_start ++;
374 p_netlist->i_data_start &= p_netlist->i_nb_data;
380 vlc_mutex_unlock( &p_netlist->lock );
384 /*****************************************************************************
385 * input_NetlistNewPtr: returns a free data_packet_t
386 * Gives a pointer ; its fields need to be initialized
387 *****************************************************************************/
388 struct data_packet_s * input_NetlistNewPtr( void * p_method_data )
390 netlist_t * p_netlist;
391 struct data_packet_s * p_return;
394 p_netlist = (netlist_t *)p_method_data;
397 vlc_mutex_lock ( &p_netlist->lock );
400 if ( p_netlist->i_data_start == p_netlist->i_data_end )
402 intf_ErrMsg("Empty Data FIFO in netlist. Unable to allocate memory");
406 p_return = (p_netlist->pp_free_data[p_netlist->i_data_start]);
408 p_netlist->i_data_start++;
409 p_netlist->i_data_start &= p_netlist->i_nb_data;
412 vlc_mutex_unlock (&p_netlist->lock);
417 /*****************************************************************************
418 * input_NetlistNewPacket: returns a free data_packet_t, and takes
419 * a corresponding storage iovec.
420 *****************************************************************************/
421 struct data_packet_s * input_NetlistNewPacket( void * p_method_data,
422 size_t i_buffer_size )
424 netlist_t * p_netlist;
425 struct data_packet_s * p_packet;
428 p_netlist = (netlist_t *)p_method_data;
431 if( i_buffer_size > p_netlist->i_buffer_size )
433 /* This should not happen */
434 intf_ErrMsg( "Netlist packet too small !" );
440 vlc_mutex_lock( &p_netlist->lock );
443 if ( p_netlist->i_iovec_start == p_netlist->i_iovec_end )
445 intf_ErrMsg("Empty io_vec FIFO in netlist. Unable to allocate memory");
449 if ( p_netlist->i_data_start == p_netlist->i_data_end )
451 intf_ErrMsg("Empty Data FIFO in netlist. Unable to allocate memory");
456 /* Gives an io_vec and associated data */
457 p_packet = p_netlist->pp_free_data[p_netlist->i_data_start];
460 p_netlist->p_free_iovec[p_netlist->i_iovec_start].iov_base;
462 p_packet->p_payload_start = p_packet->p_buffer;
464 p_packet->p_payload_end =
465 p_packet->p_buffer + i_buffer_size;
467 p_packet->p_next = NULL;
468 p_packet->b_discard_payload = 0;
470 p_packet->pi_refcount = p_netlist->pi_refcount + p_netlist->i_iovec_start;
471 (*p_packet->pi_refcount)++;
473 p_netlist->i_iovec_start ++;
474 p_netlist->i_iovec_start &= p_netlist->i_nb_iovec;
476 p_netlist->i_data_start ++;
477 p_netlist->i_data_start &= p_netlist->i_nb_data;
480 vlc_mutex_unlock( &p_netlist->lock );
485 /*****************************************************************************
486 * input_NetlistNewPES: returns a free pes_packet_t
487 *****************************************************************************/
488 struct pes_packet_s * input_NetlistNewPES( void * p_method_data )
490 netlist_t * p_netlist;
491 pes_packet_t * p_return;
494 p_netlist = (netlist_t *)p_method_data;
497 vlc_mutex_lock ( &p_netlist->lock );
500 if ( p_netlist->i_pes_start == p_netlist->i_pes_end )
502 intf_ErrMsg("Empty PES FIFO in netlist - Unable to allocate memory");
507 p_return = p_netlist->pp_free_pes[p_netlist->i_pes_start];
508 p_netlist->i_pes_start++;
509 p_netlist->i_pes_start &= p_netlist->i_nb_pes;
512 vlc_mutex_unlock (&p_netlist->lock);
515 p_return->b_data_alignment = 0;
516 p_return->b_discontinuity = 0;
519 p_return->i_pes_size = 0;
520 p_return->p_first = NULL;
525 /*****************************************************************************
526 * input_NetlistDeletePacket: puts a data_packet_t back into the netlist
527 *****************************************************************************/
528 void input_NetlistDeletePacket( void * p_method_data, data_packet_t * p_data )
530 netlist_t * p_netlist;
533 p_netlist = (netlist_t *) p_method_data;
536 vlc_mutex_lock ( &p_netlist->lock );
538 /* Delete data_packet */
539 p_netlist->i_data_end ++;
540 p_netlist->i_data_end &= p_netlist->i_nb_data;
542 p_data->p_payload_start = p_data->p_buffer;
543 p_data->p_payload_end = p_data->p_buffer + p_netlist->i_buffer_size;
545 p_netlist->pp_free_data[p_netlist->i_data_end] = p_data;
547 p_data->p_next = NULL;
548 p_data->b_discard_payload = 0;
550 /* Update reference counter */
551 (*p_data->pi_refcount)--;
553 if( (*p_data->pi_refcount) <= 0 )
556 p_netlist->i_iovec_end++;
557 p_netlist->i_iovec_end &= p_netlist->i_nb_iovec;
558 p_netlist->p_free_iovec[p_netlist->i_iovec_end].iov_base =
563 vlc_mutex_unlock (&p_netlist->lock);
566 /*****************************************************************************
567 * input_NetlistDeletePES: puts a pes_packet_t back into the netlist
568 *****************************************************************************/
569 void input_NetlistDeletePES( void * p_method_data, pes_packet_t * p_pes )
571 netlist_t * p_netlist;
572 data_packet_t * p_current_packet;
573 data_packet_t * p_next_packet;
576 p_netlist = (netlist_t *)p_method_data;
579 vlc_mutex_lock ( &p_netlist->lock );
581 /* delete free p_pes->p_first, p_next ... */
582 p_current_packet = p_pes->p_first;
583 while ( p_current_packet != NULL )
585 /* copy of NetListDeletePacket, duplicate code avoid many locks */
587 p_netlist->i_data_end ++;
588 p_netlist->i_data_end &= p_netlist->i_nb_data;
591 p_current_packet->p_payload_start = p_current_packet->p_buffer;
592 p_current_packet->p_payload_end = p_current_packet->p_buffer
593 + p_netlist->i_buffer_size;
595 p_netlist->pp_free_data[p_netlist->i_data_end] = p_current_packet;
597 /* Update reference counter */
598 (*p_current_packet->pi_refcount)--;
600 if( (*p_current_packet->pi_refcount) <= 0 )
602 (*p_current_packet->pi_refcount) = 0;
603 p_netlist->i_iovec_end++;
604 p_netlist->i_iovec_end &= p_netlist->i_nb_iovec;
605 p_netlist->p_free_iovec[p_netlist->i_iovec_end].iov_base =
606 p_current_packet->p_buffer;
609 p_next_packet = p_current_packet->p_next;
610 p_current_packet->p_next = NULL;
611 p_current_packet->b_discard_payload = 0;
612 p_current_packet = p_next_packet;
615 /* delete our current PES packet */
616 p_netlist->i_pes_end ++;
617 p_netlist->i_pes_end &= p_netlist->i_nb_pes;
618 p_netlist->pp_free_pes[p_netlist->i_pes_end] = p_pes;
621 vlc_mutex_unlock (&p_netlist->lock);
625 /*****************************************************************************
626 * input_NetlistEnd: frees all allocated structures
627 *****************************************************************************/
628 void input_NetlistEnd( input_thread_t * p_input )
630 netlist_t * p_netlist;
633 p_netlist = ( netlist_t * ) p_input->p_method_data;
635 /* destroy the mutex lock */
636 vlc_mutex_destroy( &p_netlist->lock );
638 /* free the FIFO, the buffer, and the netlist structure */
639 free( p_netlist->pi_refcount );
640 free( p_netlist->p_free_iovec );
641 free( p_netlist->pp_free_pes );
642 free( p_netlist->pp_free_data );
643 free( p_netlist->p_pes );
644 free( p_netlist->p_data );
645 free( p_netlist->p_buffers );
647 /* free the netlist */