]> git.sesse.net Git - vlc/blob - src/input/input_ext-plugins.c
930eb87495cb249b7047dc2756a82f7d27deec66
[vlc] / src / input / input_ext-plugins.c
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 $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
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.
13  * 
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <fcntl.h>
34
35 #include <vlc/vlc.h>
36
37 #ifdef HAVE_SYS_TIME_H
38 #    include <sys/time.h>
39 #endif
40
41 #ifdef HAVE_UNISTD_H
42 #   include <unistd.h>
43 #elif defined( _MSC_VER ) && defined( _WIN32 )
44 #   include <io.h>
45 #endif
46
47 #ifdef 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() */
56 #   endif
57 #endif
58
59 #ifdef WIN32
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() */
68 #   endif
69 #endif
70
71
72
73 #include "stream_control.h"
74 #include "input_ext-intf.h"
75 #include "input_ext-dec.h"
76 #include "input_ext-plugins.h"
77
78
79 /*
80  * Buffers management : internal functions
81  *
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.
85  */
86
87 #define BUFFERS_CACHE_SIZE 500
88 #define DATA_CACHE_SIZE 1000
89 #define PES_CACHE_SIZE 1000
90
91 /*****************************************************************************
92  * data_buffer_t: shared data type
93  *****************************************************************************/
94 struct data_buffer_t
95 {
96     data_buffer_t * p_next;
97
98     /* number of data packets this buffer is referenced from - when it falls
99      * down to 0, the buffer is freed */
100     int i_refcount;
101
102     /* size of the current buffer (starting right after this byte) */
103     size_t i_size;
104 };
105
106 /*****************************************************************************
107  * input_buffers_t: defines a LIFO per data type to keep
108  *****************************************************************************/
109 #define PACKETS_LIFO( TYPE, NAME )                                          \
110 struct                                                                      \
111 {                                                                           \
112     TYPE * p_stack;                                                         \
113     unsigned int i_depth;                                                   \
114 } NAME;
115
116 struct input_buffers_t
117 {
118     vlc_mutex_t lock;
119     PACKETS_LIFO( pes_packet_t, pes )
120     PACKETS_LIFO( data_packet_t, data )
121     PACKETS_LIFO( data_buffer_t, buffers )
122     size_t i_allocated;
123 };
124
125
126 /*****************************************************************************
127  * input_BuffersInit: initialize the cache structures, return a pointer to it
128  *****************************************************************************/
129 void * __input_BuffersInit( vlc_object_t *p_this )
130 {
131     input_buffers_t * p_buffers = malloc( sizeof( input_buffers_t ) );
132
133     if( p_buffers == NULL )
134     {
135         return( NULL );
136     }
137
138     memset( p_buffers, 0, sizeof( input_buffers_t ) );
139     vlc_mutex_init( p_this, &p_buffers->lock );
140
141     return( p_buffers );
142 }
143
144 /*****************************************************************************
145  * input_BuffersEnd: free all cached structures
146  *****************************************************************************/
147 #define BUFFERS_END_PACKETS_LOOP                                            \
148     while( p_packet != NULL )                                               \
149     {                                                                       \
150         p_next = p_packet->p_next;                                          \
151         free( p_packet );                                                   \
152         p_packet = p_next;                                                  \
153     }
154
155 void input_BuffersEnd( input_thread_t * p_input, input_buffers_t * p_buffers )
156 {
157     if( p_buffers != NULL )
158     {
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 );
162
163         {
164             /* Free PES */
165             pes_packet_t * p_next, * p_packet = p_buffers->pes.p_stack;
166             BUFFERS_END_PACKETS_LOOP;
167         }
168
169         {
170             /* Free data packets */
171             data_packet_t * p_next, * p_packet = p_buffers->data.p_stack;
172             BUFFERS_END_PACKETS_LOOP;
173         }
174
175         {
176             /* Free buffers */
177             data_buffer_t * p_next, * p_buf = p_buffers->buffers.p_stack;
178             while( p_buf != NULL )
179             {
180                 p_next = p_buf->p_next;
181                 p_buffers->i_allocated -= p_buf->i_size;
182                 free( p_buf );
183                 p_buf = p_next;
184             }
185         } 
186
187         if( p_buffers->i_allocated )
188         {
189             msg_Err( p_input, "%d bytes have not been freed, "
190                               "expect memory leak", p_buffers->i_allocated );
191         }
192
193         vlc_mutex_destroy( &p_buffers->lock );
194         free( p_buffers );
195     }
196 }
197
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,
202                                          size_t i_size )
203 {
204     data_buffer_t * p_buf;
205
206     /* Safety check */
207     if( p_buffers->i_allocated > INPUT_MAX_ALLOCATION )
208     {
209 //X        intf_Err( "INPUT_MAX_ALLOCATION reached (%d)",
210 //X                     p_buffers->i_allocated );
211         return NULL;
212     } 
213
214     if( p_buffers->buffers.p_stack != NULL )
215     {
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--;
220
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 )
223         {
224             p_buffers->i_allocated -= p_buf->i_size;
225             free( p_buf );
226             p_buf = malloc( sizeof(input_buffers_t) + i_size );
227             if( p_buf == NULL )
228             {
229 //X                intf_ErrMsg( "Out of memory" );
230                 return NULL;
231             }
232             p_buf->i_size = i_size;
233             p_buffers->i_allocated += i_size;
234         }
235     }
236     else
237     {
238         /* Allocate a new buffer */
239         p_buf = malloc( sizeof(input_buffers_t) + i_size );
240         if( p_buf == NULL )
241         {
242 //X            intf_ErrMsg( "Out of memory" );
243             return NULL;
244         }
245         p_buf->i_size = i_size;
246         p_buffers->i_allocated += i_size;
247     }
248
249     /* Initialize data */
250     p_buf->p_next = NULL;
251     p_buf->i_refcount = 0;
252
253     return( p_buf );
254 }
255
256 data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
257 {
258     data_buffer_t * p_buf;
259
260     vlc_mutex_lock( &p_buffers->lock );
261     p_buf = NewBuffer( p_buffers, i_size );
262     vlc_mutex_unlock( &p_buffers->lock );
263
264     return( p_buf );
265 }
266
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 )
272 {
273     /* Decrement refcount */
274     if( --p_buf->i_refcount > 0 )
275     {
276         return;
277     }
278
279     if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
280     {
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++;
285     }
286     else
287     {
288         p_buffers->i_allocated -= p_buf->i_size;
289         free( p_buf );
290     }
291 }
292
293 void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
294 {
295     vlc_mutex_lock( &p_buffers->lock );
296     ReleaseBuffer( p_buffers, p_buf );
297     vlc_mutex_unlock( &p_buffers->lock );
298 }
299
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 )
305 {
306     data_packet_t * p_data;
307
308     if( p_buffers->data.p_stack != NULL )
309     {
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--;
314     }
315     else
316     {
317         /* Allocate a new packet */
318         p_data = malloc( sizeof(data_packet_t) );
319         if( p_data == NULL )
320         {
321 //X            intf_ErrMsg( "Out of memory" );
322             return NULL;
323         }
324     }
325
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;
332     p_buf->i_refcount++;
333
334     return( p_data );
335 }
336
337 data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
338                                    data_buffer_t * p_buf )
339 {
340     data_packet_t * p_data;
341
342     vlc_mutex_lock( &p_buffers->lock );
343     p_data = ShareBuffer( p_buffers, p_buf );
344     vlc_mutex_unlock( &p_buffers->lock );
345
346     return( p_data );
347 }
348
349 /*****************************************************************************
350  * input_NewPacket: allocate a packet along with a buffer
351  *****************************************************************************/
352 static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
353                                          size_t i_size )
354 {
355     data_buffer_t * p_buf = NewBuffer( p_buffers, i_size );
356     data_packet_t * p_data;
357
358     if( p_buf == NULL )
359     {
360         return( NULL );
361     }
362
363     p_data = ShareBuffer( p_buffers, p_buf );
364     if( p_data == NULL )
365     {
366         ReleaseBuffer( p_buffers, p_buf );
367     }
368     return( p_data );
369 }
370
371 data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
372 {
373     data_packet_t * p_data;
374
375     vlc_mutex_lock( &p_buffers->lock );
376     p_data = NewPacket( p_buffers, i_size );
377     vlc_mutex_unlock( &p_buffers->lock );
378
379     return( p_data );
380 }
381
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 )
387 {
388     while( p_data != NULL )
389     {
390         data_packet_t * p_next = p_data->p_next;
391
392         ReleaseBuffer( p_buffers, p_data->p_buffer );
393
394         if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
395         {
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++;
400         }
401         else
402         {
403             free( p_data );
404         }
405
406         p_data = p_next;
407     }
408 }
409
410 void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
411 {
412     vlc_mutex_lock( &p_buffers->lock );
413     DeletePacket( p_buffers, p_data );
414     vlc_mutex_unlock( &p_buffers->lock );
415 }
416
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 )
421 {
422     pes_packet_t * p_pes;
423
424     if( p_buffers->pes.p_stack != NULL )
425     {
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--;
430     }
431     else
432     {
433         /* Allocate a new packet */
434         p_pes = malloc( sizeof(pes_packet_t) );
435         if( p_pes == NULL )
436         {
437 //X            intf_ErrMsg( "Out of memory" );
438             return NULL;
439         }
440     }
441
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;
448
449     return( p_pes );
450 }
451
452 pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
453 {
454     pes_packet_t * p_pes;
455
456     vlc_mutex_lock( &p_buffers->lock );
457     p_pes = NewPES( p_buffers );
458     vlc_mutex_unlock( &p_buffers->lock );
459
460     return( p_pes );
461 }
462
463 /*****************************************************************************
464  * input_DeletePES: put a pes and all data packets and all buffers back into
465  *                  the cache
466  *****************************************************************************/
467 static inline void DeletePES( input_buffers_t * p_buffers,
468                               pes_packet_t * p_pes )
469 {
470     while( p_pes != NULL )
471     {
472         pes_packet_t * p_next = p_pes->p_next;
473
474         /* Delete all data packets */
475         if( p_pes->p_first != NULL )
476         {
477             DeletePacket( p_buffers, p_pes->p_first );
478         }
479
480         if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
481         {
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++;
486         }
487         else
488         {
489             free( p_pes );
490         }
491
492         p_pes = p_next;
493     }
494 }
495
496 void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
497 {
498     vlc_mutex_lock( &p_buffers->lock );
499     DeletePES( p_buffers, p_pes );
500     vlc_mutex_unlock( &p_buffers->lock );
501 }
502
503
504 /*
505  * Buffers management : external functions
506  *
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).
511  */
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 )
516 {
517     ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
518     data_buffer_t * p_buf;
519     ssize_t i_ret;
520
521     vlc_mutex_lock( &p_input->p_method_data->lock );
522
523     p_buf = NewBuffer( p_input->p_method_data,
524                        i_remains + p_input->i_bufsize );
525     if( p_buf == NULL )
526     {
527         return( -1 );
528     }
529     p_buf->i_refcount = 1;
530
531     if( p_input->p_data_buffer != NULL )
532     {
533         if( i_remains )
534         {
535             p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
536                                        p_input->p_current_data,
537                                        (size_t)i_remains );
538         }
539         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
540     }
541
542     /* Do not hold the lock during pf_read (blocking call). */
543     vlc_mutex_unlock( &p_input->p_method_data->lock );
544
545     i_ret = p_input->pf_read( p_input,
546                               (byte_t *)p_buf + sizeof(data_buffer_t)
547                                + i_remains,
548                               p_input->i_bufsize );
549     if( i_ret < 0 ) i_ret = 0;
550
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;
554
555     return( (ssize_t)i_remains + i_ret );
556 }
557
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 )
564 {
565     if( p_input->p_last_data - p_input->p_current_data < i_size )
566     {
567         /* Go to the next buffer */
568         ssize_t i_ret = input_FillBuffer( p_input );
569
570         if( i_size == -1 )
571         {
572             return( -1 );
573         }
574         else if( i_ret < i_size )
575         {
576             i_size = i_ret;
577         }
578     }
579     *pp_byte = p_input->p_current_data;
580     return( i_size );
581 }
582
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 )
589 {
590     if( p_input->p_last_data - p_input->p_current_data < i_size )
591     {
592         /* Go to the next buffer */
593         ssize_t i_ret = input_FillBuffer( p_input );
594
595         if( i_ret == -1 )
596         {
597             return( -1 );
598         }
599         else if( i_ret < i_size )
600         {
601             i_size = i_ret;
602         }
603     }
604
605     if ( !i_size )
606     {
607         return 0;
608     }
609
610     *pp_data = input_ShareBuffer( p_input->p_method_data,
611                                   p_input->p_data_buffer );
612
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;
616
617     p_input->p_current_data += i_size;
618
619     return( i_size );
620 }
621
622 /*****************************************************************************
623  * input_AccessInit: initialize access plug-in wrapper structures
624  *****************************************************************************/
625 int input_AccessInit( input_thread_t * p_input )
626 {
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;
632     return( 0 );
633 }
634
635 /*****************************************************************************
636  * input_AccessReinit: reinit structures after a random seek
637  *****************************************************************************/
638 void input_AccessReinit( input_thread_t * p_input )
639 {
640     if( p_input->p_data_buffer != NULL )
641     {
642         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
643     }
644     p_input->p_data_buffer = NULL;
645     p_input->p_current_data = NULL;
646     p_input->p_last_data = NULL;
647 }
648
649 /*****************************************************************************
650  * input_AccessEnd: free access plug-in wrapper structures
651  *****************************************************************************/
652 void input_AccessEnd( input_thread_t * p_input )
653 {
654     if( p_input->p_data_buffer != NULL )
655     {
656         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
657     }
658
659     input_BuffersEnd( p_input, p_input->p_method_data );
660 }
661
662
663 /*
664  * Optional file descriptor management functions, for use by access plug-ins
665  * base on file descriptors (file, udp, http...).
666  */
667
668 /*****************************************************************************
669  * input_FDClose: close the target
670  *****************************************************************************/
671 void input_FDClose( input_thread_t * p_input )
672 {
673     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
674
675     msg_Info( p_input, "closing `%s/%s://%s'", 
676               p_input->psz_access, p_input->psz_demux, p_input->psz_name );
677  
678     close( p_access_data->i_handle );
679     free( p_access_data );
680 }
681
682 /*****************************************************************************
683  * input_FDNetworkClose: close a network target
684  *****************************************************************************/
685 void input_FDNetworkClose( input_thread_t * p_input )
686 {
687     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
688
689     msg_Info( p_input, "closing network `%s/%s://%s'", 
690               p_input->psz_access, p_input->psz_demux, p_input->psz_name );
691  
692 #ifdef WIN32
693     closesocket( p_access_data->i_handle );
694 #else
695     close( p_access_data->i_handle );
696 #endif
697
698     free( p_access_data );
699 }
700
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 )
705 {
706     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
707  
708     ssize_t i_ret = read( p_access_data->i_handle, p_buffer, i_len );
709  
710     if( i_ret > 0 )
711     {
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 );
715     }
716  
717     if( i_ret < 0 )
718     {
719         msg_Err( p_input, "read failed (%s)", strerror(errno) );
720     }
721  
722     return( i_ret );
723 }
724
725 /*****************************************************************************
726  * NetworkSelect: Checks whether data is available on a file descriptor
727  *****************************************************************************/
728 static inline int NetworkSelect( input_thread_t * p_input )
729 {
730     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
731     struct timeval  timeout;
732     fd_set          fds;
733     int             i_ret;
734
735     /* Initialize file descriptor set */
736     FD_ZERO( &fds );
737     FD_SET( p_access_data->i_handle, &fds );
738
739     /* We'll wait 0.5 second if nothing happens */
740     timeout.tv_sec = 0;
741     timeout.tv_usec = 500000;
742  
743     /* Find if some data is available */
744     i_ret = select( p_access_data->i_handle + 1, &fds,
745                      NULL, NULL, &timeout );
746  
747     if( i_ret == -1 && errno != EINTR )
748     {
749         msg_Err( p_input, "network select error (%s)", strerror(errno) );
750     }
751
752     return( i_ret );
753 }
754
755 /*****************************************************************************
756  * input_FDNetworkRead: read on a file descriptor, checking periodically
757  * p_input->b_die
758  *****************************************************************************/
759 ssize_t input_FDNetworkRead( input_thread_t * p_input, byte_t * p_buffer,
760                              size_t i_len )
761 {
762     if( NetworkSelect( p_input ) > 0 )
763     {
764         input_socket_t * p_access_data
765                              = (input_socket_t *)p_input->p_access_data;
766
767         ssize_t i_ret = recv( p_access_data->i_handle, p_buffer, i_len, 0 );
768
769         if( i_ret > 0 )
770         {
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 );
774         }
775
776         if( i_ret < 0 )
777         {
778             msg_Err( p_input, "recv failed (%s)", strerror(errno) );
779         }
780
781         return( i_ret );
782     }
783     
784     return( 0 );
785 }
786
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 )
791 {
792 #define S p_input->stream
793     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
794
795     lseek( p_access_data->i_handle, i_pos, SEEK_SET );
796
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 )
800     {
801         msg_Err( p_input, "seeking too far" );
802         S.p_selected_area->i_tell = S.p_selected_area->i_size;
803     }
804     else if( S.p_selected_area->i_tell < 0 )
805     {
806         msg_Err( p_input, "seeking too early" );
807         S.p_selected_area->i_tell = 0;
808     }
809     vlc_mutex_unlock( &S.stream_lock );
810 #undef S
811 }
812
813