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.18 2002/07/31 20:56:52 sam 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 )
212 if( p_buffers->buffers.p_stack != NULL )
214 /* Take the buffer from the cache */
215 p_buf = p_buffers->buffers.p_stack;
216 p_buffers->buffers.p_stack = p_buf->p_next;
217 p_buffers->buffers.i_depth--;
219 /* Reallocate the packet if it is too small or too large */
220 if( p_buf->i_size < i_size || p_buf->i_size > 3 * i_size )
222 p_buffers->i_allocated -= p_buf->i_size;
224 p_buf = malloc( sizeof(input_buffers_t) + i_size );
229 p_buf->i_size = i_size;
230 p_buffers->i_allocated += i_size;
235 /* Allocate a new buffer */
236 p_buf = malloc( sizeof(input_buffers_t) + i_size );
241 p_buf->i_size = i_size;
242 p_buffers->i_allocated += i_size;
245 /* Initialize data */
246 p_buf->p_next = NULL;
247 p_buf->i_refcount = 0;
252 data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
254 data_buffer_t * p_buf;
256 vlc_mutex_lock( &p_buffers->lock );
257 p_buf = NewBuffer( p_buffers, i_size );
258 vlc_mutex_unlock( &p_buffers->lock );
263 /*****************************************************************************
264 * input_ReleaseBuffer: put a buffer back into the cache
265 *****************************************************************************/
266 static inline void ReleaseBuffer( input_buffers_t * p_buffers,
267 data_buffer_t * p_buf )
269 /* Decrement refcount */
270 if( --p_buf->i_refcount > 0 )
275 if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
277 /* Cache not full : store the buffer in it */
278 p_buf->p_next = p_buffers->buffers.p_stack;
279 p_buffers->buffers.p_stack = p_buf;
280 p_buffers->buffers.i_depth++;
284 p_buffers->i_allocated -= p_buf->i_size;
289 void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
291 vlc_mutex_lock( &p_buffers->lock );
292 ReleaseBuffer( p_buffers, p_buf );
293 vlc_mutex_unlock( &p_buffers->lock );
296 /*****************************************************************************
297 * input_ShareBuffer: allocate a data_packet_t pointing to a given buffer
298 *****************************************************************************/
299 static inline data_packet_t * ShareBuffer( input_buffers_t * p_buffers,
300 data_buffer_t * p_buf )
302 data_packet_t * p_data;
304 if( p_buffers->data.p_stack != NULL )
306 /* Take the packet from the cache */
307 p_data = p_buffers->data.p_stack;
308 p_buffers->data.p_stack = p_data->p_next;
309 p_buffers->data.i_depth--;
313 /* Allocate a new packet */
314 p_data = malloc( sizeof(data_packet_t) );
321 p_data->p_buffer = p_buf;
322 p_data->p_next = NULL;
323 p_data->b_discard_payload = 0;
324 p_data->p_payload_start = p_data->p_demux_start
325 = (byte_t *)p_buf + sizeof(input_buffers_t);
326 p_data->p_payload_end = p_data->p_demux_start + p_buf->i_size;
332 data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
333 data_buffer_t * p_buf )
335 data_packet_t * p_data;
337 vlc_mutex_lock( &p_buffers->lock );
338 p_data = ShareBuffer( p_buffers, p_buf );
339 vlc_mutex_unlock( &p_buffers->lock );
344 /*****************************************************************************
345 * input_NewPacket: allocate a packet along with a buffer
346 *****************************************************************************/
347 static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
350 data_buffer_t * p_buf;
351 data_packet_t * p_data;
353 p_buf = NewBuffer( p_buffers, i_size );
360 p_data = ShareBuffer( p_buffers, p_buf );
363 ReleaseBuffer( p_buffers, p_buf );
368 data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
370 data_packet_t * p_data;
372 vlc_mutex_lock( &p_buffers->lock );
373 p_data = NewPacket( p_buffers, i_size );
374 vlc_mutex_unlock( &p_buffers->lock );
379 /*****************************************************************************
380 * input_DeletePacket: deallocate a packet and its buffers
381 *****************************************************************************/
382 static inline void DeletePacket( input_buffers_t * p_buffers,
383 data_packet_t * p_data )
385 while( p_data != NULL )
387 data_packet_t * p_next = p_data->p_next;
389 ReleaseBuffer( p_buffers, p_data->p_buffer );
391 if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
393 /* Cache not full : store the packet in it */
394 p_data->p_next = p_buffers->data.p_stack;
395 p_buffers->data.p_stack = p_data;
396 p_buffers->data.i_depth++;
407 void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
409 vlc_mutex_lock( &p_buffers->lock );
410 DeletePacket( p_buffers, p_data );
411 vlc_mutex_unlock( &p_buffers->lock );
414 /*****************************************************************************
415 * input_NewPES: return a pointer to a new PES packet
416 *****************************************************************************/
417 static inline pes_packet_t * NewPES( input_buffers_t * p_buffers )
419 pes_packet_t * p_pes;
421 if( p_buffers->pes.p_stack != NULL )
423 /* Take the packet from the cache */
424 p_pes = p_buffers->pes.p_stack;
425 p_buffers->pes.p_stack = p_pes->p_next;
426 p_buffers->pes.i_depth--;
430 /* Allocate a new packet */
431 p_pes = malloc( sizeof(pes_packet_t) );
438 p_pes->p_next = NULL;
439 p_pes->b_data_alignment = p_pes->b_discontinuity =
440 p_pes->i_pts = p_pes->i_dts = 0;
441 p_pes->p_first = p_pes->p_last = NULL;
442 p_pes->i_pes_size = 0;
443 p_pes->i_nb_data = 0;
448 pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
450 pes_packet_t * p_pes;
452 vlc_mutex_lock( &p_buffers->lock );
453 p_pes = NewPES( p_buffers );
454 vlc_mutex_unlock( &p_buffers->lock );
459 /*****************************************************************************
460 * input_DeletePES: put a pes and all data packets and all buffers back into
462 *****************************************************************************/
463 static inline void DeletePES( input_buffers_t * p_buffers,
464 pes_packet_t * p_pes )
466 while( p_pes != NULL )
468 pes_packet_t * p_next = p_pes->p_next;
470 /* Delete all data packets */
471 if( p_pes->p_first != NULL )
473 DeletePacket( p_buffers, p_pes->p_first );
476 if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
478 /* Cache not full : store the packet in it */
479 p_pes->p_next = p_buffers->pes.p_stack;
480 p_buffers->pes.p_stack = p_pes;
481 p_buffers->pes.i_depth++;
492 void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
494 vlc_mutex_lock( &p_buffers->lock );
495 DeletePES( p_buffers, p_pes );
496 vlc_mutex_unlock( &p_buffers->lock );
501 * Buffers management : external functions
503 * These functions make the glu between the access plug-in (pf_read) and
504 * the demux plug-in (pf_demux). We fill in a large buffer (approx. 10s kB)
505 * with a call to pf_read, then allow the demux plug-in to have a peep at
506 * it (input_Peek), and to split it in data_packet_t (input_SplitBuffer).
508 /*****************************************************************************
509 * input_FillBuffer: fill in p_data_buffer with data from pf_read
510 *****************************************************************************/
511 ssize_t input_FillBuffer( input_thread_t * p_input )
513 ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
514 data_buffer_t * p_buf;
517 vlc_mutex_lock( &p_input->p_method_data->lock );
519 p_buf = NewBuffer( p_input->p_method_data,
520 i_remains + p_input->i_bufsize );
523 msg_Err( p_input, "failed allocating a new buffer (decoder stuck?)" );
526 p_buf->i_refcount = 1;
528 if( p_input->p_data_buffer != NULL )
532 p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
533 p_input->p_current_data,
536 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
539 /* Do not hold the lock during pf_read (blocking call). */
540 vlc_mutex_unlock( &p_input->p_method_data->lock );
542 i_ret = p_input->pf_read( p_input,
543 (byte_t *)p_buf + sizeof(data_buffer_t)
545 p_input->i_bufsize );
546 if( i_ret < 0 ) i_ret = 0;
548 p_input->p_data_buffer = p_buf;
549 p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
550 p_input->p_last_data = p_input->p_current_data + i_remains + i_ret;
552 return( (ssize_t)i_remains + i_ret );
555 /*****************************************************************************
556 * input_Peek: give a pointer to the next available bytes in the buffer
557 * (min. i_size bytes)
558 * Returns the number of bytes read, or -1 in case of error
559 *****************************************************************************/
560 ssize_t input_Peek( input_thread_t * p_input, byte_t ** pp_byte, size_t i_size )
562 if( p_input->p_last_data - p_input->p_current_data < i_size )
564 /* Go to the next buffer */
565 ssize_t i_ret = input_FillBuffer( p_input );
571 else if( i_ret < i_size )
576 *pp_byte = p_input->p_current_data;
580 /*****************************************************************************
581 * input_SplitBuffer: give a pointer to a data packet containing i_size bytes
582 * Returns the number of bytes read, or -1 in case of error
583 *****************************************************************************/
584 ssize_t input_SplitBuffer( input_thread_t * p_input,
585 data_packet_t ** pp_data, size_t i_size )
587 if( p_input->p_last_data - p_input->p_current_data < i_size )
589 /* Go to the next buffer */
590 ssize_t i_ret = input_FillBuffer( p_input );
596 else if( i_ret < i_size )
607 *pp_data = input_ShareBuffer( p_input->p_method_data,
608 p_input->p_data_buffer );
610 (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
611 = p_input->p_current_data;
612 (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
614 p_input->p_current_data += i_size;
619 /*****************************************************************************
620 * input_AccessInit: initialize access plug-in wrapper structures
621 *****************************************************************************/
622 int input_AccessInit( input_thread_t * p_input )
624 p_input->p_method_data = input_BuffersInit( p_input );
625 if( p_input->p_method_data == NULL ) return( -1 );
626 p_input->p_data_buffer = NULL;
627 p_input->p_current_data = NULL;
628 p_input->p_last_data = NULL;
632 /*****************************************************************************
633 * input_AccessReinit: reinit structures after a random seek
634 *****************************************************************************/
635 void input_AccessReinit( input_thread_t * p_input )
637 if( p_input->p_data_buffer != NULL )
639 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
641 p_input->p_data_buffer = NULL;
642 p_input->p_current_data = NULL;
643 p_input->p_last_data = NULL;
646 /*****************************************************************************
647 * input_AccessEnd: free access plug-in wrapper structures
648 *****************************************************************************/
649 void input_AccessEnd( input_thread_t * p_input )
651 if( p_input->p_data_buffer != NULL )
653 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
656 input_BuffersEnd( p_input, p_input->p_method_data );
661 * Optional file descriptor management functions, for use by access plug-ins
662 * base on file descriptors (file, udp, http...).
665 /*****************************************************************************
666 * input_FDClose: close the target
667 *****************************************************************************/
668 void __input_FDClose( vlc_object_t * p_this )
670 input_thread_t * p_input = (input_thread_t *)p_this;
671 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
673 msg_Info( p_input, "closing `%s/%s://%s'",
674 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
676 close( p_access_data->i_handle );
677 free( p_access_data );
680 /*****************************************************************************
681 * input_FDNetworkClose: close a network target
682 *****************************************************************************/
683 void __input_FDNetworkClose( vlc_object_t * p_this )
685 input_thread_t * p_input = (input_thread_t *)p_this;
686 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
688 msg_Info( p_input, "closing network `%s/%s://%s'",
689 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
692 closesocket( p_access_data->i_handle );
694 close( p_access_data->i_handle );
697 free( p_access_data );
700 /*****************************************************************************
701 * input_FDRead: standard read on a file descriptor.
702 *****************************************************************************/
703 ssize_t input_FDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
705 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
707 ssize_t i_ret = read( p_access_data->i_handle, p_buffer, i_len );
711 vlc_mutex_lock( &p_input->stream.stream_lock );
712 p_input->stream.p_selected_area->i_tell += i_ret;
713 vlc_mutex_unlock( &p_input->stream.stream_lock );
718 msg_Err( p_input, "read failed (%s)", strerror(errno) );
724 /*****************************************************************************
725 * NetworkSelect: Checks whether data is available on a file descriptor
726 *****************************************************************************/
727 static inline int NetworkSelect( input_thread_t * p_input )
729 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
730 struct timeval timeout;
734 /* Initialize file descriptor set */
736 FD_SET( p_access_data->i_handle, &fds );
738 /* We'll wait 0.5 second if nothing happens */
740 timeout.tv_usec = 500000;
742 /* Find if some data is available */
743 i_ret = select( p_access_data->i_handle + 1, &fds,
744 NULL, NULL, &timeout );
746 if( i_ret == -1 && errno != EINTR )
748 msg_Err( p_input, "network select error (%s)", strerror(errno) );
754 /*****************************************************************************
755 * input_FDNetworkRead: read on a file descriptor, checking periodically
757 *****************************************************************************/
758 ssize_t input_FDNetworkRead( input_thread_t * p_input, byte_t * p_buffer,
761 if( NetworkSelect( p_input ) > 0 )
763 input_socket_t * p_access_data
764 = (input_socket_t *)p_input->p_access_data;
766 ssize_t i_ret = recv( p_access_data->i_handle, p_buffer, i_len, 0 );
770 vlc_mutex_lock( &p_input->stream.stream_lock );
771 p_input->stream.p_selected_area->i_tell += i_ret;
772 vlc_mutex_unlock( &p_input->stream.stream_lock );
777 msg_Err( p_input, "recv failed (%s)", strerror(errno) );
786 /*****************************************************************************
787 * input_FDSeek: seek to a specific location in a file
788 *****************************************************************************/
789 void input_FDSeek( input_thread_t * p_input, off_t i_pos )
791 #define S p_input->stream
792 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
794 lseek( p_access_data->i_handle, i_pos, SEEK_SET );
796 vlc_mutex_lock( &S.stream_lock );
797 S.p_selected_area->i_tell = i_pos;
798 if( S.p_selected_area->i_tell > S.p_selected_area->i_size )
800 msg_Err( p_input, "seeking too far" );
801 S.p_selected_area->i_tell = S.p_selected_area->i_size;
803 else if( S.p_selected_area->i_tell < 0 )
805 msg_Err( p_input, "seeking too early" );
806 S.p_selected_area->i_tell = 0;
808 vlc_mutex_unlock( &S.stream_lock );