1 /*****************************************************************************
2 * input_ext-plugins.c: useful functions for access and demux plug-ins
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 VideoLAN
5 * $Id: input_ext-plugins.c,v 1.17 2002/07/24 23:11:55 massiot Exp $
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
29 #include <sys/types.h>
37 #ifdef HAVE_SYS_TIME_H
38 # include <sys/time.h>
43 #elif defined( _MSC_VER ) && defined( _WIN32 )
48 # include <winsock2.h>
49 # include <ws2tcpip.h>
50 #elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
51 # include <netdb.h> /* hostent ... */
52 # include <sys/socket.h>
53 # include <netinet/in.h>
54 # ifdef HAVE_ARPA_INET_H
55 # include <arpa/inet.h> /* inet_ntoa(), inet_aton() */
60 # include <winsock2.h>
61 # include <ws2tcpip.h>
62 #elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
63 # include <netdb.h> /* hostent ... */
64 # include <sys/socket.h>
65 # include <netinet/in.h>
66 # ifdef HAVE_ARPA_INET_H
67 # include <arpa/inet.h> /* inet_ntoa(), inet_aton() */
73 #include "stream_control.h"
74 #include "input_ext-intf.h"
75 #include "input_ext-dec.h"
76 #include "input_ext-plugins.h"
80 * Buffers management : internal functions
82 * All functions are static, but exported versions with mutex protection
83 * start with input_*. Not all of these exported functions are actually used,
84 * but they are included here for completeness.
87 #define BUFFERS_CACHE_SIZE 500
88 #define DATA_CACHE_SIZE 1000
89 #define PES_CACHE_SIZE 1000
91 /*****************************************************************************
92 * data_buffer_t: shared data type
93 *****************************************************************************/
96 data_buffer_t * p_next;
98 /* number of data packets this buffer is referenced from - when it falls
99 * down to 0, the buffer is freed */
102 /* size of the current buffer (starting right after this byte) */
106 /*****************************************************************************
107 * input_buffers_t: defines a LIFO per data type to keep
108 *****************************************************************************/
109 #define PACKETS_LIFO( TYPE, NAME ) \
113 unsigned int i_depth; \
116 struct input_buffers_t
119 PACKETS_LIFO( pes_packet_t, pes )
120 PACKETS_LIFO( data_packet_t, data )
121 PACKETS_LIFO( data_buffer_t, buffers )
126 /*****************************************************************************
127 * input_BuffersInit: initialize the cache structures, return a pointer to it
128 *****************************************************************************/
129 void * __input_BuffersInit( vlc_object_t *p_this )
131 input_buffers_t * p_buffers = malloc( sizeof( input_buffers_t ) );
133 if( p_buffers == NULL )
138 memset( p_buffers, 0, sizeof( input_buffers_t ) );
139 vlc_mutex_init( p_this, &p_buffers->lock );
144 /*****************************************************************************
145 * input_BuffersEnd: free all cached structures
146 *****************************************************************************/
147 #define BUFFERS_END_PACKETS_LOOP \
148 while( p_packet != NULL ) \
150 p_next = p_packet->p_next; \
155 void input_BuffersEnd( input_thread_t * p_input, input_buffers_t * p_buffers )
157 if( p_buffers != NULL )
159 msg_Dbg( p_input, "pes: %d packets", p_buffers->pes.i_depth );
160 msg_Dbg( p_input, "data: %d packets", p_buffers->data.i_depth );
161 msg_Dbg( p_input, "buffers: %d packets", p_buffers->buffers.i_depth );
165 pes_packet_t * p_next, * p_packet = p_buffers->pes.p_stack;
166 BUFFERS_END_PACKETS_LOOP;
170 /* Free data packets */
171 data_packet_t * p_next, * p_packet = p_buffers->data.p_stack;
172 BUFFERS_END_PACKETS_LOOP;
177 data_buffer_t * p_next, * p_buf = p_buffers->buffers.p_stack;
178 while( p_buf != NULL )
180 p_next = p_buf->p_next;
181 p_buffers->i_allocated -= p_buf->i_size;
187 if( p_buffers->i_allocated )
189 msg_Err( p_input, "%d bytes have not been freed, "
190 "expect memory leak", p_buffers->i_allocated );
193 vlc_mutex_destroy( &p_buffers->lock );
198 /*****************************************************************************
199 * input_NewBuffer: return a pointer to a data buffer of the appropriate size
200 *****************************************************************************/
201 static inline data_buffer_t * NewBuffer( input_buffers_t * p_buffers,
204 data_buffer_t * p_buf;
207 if( p_buffers->i_allocated > INPUT_MAX_ALLOCATION )
209 //X intf_Err( "INPUT_MAX_ALLOCATION reached (%d)",
210 //X p_buffers->i_allocated );
214 if( p_buffers->buffers.p_stack != NULL )
216 /* Take the buffer from the cache */
217 p_buf = p_buffers->buffers.p_stack;
218 p_buffers->buffers.p_stack = p_buf->p_next;
219 p_buffers->buffers.i_depth--;
221 /* Reallocate the packet if it is too small or too large */
222 if( p_buf->i_size < i_size || p_buf->i_size > 3 * i_size )
224 p_buffers->i_allocated -= p_buf->i_size;
226 p_buf = malloc( sizeof(input_buffers_t) + i_size );
229 //X intf_ErrMsg( "Out of memory" );
232 p_buf->i_size = i_size;
233 p_buffers->i_allocated += i_size;
238 /* Allocate a new buffer */
239 p_buf = malloc( sizeof(input_buffers_t) + i_size );
242 //X intf_ErrMsg( "Out of memory" );
245 p_buf->i_size = i_size;
246 p_buffers->i_allocated += i_size;
249 /* Initialize data */
250 p_buf->p_next = NULL;
251 p_buf->i_refcount = 0;
256 data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
258 data_buffer_t * p_buf;
260 vlc_mutex_lock( &p_buffers->lock );
261 p_buf = NewBuffer( p_buffers, i_size );
262 vlc_mutex_unlock( &p_buffers->lock );
267 /*****************************************************************************
268 * input_ReleaseBuffer: put a buffer back into the cache
269 *****************************************************************************/
270 static inline void ReleaseBuffer( input_buffers_t * p_buffers,
271 data_buffer_t * p_buf )
273 /* Decrement refcount */
274 if( --p_buf->i_refcount > 0 )
279 if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
281 /* Cache not full : store the buffer in it */
282 p_buf->p_next = p_buffers->buffers.p_stack;
283 p_buffers->buffers.p_stack = p_buf;
284 p_buffers->buffers.i_depth++;
288 p_buffers->i_allocated -= p_buf->i_size;
293 void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
295 vlc_mutex_lock( &p_buffers->lock );
296 ReleaseBuffer( p_buffers, p_buf );
297 vlc_mutex_unlock( &p_buffers->lock );
300 /*****************************************************************************
301 * input_ShareBuffer: allocate a data_packet_t pointing to a given buffer
302 *****************************************************************************/
303 static inline data_packet_t * ShareBuffer( input_buffers_t * p_buffers,
304 data_buffer_t * p_buf )
306 data_packet_t * p_data;
308 if( p_buffers->data.p_stack != NULL )
310 /* Take the packet from the cache */
311 p_data = p_buffers->data.p_stack;
312 p_buffers->data.p_stack = p_data->p_next;
313 p_buffers->data.i_depth--;
317 /* Allocate a new packet */
318 p_data = malloc( sizeof(data_packet_t) );
321 //X intf_ErrMsg( "Out of memory" );
326 p_data->p_buffer = p_buf;
327 p_data->p_next = NULL;
328 p_data->b_discard_payload = 0;
329 p_data->p_payload_start = p_data->p_demux_start
330 = (byte_t *)p_buf + sizeof(input_buffers_t);
331 p_data->p_payload_end = p_data->p_demux_start + p_buf->i_size;
337 data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
338 data_buffer_t * p_buf )
340 data_packet_t * p_data;
342 vlc_mutex_lock( &p_buffers->lock );
343 p_data = ShareBuffer( p_buffers, p_buf );
344 vlc_mutex_unlock( &p_buffers->lock );
349 /*****************************************************************************
350 * input_NewPacket: allocate a packet along with a buffer
351 *****************************************************************************/
352 static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
355 data_buffer_t * p_buf = NewBuffer( p_buffers, i_size );
356 data_packet_t * p_data;
363 p_data = ShareBuffer( p_buffers, p_buf );
366 ReleaseBuffer( p_buffers, p_buf );
371 data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
373 data_packet_t * p_data;
375 vlc_mutex_lock( &p_buffers->lock );
376 p_data = NewPacket( p_buffers, i_size );
377 vlc_mutex_unlock( &p_buffers->lock );
382 /*****************************************************************************
383 * input_DeletePacket: deallocate a packet and its buffers
384 *****************************************************************************/
385 static inline void DeletePacket( input_buffers_t * p_buffers,
386 data_packet_t * p_data )
388 while( p_data != NULL )
390 data_packet_t * p_next = p_data->p_next;
392 ReleaseBuffer( p_buffers, p_data->p_buffer );
394 if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
396 /* Cache not full : store the packet in it */
397 p_data->p_next = p_buffers->data.p_stack;
398 p_buffers->data.p_stack = p_data;
399 p_buffers->data.i_depth++;
410 void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
412 vlc_mutex_lock( &p_buffers->lock );
413 DeletePacket( p_buffers, p_data );
414 vlc_mutex_unlock( &p_buffers->lock );
417 /*****************************************************************************
418 * input_NewPES: return a pointer to a new PES packet
419 *****************************************************************************/
420 static inline pes_packet_t * NewPES( input_buffers_t * p_buffers )
422 pes_packet_t * p_pes;
424 if( p_buffers->pes.p_stack != NULL )
426 /* Take the packet from the cache */
427 p_pes = p_buffers->pes.p_stack;
428 p_buffers->pes.p_stack = p_pes->p_next;
429 p_buffers->pes.i_depth--;
433 /* Allocate a new packet */
434 p_pes = malloc( sizeof(pes_packet_t) );
437 //X intf_ErrMsg( "Out of memory" );
442 p_pes->p_next = NULL;
443 p_pes->b_data_alignment = p_pes->b_discontinuity =
444 p_pes->i_pts = p_pes->i_dts = 0;
445 p_pes->p_first = p_pes->p_last = NULL;
446 p_pes->i_pes_size = 0;
447 p_pes->i_nb_data = 0;
452 pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
454 pes_packet_t * p_pes;
456 vlc_mutex_lock( &p_buffers->lock );
457 p_pes = NewPES( p_buffers );
458 vlc_mutex_unlock( &p_buffers->lock );
463 /*****************************************************************************
464 * input_DeletePES: put a pes and all data packets and all buffers back into
466 *****************************************************************************/
467 static inline void DeletePES( input_buffers_t * p_buffers,
468 pes_packet_t * p_pes )
470 while( p_pes != NULL )
472 pes_packet_t * p_next = p_pes->p_next;
474 /* Delete all data packets */
475 if( p_pes->p_first != NULL )
477 DeletePacket( p_buffers, p_pes->p_first );
480 if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
482 /* Cache not full : store the packet in it */
483 p_pes->p_next = p_buffers->pes.p_stack;
484 p_buffers->pes.p_stack = p_pes;
485 p_buffers->pes.i_depth++;
496 void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
498 vlc_mutex_lock( &p_buffers->lock );
499 DeletePES( p_buffers, p_pes );
500 vlc_mutex_unlock( &p_buffers->lock );
505 * Buffers management : external functions
507 * These functions make the glu between the access plug-in (pf_read) and
508 * the demux plug-in (pf_demux). We fill in a large buffer (approx. 10s kB)
509 * with a call to pf_read, then allow the demux plug-in to have a peep at
510 * it (input_Peek), and to split it in data_packet_t (input_SplitBuffer).
512 /*****************************************************************************
513 * input_FillBuffer: fill in p_data_buffer with data from pf_read
514 *****************************************************************************/
515 ssize_t input_FillBuffer( input_thread_t * p_input )
517 ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
518 data_buffer_t * p_buf;
521 vlc_mutex_lock( &p_input->p_method_data->lock );
523 p_buf = NewBuffer( p_input->p_method_data,
524 i_remains + p_input->i_bufsize );
529 p_buf->i_refcount = 1;
531 if( p_input->p_data_buffer != NULL )
535 p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
536 p_input->p_current_data,
539 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
542 /* Do not hold the lock during pf_read (blocking call). */
543 vlc_mutex_unlock( &p_input->p_method_data->lock );
545 i_ret = p_input->pf_read( p_input,
546 (byte_t *)p_buf + sizeof(data_buffer_t)
548 p_input->i_bufsize );
549 if( i_ret < 0 ) i_ret = 0;
551 p_input->p_data_buffer = p_buf;
552 p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
553 p_input->p_last_data = p_input->p_current_data + i_remains + i_ret;
555 return( (ssize_t)i_remains + i_ret );
558 /*****************************************************************************
559 * input_Peek: give a pointer to the next available bytes in the buffer
560 * (min. i_size bytes)
561 * Returns the number of bytes read, or -1 in case of error
562 *****************************************************************************/
563 ssize_t input_Peek( input_thread_t * p_input, byte_t ** pp_byte, size_t i_size )
565 if( p_input->p_last_data - p_input->p_current_data < i_size )
567 /* Go to the next buffer */
568 ssize_t i_ret = input_FillBuffer( p_input );
574 else if( i_ret < i_size )
579 *pp_byte = p_input->p_current_data;
583 /*****************************************************************************
584 * input_SplitBuffer: give a pointer to a data packet containing i_size bytes
585 * Returns the number of bytes read, or -1 in case of error
586 *****************************************************************************/
587 ssize_t input_SplitBuffer( input_thread_t * p_input,
588 data_packet_t ** pp_data, size_t i_size )
590 if( p_input->p_last_data - p_input->p_current_data < i_size )
592 /* Go to the next buffer */
593 ssize_t i_ret = input_FillBuffer( p_input );
599 else if( i_ret < i_size )
610 *pp_data = input_ShareBuffer( p_input->p_method_data,
611 p_input->p_data_buffer );
613 (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
614 = p_input->p_current_data;
615 (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
617 p_input->p_current_data += i_size;
622 /*****************************************************************************
623 * input_AccessInit: initialize access plug-in wrapper structures
624 *****************************************************************************/
625 int input_AccessInit( input_thread_t * p_input )
627 p_input->p_method_data = input_BuffersInit( p_input );
628 if( p_input->p_method_data == NULL ) return( -1 );
629 p_input->p_data_buffer = NULL;
630 p_input->p_current_data = NULL;
631 p_input->p_last_data = NULL;
635 /*****************************************************************************
636 * input_AccessReinit: reinit structures after a random seek
637 *****************************************************************************/
638 void input_AccessReinit( input_thread_t * p_input )
640 if( p_input->p_data_buffer != NULL )
642 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
644 p_input->p_data_buffer = NULL;
645 p_input->p_current_data = NULL;
646 p_input->p_last_data = NULL;
649 /*****************************************************************************
650 * input_AccessEnd: free access plug-in wrapper structures
651 *****************************************************************************/
652 void input_AccessEnd( input_thread_t * p_input )
654 if( p_input->p_data_buffer != NULL )
656 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
659 input_BuffersEnd( p_input, p_input->p_method_data );
664 * Optional file descriptor management functions, for use by access plug-ins
665 * base on file descriptors (file, udp, http...).
668 /*****************************************************************************
669 * input_FDClose: close the target
670 *****************************************************************************/
671 void input_FDClose( input_thread_t * p_input )
673 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
675 msg_Info( p_input, "closing `%s/%s://%s'",
676 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
678 close( p_access_data->i_handle );
679 free( p_access_data );
682 /*****************************************************************************
683 * input_FDNetworkClose: close a network target
684 *****************************************************************************/
685 void input_FDNetworkClose( input_thread_t * p_input )
687 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
689 msg_Info( p_input, "closing network `%s/%s://%s'",
690 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
693 closesocket( p_access_data->i_handle );
695 close( p_access_data->i_handle );
698 free( p_access_data );
701 /*****************************************************************************
702 * input_FDRead: standard read on a file descriptor.
703 *****************************************************************************/
704 ssize_t input_FDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
706 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
708 ssize_t i_ret = read( p_access_data->i_handle, p_buffer, i_len );
712 vlc_mutex_lock( &p_input->stream.stream_lock );
713 p_input->stream.p_selected_area->i_tell += i_ret;
714 vlc_mutex_unlock( &p_input->stream.stream_lock );
719 msg_Err( p_input, "read failed (%s)", strerror(errno) );
725 /*****************************************************************************
726 * NetworkSelect: Checks whether data is available on a file descriptor
727 *****************************************************************************/
728 static inline int NetworkSelect( input_thread_t * p_input )
730 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
731 struct timeval timeout;
735 /* Initialize file descriptor set */
737 FD_SET( p_access_data->i_handle, &fds );
739 /* We'll wait 0.5 second if nothing happens */
741 timeout.tv_usec = 500000;
743 /* Find if some data is available */
744 i_ret = select( p_access_data->i_handle + 1, &fds,
745 NULL, NULL, &timeout );
747 if( i_ret == -1 && errno != EINTR )
749 msg_Err( p_input, "network select error (%s)", strerror(errno) );
755 /*****************************************************************************
756 * input_FDNetworkRead: read on a file descriptor, checking periodically
758 *****************************************************************************/
759 ssize_t input_FDNetworkRead( input_thread_t * p_input, byte_t * p_buffer,
762 if( NetworkSelect( p_input ) > 0 )
764 input_socket_t * p_access_data
765 = (input_socket_t *)p_input->p_access_data;
767 ssize_t i_ret = recv( p_access_data->i_handle, p_buffer, i_len, 0 );
771 vlc_mutex_lock( &p_input->stream.stream_lock );
772 p_input->stream.p_selected_area->i_tell += i_ret;
773 vlc_mutex_unlock( &p_input->stream.stream_lock );
778 msg_Err( p_input, "recv failed (%s)", strerror(errno) );
787 /*****************************************************************************
788 * input_FDSeek: seek to a specific location in a file
789 *****************************************************************************/
790 void input_FDSeek( input_thread_t * p_input, off_t i_pos )
792 #define S p_input->stream
793 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
795 lseek( p_access_data->i_handle, i_pos, SEEK_SET );
797 vlc_mutex_lock( &S.stream_lock );
798 S.p_selected_area->i_tell = i_pos;
799 if( S.p_selected_area->i_tell > S.p_selected_area->i_size )
801 msg_Err( p_input, "seeking too far" );
802 S.p_selected_area->i_tell = S.p_selected_area->i_size;
804 else if( S.p_selected_area->i_tell < 0 )
806 msg_Err( p_input, "seeking too early" );
807 S.p_selected_area->i_tell = 0;
809 vlc_mutex_unlock( &S.stream_lock );