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.48 2001/12/09 17:01:37 sam 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 */
49 #include "intf_msg.h" /* intf_*Msg */
50 #include "threads.h" /* mutex */
54 # include "input_iovec.h"
57 #include "stream_control.h"
58 #include "input_ext-intf.h"
59 #include "input_ext-dec.h"
60 #include "input_ext-plugins.h"
62 /*****************************************************************************
64 *****************************************************************************/
66 /*****************************************************************************
67 * input_NetlistInit: allocates netlist buffers and init indexes
69 * Changes from input_NetList: we have to give the length of the buffer which
70 * is different from i_nb_data now, since we may have several data pointers
71 * in one iovec. Thus we can only delete an iovec when its refcount is 0.
72 * We only received a buffer with a GetIovec whereas NewPacket gives a pointer.
73 *****************************************************************************/
74 int input_NetlistInit( input_thread_t * p_input,
75 int i_nb_iovec, int i_nb_data, int i_nb_pes,
76 size_t i_buffer_size, int i_read_once )
79 netlist_t * p_netlist;
81 /* First we allocate and initialise our netlist struct */
82 p_input->p_method_data = malloc(sizeof(netlist_t));
83 if ( p_input->p_method_data == NULL )
85 intf_ErrMsg("Unable to malloc the netlist struct");
89 p_netlist = (netlist_t *) p_input->p_method_data;
91 /* Nb of packets read once by input */
92 p_netlist->i_read_once = i_read_once;
94 /* In order to optimize netlist, we are taking i_nb_data a 2^i
95 * so that modulo is an "&".
96 * This is not changing i_nb data outside this function except in
97 * the netlist_t struct */
98 /* As i_loop is unsigned int, and i_ns_data int, this shouldn't be a
100 for( i_loop = 1; i_loop < i_nb_data; i_loop *= 2 )
105 intf_DbgMsg( "Netlist : Required %i byte, got %u",i_nb_data,i_loop );
108 /* Same thing for i_nb_pes */
109 for( i_loop = 1; i_loop < i_nb_pes; i_loop *= 2 )
114 intf_DbgMsg( "Netlist : Required %i byte, got %u",i_nb_pes,i_loop );
117 /* Same thing for i_nb_iovec */
118 for( i_loop = 1; i_loop < i_nb_iovec; i_loop *= 2 )
123 intf_DbgMsg( "Netlist : Required %i byte, got %u",i_nb_iovec,i_loop );
126 /* allocate the buffers */
127 p_netlist->p_buffers = malloc( i_nb_iovec *i_buffer_size );
128 if ( p_netlist->p_buffers == NULL )
130 intf_ErrMsg ("Unable to malloc in netlist initialization (1)");
135 /* table of pointers to data packets */
136 p_netlist->p_data = malloc( i_nb_data *sizeof(data_packet_t) );
137 if ( p_netlist->p_data == NULL )
139 intf_ErrMsg ("Unable to malloc in netlist initialization (2)");
140 free( p_netlist->p_buffers );
145 /* table of pointer to PES packets */
146 p_netlist->p_pes = malloc( i_nb_pes *sizeof(pes_packet_t) );
147 if ( p_netlist->p_pes == NULL )
149 intf_ErrMsg ("Unable to malloc in netlist initialization (3)");
150 free( p_netlist->p_buffers );
151 free( p_netlist->p_data );
156 /* allocate the FIFOs : tables of free pointers */
157 p_netlist->pp_free_data =
158 malloc( i_nb_data *sizeof(data_packet_t *) );
159 if ( p_netlist->pp_free_data == NULL )
161 intf_ErrMsg ("Unable to malloc in netlist initialization (4)");
162 free( p_netlist->p_buffers );
163 free( p_netlist->p_data );
164 free( p_netlist->p_pes );
168 p_netlist->pp_free_pes =
169 malloc( i_nb_pes *sizeof(pes_packet_t *) );
170 if ( p_netlist->pp_free_pes == NULL )
172 intf_ErrMsg ("Unable to malloc in netlist initialization (5)");
173 free( p_netlist->p_buffers );
174 free( p_netlist->p_data );
175 free( p_netlist->p_pes );
176 free( p_netlist->pp_free_data );
181 p_netlist->p_free_iovec =
182 malloc( (i_nb_iovec + p_netlist->i_read_once) * sizeof(struct iovec) );
183 if ( p_netlist->p_free_iovec == NULL )
185 intf_ErrMsg ("Unable to malloc in DVD netlist initialization (6)");
186 free( p_netlist->p_buffers );
187 free( p_netlist->p_data );
188 free( p_netlist->p_pes );
189 free( p_netlist->pp_free_data );
190 free( p_netlist->pp_free_pes );
195 /* table for reference counter of iovecs */
196 p_netlist->pi_refcount = malloc( i_nb_iovec *sizeof(int) );
197 if ( p_netlist->pi_refcount == NULL )
199 intf_ErrMsg ("Unable to malloc in DVD netlist initialization (7)");
200 free( p_netlist->p_buffers );
201 free( p_netlist->p_data );
202 free( p_netlist->p_pes );
203 free( p_netlist->pp_free_data );
204 free( p_netlist->pp_free_pes );
205 free( p_netlist->p_free_iovec );
210 /* Fill the data FIFO */
211 for ( i_loop = 0; i_loop < i_nb_data; i_loop++ )
213 p_netlist->pp_free_data[i_loop] =
214 p_netlist->p_data + i_loop;
216 /* by default, one data packet for one buffer */
217 if( i_nb_data == i_nb_iovec )
219 p_netlist->pp_free_data[i_loop]->p_buffer =
220 p_netlist->p_buffers + i_loop * i_buffer_size;
222 p_netlist->pp_free_data[i_loop]->p_payload_start =
223 p_netlist->pp_free_data[i_loop]->p_buffer;
225 p_netlist->pp_free_data[i_loop]->p_payload_end =
226 p_netlist->pp_free_data[i_loop]->p_buffer + i_buffer_size;
230 /* Fill the PES FIFO */
231 for ( i_loop = 0; i_loop < i_nb_pes ; i_loop++ )
233 p_netlist->pp_free_pes[i_loop] =
234 p_netlist->p_pes + i_loop;
237 /* Deal with the iovec */
238 for ( i_loop = 0; i_loop < i_nb_iovec; i_loop++ )
240 p_netlist->p_free_iovec[i_loop].iov_base =
241 p_netlist->p_buffers + i_loop * i_buffer_size;
243 p_netlist->p_free_iovec[i_loop].iov_len = i_buffer_size;
246 /* initialize reference counters */
247 memset( p_netlist->pi_refcount, 0, i_nb_iovec *sizeof(int) );
250 vlc_mutex_init (&p_netlist->lock);
252 /* initialize indexes */
253 p_netlist->i_iovec_start = 0;
254 p_netlist->i_iovec_end = i_nb_iovec - 1;
256 p_netlist->i_data_start = 0;
257 p_netlist->i_data_end = i_nb_data - 1;
259 p_netlist->i_pes_start = 0;
260 p_netlist->i_pes_end = i_nb_pes - 1;
262 /* we give (nb - 1) to use & instead of %
263 * if you really need nb you have to add 1 */
264 p_netlist->i_nb_iovec = i_nb_iovec - 1;
265 p_netlist->i_nb_data = i_nb_data - 1;
266 p_netlist->i_nb_pes = i_nb_pes - 1;
267 p_netlist->i_buffer_size = i_buffer_size;
269 return 0; /* Everything went all right */
272 /*****************************************************************************
273 * input_NetlistGetiovec: returns an iovec pointer for a readv() operation
274 *****************************************************************************
275 * We return an iovec vector, so that readv can read many packets at a time.
276 * pp_data will be set to direct to the fifo pointer in DVDMviovec, which
277 * will allow us to get the corresponding data_packet.
278 *****************************************************************************/
279 struct iovec * input_NetlistGetiovec( void * p_method_data )
281 netlist_t * p_netlist;
284 p_netlist = (netlist_t *)p_method_data;
286 /* check that we have enough free iovec */
288 (p_netlist->i_iovec_end - p_netlist->i_iovec_start)
289 & p_netlist->i_nb_iovec ) < p_netlist->i_read_once )
291 intf_WarnMsg( 4, "input info: waiting for free iovec" );
292 msleep( INPUT_IDLE_SLEEP );
295 (p_netlist->i_iovec_end - p_netlist->i_iovec_start)
296 & p_netlist->i_nb_iovec ) < p_netlist->i_read_once )
298 msleep( INPUT_IDLE_SLEEP );
301 intf_WarnMsg( 4, "input info: found free iovec" );
305 (p_netlist->i_data_end - p_netlist->i_data_start)
306 & p_netlist->i_nb_data ) < p_netlist->i_read_once )
308 intf_WarnMsg( 4, "input info: waiting for free data packet" );
309 msleep( INPUT_IDLE_SLEEP );
312 (p_netlist->i_data_end - p_netlist->i_data_start)
313 & p_netlist->i_nb_data ) < p_netlist->i_read_once )
315 msleep( INPUT_IDLE_SLEEP );
318 intf_WarnMsg( 4, "input info: found free data packet" );
321 /* readv only takes contiguous buffers
322 * so, as a solution, we chose to have a FIFO a bit longer
323 * than i_nb_data, and copy the begining of the FIFO to its end
324 * if the readv needs to go after the end */
325 if( p_netlist->i_nb_iovec - p_netlist->i_iovec_start + 1 <
326 p_netlist->i_read_once )
328 memcpy( &p_netlist->p_free_iovec[p_netlist->i_nb_iovec + 1],
329 p_netlist->p_free_iovec,
330 (p_netlist->i_read_once -
331 (p_netlist->i_nb_iovec + 1 - p_netlist->i_iovec_start))
332 * sizeof(struct iovec)
337 return p_netlist->p_free_iovec + p_netlist->i_iovec_start;
341 /*****************************************************************************
342 * input_NetlistMviovec: move the iovec pointer by one after a readv()
343 * operation and gives a data_packet corresponding to iovec in p_data
344 *****************************************************************************/
345 void input_NetlistMviovec( void * p_method_data, int i_nb_iovec,
346 struct data_packet_s ** pp_data )
348 netlist_t * p_netlist;
349 unsigned int i_loop = 0;
352 p_netlist = (netlist_t *)p_method_data;
355 vlc_mutex_lock( &p_netlist->lock );
357 /* Fills a table of pointers to packets associated with the io_vec's */
358 while( i_loop < i_nb_iovec )
360 pp_data[i_loop] = p_netlist->pp_free_data[p_netlist->i_data_start];
362 pp_data[i_loop]->p_buffer =
363 p_netlist->p_free_iovec[p_netlist->i_iovec_start].iov_base;
365 pp_data[i_loop]->p_payload_start = pp_data[i_loop]->p_buffer;
367 pp_data[i_loop]->p_payload_end =
368 pp_data[i_loop]->p_buffer + p_netlist->i_buffer_size;
370 pp_data[i_loop]->p_next = NULL;
371 pp_data[i_loop]->b_discard_payload = 0;
373 pp_data[i_loop]->pi_refcount = p_netlist->pi_refcount +
374 p_netlist->i_iovec_start;
375 if( (*pp_data[i_loop]->pi_refcount) != 0)
377 intf_ErrMsg( "netlist error: refcount should be 0 (%d)",
378 (*pp_data[i_loop]->pi_refcount) );
380 (*pp_data[i_loop]->pi_refcount) = 1;
382 p_netlist->i_iovec_start ++;
383 p_netlist->i_iovec_start &= p_netlist->i_nb_iovec;
385 p_netlist->i_data_start ++;
386 p_netlist->i_data_start &= p_netlist->i_nb_data;
392 vlc_mutex_unlock( &p_netlist->lock );
396 /*****************************************************************************
397 * input_NetlistNewPtr: returns a free data_packet_t
398 * Gives a pointer ; its fields need to be initialized
399 *****************************************************************************/
400 struct data_packet_s * input_NetlistNewPtr( void * p_method_data )
402 netlist_t * p_netlist;
403 struct data_packet_s * p_return;
406 p_netlist = (netlist_t *)p_method_data;
409 vlc_mutex_lock ( &p_netlist->lock );
412 if ( p_netlist->i_data_start == p_netlist->i_data_end )
414 intf_ErrMsg("Empty Data FIFO in netlist. Unable to allocate memory");
418 p_return = (p_netlist->pp_free_data[p_netlist->i_data_start]);
420 p_netlist->i_data_start++;
421 p_netlist->i_data_start &= p_netlist->i_nb_data;
423 p_return->p_payload_start = p_return->p_buffer;
425 p_return->p_payload_end =
426 p_return->p_buffer + p_netlist->i_buffer_size;
428 p_return->p_next = NULL;
429 p_return->b_discard_payload = 0;
432 vlc_mutex_unlock (&p_netlist->lock);
437 /*****************************************************************************
438 * input_NetlistNewPacket: returns a free data_packet_t, and takes
439 * a corresponding storage iovec.
440 *****************************************************************************/
441 struct data_packet_s * input_NetlistNewPacket( void * p_method_data,
442 size_t i_buffer_size )
444 netlist_t * p_netlist;
445 struct data_packet_s * p_packet;
448 p_netlist = (netlist_t *)p_method_data;
451 if( i_buffer_size > p_netlist->i_buffer_size )
453 /* This should not happen */
454 intf_ErrMsg( "Netlist packet too small !" );
460 vlc_mutex_lock( &p_netlist->lock );
463 if ( p_netlist->i_iovec_start == p_netlist->i_iovec_end )
465 intf_ErrMsg("Empty io_vec FIFO in netlist. Unable to allocate memory");
469 if ( p_netlist->i_data_start == p_netlist->i_data_end )
471 intf_ErrMsg("Empty Data FIFO in netlist. Unable to allocate memory");
476 /* Gives an io_vec and associated data */
477 p_packet = p_netlist->pp_free_data[p_netlist->i_data_start];
480 p_netlist->p_free_iovec[p_netlist->i_iovec_start].iov_base;
482 p_packet->p_payload_start = p_packet->p_buffer;
484 p_packet->p_payload_end =
485 p_packet->p_buffer + i_buffer_size;
487 p_packet->p_next = NULL;
488 p_packet->b_discard_payload = 0;
490 p_packet->pi_refcount = p_netlist->pi_refcount + p_netlist->i_iovec_start;
491 if( (*p_packet->pi_refcount) != 0)
493 intf_ErrMsg( "netlist error: refcount should be 0 (%d)",
494 (*p_packet->pi_refcount) );
496 (*p_packet->pi_refcount) = 1;
498 p_netlist->i_iovec_start ++;
499 p_netlist->i_iovec_start &= p_netlist->i_nb_iovec;
501 p_netlist->i_data_start ++;
502 p_netlist->i_data_start &= p_netlist->i_nb_data;
505 vlc_mutex_unlock( &p_netlist->lock );
510 /*****************************************************************************
511 * input_NetlistNewPES: returns a free pes_packet_t
512 *****************************************************************************/
513 struct pes_packet_s * input_NetlistNewPES( void * p_method_data )
515 netlist_t * p_netlist;
516 pes_packet_t * p_return;
519 p_netlist = (netlist_t *)p_method_data;
522 vlc_mutex_lock ( &p_netlist->lock );
525 if ( p_netlist->i_pes_start == p_netlist->i_pes_end )
527 intf_ErrMsg("Empty PES FIFO in netlist - Unable to allocate memory");
532 p_return = p_netlist->pp_free_pes[p_netlist->i_pes_start];
533 p_netlist->i_pes_start++;
534 p_netlist->i_pes_start &= p_netlist->i_nb_pes;
537 vlc_mutex_unlock (&p_netlist->lock);
540 p_return->b_data_alignment = 0;
541 p_return->b_discontinuity = 0;
544 p_return->i_pes_size = 0;
545 p_return->p_first = NULL;
550 /*****************************************************************************
551 * input_NetlistDeletePacket: puts a data_packet_t back into the netlist
552 *****************************************************************************/
553 void input_NetlistDeletePacket( void * p_method_data, data_packet_t * p_data )
555 netlist_t * p_netlist;
558 p_netlist = (netlist_t *) p_method_data;
561 vlc_mutex_lock ( &p_netlist->lock );
563 /* Delete data_packet */
564 p_netlist->i_data_end ++;
565 p_netlist->i_data_end &= p_netlist->i_nb_data;
567 p_data->p_payload_start = p_data->p_buffer;
568 p_data->p_payload_end = p_data->p_buffer + p_netlist->i_buffer_size;
570 p_netlist->pp_free_data[p_netlist->i_data_end] = p_data;
572 p_data->p_next = NULL;
573 p_data->b_discard_payload = 0;
575 /* Update reference counter */
576 (*p_data->pi_refcount)--;
578 if( (*p_data->pi_refcount) == 0 )
580 (*p_data->pi_refcount) = 0;
581 p_netlist->i_iovec_end++;
582 p_netlist->i_iovec_end &= p_netlist->i_nb_iovec;
583 p_netlist->p_free_iovec[p_netlist->i_iovec_end].iov_base =
586 else if( (*p_data->pi_refcount) < 0 )
588 intf_ErrMsg( "netlist error: refcount can't be negative (%d)",
589 (*p_data->pi_refcount) );
593 vlc_mutex_unlock (&p_netlist->lock);
596 /*****************************************************************************
597 * input_NetlistDeletePES: puts a pes_packet_t back into the netlist
598 *****************************************************************************/
599 void input_NetlistDeletePES( void * p_method_data, pes_packet_t * p_pes )
601 netlist_t * p_netlist;
602 data_packet_t * p_current_packet;
603 data_packet_t * p_next_packet;
606 p_netlist = (netlist_t *)p_method_data;
609 vlc_mutex_lock ( &p_netlist->lock );
611 /* delete free p_pes->p_first, p_next ... */
612 p_current_packet = p_pes->p_first;
613 while ( p_current_packet != NULL )
615 /* copy of NetListDeletePacket, duplicate code avoid many locks */
617 p_netlist->i_data_end ++;
618 p_netlist->i_data_end &= p_netlist->i_nb_data;
621 p_current_packet->p_payload_start = p_current_packet->p_buffer;
622 p_current_packet->p_payload_end = p_current_packet->p_buffer
623 + p_netlist->i_buffer_size;
625 p_netlist->pp_free_data[p_netlist->i_data_end] = p_current_packet;
627 /* Update reference counter */
628 (*p_current_packet->pi_refcount)--;
630 if( (*p_current_packet->pi_refcount) == 0 )
632 (*p_current_packet->pi_refcount) = 0;
633 p_netlist->i_iovec_end++;
634 p_netlist->i_iovec_end &= p_netlist->i_nb_iovec;
635 p_netlist->p_free_iovec[p_netlist->i_iovec_end].iov_base =
636 p_current_packet->p_buffer;
638 else if( (*p_current_packet->pi_refcount) < 0 )
640 intf_ErrMsg( "netlist error: refcount can't be negative (%d)",
641 (*p_current_packet->pi_refcount) );
644 p_next_packet = p_current_packet->p_next;
645 p_current_packet->p_next = NULL;
646 p_current_packet->b_discard_payload = 0;
647 p_current_packet = p_next_packet;
650 /* delete our current PES packet */
651 p_netlist->i_pes_end ++;
652 p_netlist->i_pes_end &= p_netlist->i_nb_pes;
653 p_netlist->pp_free_pes[p_netlist->i_pes_end] = p_pes;
656 vlc_mutex_unlock (&p_netlist->lock);
660 /*****************************************************************************
661 * input_NetlistEnd: frees all allocated structures
662 *****************************************************************************/
663 void input_NetlistEnd( input_thread_t * p_input )
665 netlist_t * p_netlist;
668 p_netlist = ( netlist_t * ) p_input->p_method_data;
670 /* destroy the mutex lock */
671 vlc_mutex_destroy( &p_netlist->lock );
673 /* free the FIFO, the buffer, and the netlist structure */
674 free( p_netlist->pi_refcount );
675 free( p_netlist->p_free_iovec );
676 free( p_netlist->pp_free_pes );
677 free( p_netlist->pp_free_data );
678 free( p_netlist->p_pes );
679 free( p_netlist->p_data );
680 free( p_netlist->p_buffers );
682 /* free the netlist */