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-2001 VideoLAN
9 * $Id: input_netlist.c,v 1.47 2001/12/03 17:34:08 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 "intf_msg.h" /* intf_*Msg */
51 #include "threads.h" /* mutex */
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( 4, "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( 4, "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( 4, "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( 4, "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]->p_payload_start = pp_data[i_loop]->p_buffer;
368 pp_data[i_loop]->p_payload_end =
369 pp_data[i_loop]->p_buffer + p_netlist->i_buffer_size;
371 pp_data[i_loop]->p_next = NULL;
372 pp_data[i_loop]->b_discard_payload = 0;
374 pp_data[i_loop]->pi_refcount = p_netlist->pi_refcount +
375 p_netlist->i_iovec_start;
376 if( (*pp_data[i_loop]->pi_refcount) != 0)
378 intf_ErrMsg( "netlist error: refcount should be 0 (%d)",
379 (*pp_data[i_loop]->pi_refcount) );
381 (*pp_data[i_loop]->pi_refcount) = 1;
383 p_netlist->i_iovec_start ++;
384 p_netlist->i_iovec_start &= p_netlist->i_nb_iovec;
386 p_netlist->i_data_start ++;
387 p_netlist->i_data_start &= p_netlist->i_nb_data;
393 vlc_mutex_unlock( &p_netlist->lock );
397 /*****************************************************************************
398 * input_NetlistNewPtr: returns a free data_packet_t
399 * Gives a pointer ; its fields need to be initialized
400 *****************************************************************************/
401 struct data_packet_s * input_NetlistNewPtr( void * p_method_data )
403 netlist_t * p_netlist;
404 struct data_packet_s * p_return;
407 p_netlist = (netlist_t *)p_method_data;
410 vlc_mutex_lock ( &p_netlist->lock );
413 if ( p_netlist->i_data_start == p_netlist->i_data_end )
415 intf_ErrMsg("Empty Data FIFO in netlist. Unable to allocate memory");
419 p_return = (p_netlist->pp_free_data[p_netlist->i_data_start]);
421 p_netlist->i_data_start++;
422 p_netlist->i_data_start &= p_netlist->i_nb_data;
424 p_return->p_payload_start = p_return->p_buffer;
426 p_return->p_payload_end =
427 p_return->p_buffer + p_netlist->i_buffer_size;
429 p_return->p_next = NULL;
430 p_return->b_discard_payload = 0;
433 vlc_mutex_unlock (&p_netlist->lock);
438 /*****************************************************************************
439 * input_NetlistNewPacket: returns a free data_packet_t, and takes
440 * a corresponding storage iovec.
441 *****************************************************************************/
442 struct data_packet_s * input_NetlistNewPacket( void * p_method_data,
443 size_t i_buffer_size )
445 netlist_t * p_netlist;
446 struct data_packet_s * p_packet;
449 p_netlist = (netlist_t *)p_method_data;
452 if( i_buffer_size > p_netlist->i_buffer_size )
454 /* This should not happen */
455 intf_ErrMsg( "Netlist packet too small !" );
461 vlc_mutex_lock( &p_netlist->lock );
464 if ( p_netlist->i_iovec_start == p_netlist->i_iovec_end )
466 intf_ErrMsg("Empty io_vec FIFO in netlist. Unable to allocate memory");
470 if ( p_netlist->i_data_start == p_netlist->i_data_end )
472 intf_ErrMsg("Empty Data FIFO in netlist. Unable to allocate memory");
477 /* Gives an io_vec and associated data */
478 p_packet = p_netlist->pp_free_data[p_netlist->i_data_start];
481 p_netlist->p_free_iovec[p_netlist->i_iovec_start].iov_base;
483 p_packet->p_payload_start = p_packet->p_buffer;
485 p_packet->p_payload_end =
486 p_packet->p_buffer + i_buffer_size;
488 p_packet->p_next = NULL;
489 p_packet->b_discard_payload = 0;
491 p_packet->pi_refcount = p_netlist->pi_refcount + p_netlist->i_iovec_start;
492 if( (*p_packet->pi_refcount) != 0)
494 intf_ErrMsg( "netlist error: refcount should be 0 (%d)",
495 (*p_packet->pi_refcount) );
497 (*p_packet->pi_refcount) = 1;
499 p_netlist->i_iovec_start ++;
500 p_netlist->i_iovec_start &= p_netlist->i_nb_iovec;
502 p_netlist->i_data_start ++;
503 p_netlist->i_data_start &= p_netlist->i_nb_data;
506 vlc_mutex_unlock( &p_netlist->lock );
511 /*****************************************************************************
512 * input_NetlistNewPES: returns a free pes_packet_t
513 *****************************************************************************/
514 struct pes_packet_s * input_NetlistNewPES( void * p_method_data )
516 netlist_t * p_netlist;
517 pes_packet_t * p_return;
520 p_netlist = (netlist_t *)p_method_data;
523 vlc_mutex_lock ( &p_netlist->lock );
526 if ( p_netlist->i_pes_start == p_netlist->i_pes_end )
528 intf_ErrMsg("Empty PES FIFO in netlist - Unable to allocate memory");
533 p_return = p_netlist->pp_free_pes[p_netlist->i_pes_start];
534 p_netlist->i_pes_start++;
535 p_netlist->i_pes_start &= p_netlist->i_nb_pes;
538 vlc_mutex_unlock (&p_netlist->lock);
541 p_return->b_data_alignment = 0;
542 p_return->b_discontinuity = 0;
545 p_return->i_pes_size = 0;
546 p_return->p_first = NULL;
551 /*****************************************************************************
552 * input_NetlistDeletePacket: puts a data_packet_t back into the netlist
553 *****************************************************************************/
554 void input_NetlistDeletePacket( void * p_method_data, data_packet_t * p_data )
556 netlist_t * p_netlist;
559 p_netlist = (netlist_t *) p_method_data;
562 vlc_mutex_lock ( &p_netlist->lock );
564 /* Delete data_packet */
565 p_netlist->i_data_end ++;
566 p_netlist->i_data_end &= p_netlist->i_nb_data;
568 p_data->p_payload_start = p_data->p_buffer;
569 p_data->p_payload_end = p_data->p_buffer + p_netlist->i_buffer_size;
571 p_netlist->pp_free_data[p_netlist->i_data_end] = p_data;
573 p_data->p_next = NULL;
574 p_data->b_discard_payload = 0;
576 /* Update reference counter */
577 (*p_data->pi_refcount)--;
579 if( (*p_data->pi_refcount) == 0 )
581 (*p_data->pi_refcount) = 0;
582 p_netlist->i_iovec_end++;
583 p_netlist->i_iovec_end &= p_netlist->i_nb_iovec;
584 p_netlist->p_free_iovec[p_netlist->i_iovec_end].iov_base =
587 else if( (*p_data->pi_refcount) < 0 )
589 intf_ErrMsg( "netlist error: refcount can't be negative (%d)",
590 (*p_data->pi_refcount) );
594 vlc_mutex_unlock (&p_netlist->lock);
597 /*****************************************************************************
598 * input_NetlistDeletePES: puts a pes_packet_t back into the netlist
599 *****************************************************************************/
600 void input_NetlistDeletePES( void * p_method_data, pes_packet_t * p_pes )
602 netlist_t * p_netlist;
603 data_packet_t * p_current_packet;
604 data_packet_t * p_next_packet;
607 p_netlist = (netlist_t *)p_method_data;
610 vlc_mutex_lock ( &p_netlist->lock );
612 /* delete free p_pes->p_first, p_next ... */
613 p_current_packet = p_pes->p_first;
614 while ( p_current_packet != NULL )
616 /* copy of NetListDeletePacket, duplicate code avoid many locks */
618 p_netlist->i_data_end ++;
619 p_netlist->i_data_end &= p_netlist->i_nb_data;
622 p_current_packet->p_payload_start = p_current_packet->p_buffer;
623 p_current_packet->p_payload_end = p_current_packet->p_buffer
624 + p_netlist->i_buffer_size;
626 p_netlist->pp_free_data[p_netlist->i_data_end] = p_current_packet;
628 /* Update reference counter */
629 (*p_current_packet->pi_refcount)--;
631 if( (*p_current_packet->pi_refcount) == 0 )
633 (*p_current_packet->pi_refcount) = 0;
634 p_netlist->i_iovec_end++;
635 p_netlist->i_iovec_end &= p_netlist->i_nb_iovec;
636 p_netlist->p_free_iovec[p_netlist->i_iovec_end].iov_base =
637 p_current_packet->p_buffer;
639 else if( (*p_current_packet->pi_refcount) < 0 )
641 intf_ErrMsg( "netlist error: refcount can't be negative (%d)",
642 (*p_current_packet->pi_refcount) );
645 p_next_packet = p_current_packet->p_next;
646 p_current_packet->p_next = NULL;
647 p_current_packet->b_discard_payload = 0;
648 p_current_packet = p_next_packet;
651 /* delete our current PES packet */
652 p_netlist->i_pes_end ++;
653 p_netlist->i_pes_end &= p_netlist->i_nb_pes;
654 p_netlist->pp_free_pes[p_netlist->i_pes_end] = p_pes;
657 vlc_mutex_unlock (&p_netlist->lock);
661 /*****************************************************************************
662 * input_NetlistEnd: frees all allocated structures
663 *****************************************************************************/
664 void input_NetlistEnd( input_thread_t * p_input )
666 netlist_t * p_netlist;
669 p_netlist = ( netlist_t * ) p_input->p_method_data;
671 /* destroy the mutex lock */
672 vlc_mutex_destroy( &p_netlist->lock );
674 /* free the FIFO, the buffer, and the netlist structure */
675 free( p_netlist->pi_refcount );
676 free( p_netlist->p_free_iovec );
677 free( p_netlist->pp_free_pes );
678 free( p_netlist->pp_free_data );
679 free( p_netlist->p_pes );
680 free( p_netlist->p_data );
681 free( p_netlist->p_buffers );
683 /* free the netlist */