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.20 2002/11/10 18:04:23 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 *****************************************************************************/
32 #ifdef HAVE_SYS_STAT_H
33 # include <sys/stat.h>
44 #ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
50 #elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE )
55 /* No network support */
56 #elif defined( WIN32 )
57 # include <winsock2.h>
58 # include <ws2tcpip.h>
59 #elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
60 # include <sys/types.h>
61 # include <sys/socket.h> /* recv() */
64 #include "stream_control.h"
65 #include "input_ext-intf.h"
66 #include "input_ext-dec.h"
67 #include "input_ext-plugins.h"
71 * Buffers management : internal functions
73 * All functions are static, but exported versions with mutex protection
74 * start with input_*. Not all of these exported functions are actually used,
75 * but they are included here for completeness.
78 #define BUFFERS_CACHE_SIZE 500
79 #define DATA_CACHE_SIZE 1000
80 #define PES_CACHE_SIZE 1000
82 /*****************************************************************************
83 * data_buffer_t: shared data type
84 *****************************************************************************/
87 data_buffer_t * p_next;
89 /* number of data packets this buffer is referenced from - when it falls
90 * down to 0, the buffer is freed */
93 /* size of the current buffer (starting right after this byte) */
97 /*****************************************************************************
98 * input_buffers_t: defines a LIFO per data type to keep
99 *****************************************************************************/
100 #define PACKETS_LIFO( TYPE, NAME ) \
104 unsigned int i_depth; \
107 struct input_buffers_t
110 PACKETS_LIFO( pes_packet_t, pes )
111 PACKETS_LIFO( data_packet_t, data )
112 PACKETS_LIFO( data_buffer_t, buffers )
117 /*****************************************************************************
118 * input_BuffersInit: initialize the cache structures, return a pointer to it
119 *****************************************************************************/
120 void * __input_BuffersInit( vlc_object_t *p_this )
122 input_buffers_t * p_buffers = malloc( sizeof( input_buffers_t ) );
124 if( p_buffers == NULL )
129 memset( p_buffers, 0, sizeof( input_buffers_t ) );
130 vlc_mutex_init( p_this, &p_buffers->lock );
135 /*****************************************************************************
136 * input_BuffersEnd: free all cached structures
137 *****************************************************************************/
138 #define BUFFERS_END_PACKETS_LOOP \
139 while( p_packet != NULL ) \
141 p_next = p_packet->p_next; \
146 void input_BuffersEnd( input_thread_t * p_input, input_buffers_t * p_buffers )
148 if( p_buffers != NULL )
150 msg_Dbg( p_input, "pes: %d packets", p_buffers->pes.i_depth );
151 msg_Dbg( p_input, "data: %d packets", p_buffers->data.i_depth );
152 msg_Dbg( p_input, "buffers: %d packets", p_buffers->buffers.i_depth );
156 pes_packet_t * p_next, * p_packet = p_buffers->pes.p_stack;
157 BUFFERS_END_PACKETS_LOOP;
161 /* Free data packets */
162 data_packet_t * p_next, * p_packet = p_buffers->data.p_stack;
163 BUFFERS_END_PACKETS_LOOP;
168 data_buffer_t * p_next, * p_buf = p_buffers->buffers.p_stack;
169 while( p_buf != NULL )
171 p_next = p_buf->p_next;
172 p_buffers->i_allocated -= p_buf->i_size;
178 if( p_buffers->i_allocated )
180 msg_Err( p_input, "%d bytes have not been freed, "
181 "expect memory leak", p_buffers->i_allocated );
184 vlc_mutex_destroy( &p_buffers->lock );
189 /*****************************************************************************
190 * input_NewBuffer: return a pointer to a data buffer of the appropriate size
191 *****************************************************************************/
192 static inline data_buffer_t * NewBuffer( input_buffers_t * p_buffers,
195 data_buffer_t * p_buf;
198 if( p_buffers->i_allocated > INPUT_MAX_ALLOCATION )
203 if( p_buffers->buffers.p_stack != NULL )
205 /* Take the buffer from the cache */
206 p_buf = p_buffers->buffers.p_stack;
207 p_buffers->buffers.p_stack = p_buf->p_next;
208 p_buffers->buffers.i_depth--;
210 /* Reallocate the packet if it is too small or too large */
211 if( p_buf->i_size < i_size || p_buf->i_size > 3 * i_size )
213 p_buffers->i_allocated -= p_buf->i_size;
215 p_buf = malloc( sizeof(input_buffers_t) + i_size );
220 p_buf->i_size = i_size;
221 p_buffers->i_allocated += i_size;
226 /* Allocate a new buffer */
227 p_buf = malloc( sizeof(input_buffers_t) + i_size );
232 p_buf->i_size = i_size;
233 p_buffers->i_allocated += i_size;
236 /* Initialize data */
237 p_buf->p_next = NULL;
238 p_buf->i_refcount = 0;
243 data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
245 data_buffer_t * p_buf;
247 vlc_mutex_lock( &p_buffers->lock );
248 p_buf = NewBuffer( p_buffers, i_size );
249 vlc_mutex_unlock( &p_buffers->lock );
254 /*****************************************************************************
255 * input_ReleaseBuffer: put a buffer back into the cache
256 *****************************************************************************/
257 static inline void ReleaseBuffer( input_buffers_t * p_buffers,
258 data_buffer_t * p_buf )
260 /* Decrement refcount */
261 if( --p_buf->i_refcount > 0 )
266 if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
268 /* Cache not full : store the buffer in it */
269 p_buf->p_next = p_buffers->buffers.p_stack;
270 p_buffers->buffers.p_stack = p_buf;
271 p_buffers->buffers.i_depth++;
275 p_buffers->i_allocated -= p_buf->i_size;
280 void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
282 vlc_mutex_lock( &p_buffers->lock );
283 ReleaseBuffer( p_buffers, p_buf );
284 vlc_mutex_unlock( &p_buffers->lock );
287 /*****************************************************************************
288 * input_ShareBuffer: allocate a data_packet_t pointing to a given buffer
289 *****************************************************************************/
290 static inline data_packet_t * ShareBuffer( input_buffers_t * p_buffers,
291 data_buffer_t * p_buf )
293 data_packet_t * p_data;
295 if( p_buffers->data.p_stack != NULL )
297 /* Take the packet from the cache */
298 p_data = p_buffers->data.p_stack;
299 p_buffers->data.p_stack = p_data->p_next;
300 p_buffers->data.i_depth--;
304 /* Allocate a new packet */
305 p_data = malloc( sizeof(data_packet_t) );
312 p_data->p_buffer = p_buf;
313 p_data->p_next = NULL;
314 p_data->b_discard_payload = 0;
315 p_data->p_payload_start = p_data->p_demux_start
316 = (byte_t *)p_buf + sizeof(input_buffers_t);
317 p_data->p_payload_end = p_data->p_demux_start + p_buf->i_size;
323 data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
324 data_buffer_t * p_buf )
326 data_packet_t * p_data;
328 vlc_mutex_lock( &p_buffers->lock );
329 p_data = ShareBuffer( p_buffers, p_buf );
330 vlc_mutex_unlock( &p_buffers->lock );
335 /*****************************************************************************
336 * input_NewPacket: allocate a packet along with a buffer
337 *****************************************************************************/
338 static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
341 data_buffer_t * p_buf;
342 data_packet_t * p_data;
344 p_buf = NewBuffer( p_buffers, i_size );
351 p_data = ShareBuffer( p_buffers, p_buf );
354 ReleaseBuffer( p_buffers, p_buf );
359 data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
361 data_packet_t * p_data;
363 vlc_mutex_lock( &p_buffers->lock );
364 p_data = NewPacket( p_buffers, i_size );
365 vlc_mutex_unlock( &p_buffers->lock );
370 /*****************************************************************************
371 * input_DeletePacket: deallocate a packet and its buffers
372 *****************************************************************************/
373 static inline void DeletePacket( input_buffers_t * p_buffers,
374 data_packet_t * p_data )
376 while( p_data != NULL )
378 data_packet_t * p_next = p_data->p_next;
380 ReleaseBuffer( p_buffers, p_data->p_buffer );
382 if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
384 /* Cache not full : store the packet in it */
385 p_data->p_next = p_buffers->data.p_stack;
386 p_buffers->data.p_stack = p_data;
387 p_buffers->data.i_depth++;
398 void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
400 vlc_mutex_lock( &p_buffers->lock );
401 DeletePacket( p_buffers, p_data );
402 vlc_mutex_unlock( &p_buffers->lock );
405 /*****************************************************************************
406 * input_NewPES: return a pointer to a new PES packet
407 *****************************************************************************/
408 static inline pes_packet_t * NewPES( input_buffers_t * p_buffers )
410 pes_packet_t * p_pes;
412 if( p_buffers->pes.p_stack != NULL )
414 /* Take the packet from the cache */
415 p_pes = p_buffers->pes.p_stack;
416 p_buffers->pes.p_stack = p_pes->p_next;
417 p_buffers->pes.i_depth--;
421 /* Allocate a new packet */
422 p_pes = malloc( sizeof(pes_packet_t) );
429 p_pes->p_next = NULL;
430 p_pes->b_data_alignment = p_pes->b_discontinuity =
431 p_pes->i_pts = p_pes->i_dts = 0;
432 p_pes->p_first = p_pes->p_last = NULL;
433 p_pes->i_pes_size = 0;
434 p_pes->i_nb_data = 0;
439 pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
441 pes_packet_t * p_pes;
443 vlc_mutex_lock( &p_buffers->lock );
444 p_pes = NewPES( p_buffers );
445 vlc_mutex_unlock( &p_buffers->lock );
450 /*****************************************************************************
451 * input_DeletePES: put a pes and all data packets and all buffers back into
453 *****************************************************************************/
454 static inline void DeletePES( input_buffers_t * p_buffers,
455 pes_packet_t * p_pes )
457 while( p_pes != NULL )
459 pes_packet_t * p_next = p_pes->p_next;
461 /* Delete all data packets */
462 if( p_pes->p_first != NULL )
464 DeletePacket( p_buffers, p_pes->p_first );
467 if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
469 /* Cache not full : store the packet in it */
470 p_pes->p_next = p_buffers->pes.p_stack;
471 p_buffers->pes.p_stack = p_pes;
472 p_buffers->pes.i_depth++;
483 void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
485 vlc_mutex_lock( &p_buffers->lock );
486 DeletePES( p_buffers, p_pes );
487 vlc_mutex_unlock( &p_buffers->lock );
492 * Buffers management : external functions
494 * These functions make the glu between the access plug-in (pf_read) and
495 * the demux plug-in (pf_demux). We fill in a large buffer (approx. 10s kB)
496 * with a call to pf_read, then allow the demux plug-in to have a peep at
497 * it (input_Peek), and to split it in data_packet_t (input_SplitBuffer).
499 /*****************************************************************************
500 * input_FillBuffer: fill in p_data_buffer with data from pf_read
501 *****************************************************************************/
502 ssize_t input_FillBuffer( input_thread_t * p_input )
504 ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
505 data_buffer_t * p_buf;
508 vlc_mutex_lock( &p_input->p_method_data->lock );
510 p_buf = NewBuffer( p_input->p_method_data,
511 i_remains + p_input->i_bufsize );
514 msg_Err( p_input, "failed allocating a new buffer (decoder stuck?)" );
517 p_buf->i_refcount = 1;
519 if( p_input->p_data_buffer != NULL )
523 p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
524 p_input->p_current_data,
527 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
530 /* Do not hold the lock during pf_read (blocking call). */
531 vlc_mutex_unlock( &p_input->p_method_data->lock );
533 i_ret = p_input->pf_read( p_input,
534 (byte_t *)p_buf + sizeof(data_buffer_t)
536 p_input->i_bufsize );
537 if( i_ret < 0 ) i_ret = 0;
539 p_input->p_data_buffer = p_buf;
540 p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
541 p_input->p_last_data = p_input->p_current_data + i_remains + i_ret;
543 return (ssize_t)i_remains + i_ret;
546 /*****************************************************************************
547 * input_Peek: give a pointer to the next available bytes in the buffer
548 * (min. i_size bytes)
549 * Returns the number of bytes read, or -1 in case of error
550 *****************************************************************************/
551 ssize_t input_Peek( input_thread_t * p_input, byte_t ** pp_byte, size_t i_size )
553 if( p_input->p_last_data - p_input->p_current_data < i_size )
555 /* Go to the next buffer */
556 ssize_t i_ret = input_FillBuffer( p_input );
562 else if( i_ret < i_size )
567 *pp_byte = p_input->p_current_data;
571 /*****************************************************************************
572 * input_SplitBuffer: give a pointer to a data packet containing i_size bytes
573 * Returns the number of bytes read, or -1 in case of error
574 *****************************************************************************/
575 ssize_t input_SplitBuffer( input_thread_t * p_input,
576 data_packet_t ** pp_data, size_t i_size )
578 if( p_input->p_last_data - p_input->p_current_data < i_size )
580 /* Go to the next buffer */
581 ssize_t i_ret = input_FillBuffer( p_input );
587 else if( i_ret < i_size )
598 *pp_data = input_ShareBuffer( p_input->p_method_data,
599 p_input->p_data_buffer );
601 (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
602 = p_input->p_current_data;
603 (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
605 p_input->p_current_data += i_size;
607 /* Update stream position */
608 vlc_mutex_lock( &p_input->stream.stream_lock );
609 p_input->stream.p_selected_area->i_tell += i_size;
610 vlc_mutex_unlock( &p_input->stream.stream_lock );
615 /*****************************************************************************
616 * input_AccessInit: initialize access plug-in wrapper structures
617 *****************************************************************************/
618 int input_AccessInit( input_thread_t * p_input )
620 p_input->p_method_data = input_BuffersInit( p_input );
621 if( p_input->p_method_data == NULL ) return -1;
622 p_input->p_data_buffer = NULL;
623 p_input->p_current_data = NULL;
624 p_input->p_last_data = NULL;
628 /*****************************************************************************
629 * input_AccessReinit: reinit structures after a random seek
630 *****************************************************************************/
631 void input_AccessReinit( input_thread_t * p_input )
633 if( p_input->p_data_buffer != NULL )
635 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
637 p_input->p_data_buffer = NULL;
638 p_input->p_current_data = NULL;
639 p_input->p_last_data = NULL;
642 /*****************************************************************************
643 * input_AccessEnd: free access plug-in wrapper structures
644 *****************************************************************************/
645 void input_AccessEnd( input_thread_t * p_input )
647 if( p_input->p_data_buffer != NULL )
649 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
652 input_BuffersEnd( p_input, p_input->p_method_data );
657 * Optional file descriptor management functions, for use by access plug-ins
658 * base on file descriptors (file, udp, http...).
661 /*****************************************************************************
662 * input_FDClose: close the target
663 *****************************************************************************/
664 void __input_FDClose( vlc_object_t * p_this )
666 input_thread_t * p_input = (input_thread_t *)p_this;
667 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
669 msg_Info( p_input, "closing `%s/%s://%s'",
670 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
672 close( p_access_data->i_handle );
673 free( p_access_data );
676 /*****************************************************************************
677 * input_FDNetworkClose: close a network target
678 *****************************************************************************/
679 void __input_FDNetworkClose( vlc_object_t * p_this )
681 input_thread_t * p_input = (input_thread_t *)p_this;
682 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
684 msg_Info( p_input, "closing network `%s/%s://%s'",
685 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
687 #if defined( WIN32 ) && !defined( UNDER_CE )
688 closesocket( p_access_data->i_handle );
690 close( p_access_data->i_handle );
693 free( p_access_data );
696 /*****************************************************************************
697 * input_FDRead: standard read on a file descriptor.
698 *****************************************************************************/
699 ssize_t input_FDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
701 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
703 ssize_t i_ret = read( p_access_data->i_handle, p_buffer, i_len );
708 msg_Err( p_input, "read failed (%s)", strerror(errno) );
710 msg_Err( p_input, "read failed" );
717 /*****************************************************************************
718 * NetworkSelect: Checks whether data is available on a file descriptor
719 *****************************************************************************/
720 static inline int NetworkSelect( input_thread_t * p_input )
726 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
727 struct timeval timeout;
731 /* Initialize file descriptor set */
733 FD_SET( p_access_data->i_handle, &fds );
735 /* We'll wait 0.5 second if nothing happens */
737 timeout.tv_usec = 500000;
739 /* Find if some data is available */
740 i_ret = select( p_access_data->i_handle + 1, &fds,
741 NULL, NULL, &timeout );
743 if( i_ret == -1 && errno != EINTR )
745 msg_Err( p_input, "network select error (%s)", strerror(errno) );
753 /*****************************************************************************
754 * input_FDNetworkRead: read on a file descriptor, checking periodically
756 *****************************************************************************/
757 ssize_t input_FDNetworkRead( input_thread_t * p_input, byte_t * p_buffer,
764 if( NetworkSelect( p_input ) > 0 )
766 input_socket_t * p_access_data
767 = (input_socket_t *)p_input->p_access_data;
769 ssize_t i_ret = recv( p_access_data->i_handle, p_buffer, i_len, 0 );
773 vlc_mutex_lock( &p_input->stream.stream_lock );
774 p_input->stream.p_selected_area->i_tell += i_ret;
775 vlc_mutex_unlock( &p_input->stream.stream_lock );
780 msg_Err( p_input, "recv failed (%s)", strerror(errno) );
791 /*****************************************************************************
792 * input_FDSeek: seek to a specific location in a file
793 *****************************************************************************/
794 void input_FDSeek( input_thread_t * p_input, off_t i_pos )
796 #define S p_input->stream
797 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
799 lseek( p_access_data->i_handle, i_pos, SEEK_SET );
801 vlc_mutex_lock( &S.stream_lock );
802 S.p_selected_area->i_tell = i_pos;
803 if( S.p_selected_area->i_tell > S.p_selected_area->i_size )
805 msg_Err( p_input, "seeking too far" );
806 S.p_selected_area->i_tell = S.p_selected_area->i_size;
808 else if( S.p_selected_area->i_tell < 0 )
810 msg_Err( p_input, "seeking too early" );
811 S.p_selected_area->i_tell = 0;
813 vlc_mutex_unlock( &S.stream_lock );