]> git.sesse.net Git - vlc/blob - src/input/input_ext-plugins.c
fcc5ae1566d597ff964cb3f6bf3cd10915f52135
[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.19 2002/10/26 15:24:19 gbazin 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         return NULL;
210     } 
211
212     if( p_buffers->buffers.p_stack != NULL )
213     {
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--;
218
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 )
221         {
222             p_buffers->i_allocated -= p_buf->i_size;
223             free( p_buf );
224             p_buf = malloc( sizeof(input_buffers_t) + i_size );
225             if( p_buf == NULL )
226             {
227                 return NULL;
228             }
229             p_buf->i_size = i_size;
230             p_buffers->i_allocated += i_size;
231         }
232     }
233     else
234     {
235         /* Allocate a new buffer */
236         p_buf = malloc( sizeof(input_buffers_t) + i_size );
237         if( p_buf == NULL )
238         {
239             return NULL;
240         }
241         p_buf->i_size = i_size;
242         p_buffers->i_allocated += i_size;
243     }
244
245     /* Initialize data */
246     p_buf->p_next = NULL;
247     p_buf->i_refcount = 0;
248
249     return p_buf;
250 }
251
252 data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
253 {
254     data_buffer_t * p_buf;
255
256     vlc_mutex_lock( &p_buffers->lock );
257     p_buf = NewBuffer( p_buffers, i_size );
258     vlc_mutex_unlock( &p_buffers->lock );
259
260     return( p_buf );
261 }
262
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 )
268 {
269     /* Decrement refcount */
270     if( --p_buf->i_refcount > 0 )
271     {
272         return;
273     }
274
275     if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
276     {
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++;
281     }
282     else
283     {
284         p_buffers->i_allocated -= p_buf->i_size;
285         free( p_buf );
286     }
287 }
288
289 void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
290 {
291     vlc_mutex_lock( &p_buffers->lock );
292     ReleaseBuffer( p_buffers, p_buf );
293     vlc_mutex_unlock( &p_buffers->lock );
294 }
295
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 )
301 {
302     data_packet_t * p_data;
303
304     if( p_buffers->data.p_stack != NULL )
305     {
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--;
310     }
311     else
312     {
313         /* Allocate a new packet */
314         p_data = malloc( sizeof(data_packet_t) );
315         if( p_data == NULL )
316         {
317             return NULL;
318         }
319     }
320
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;
327     p_buf->i_refcount++;
328
329     return p_data;
330 }
331
332 data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
333                                    data_buffer_t * p_buf )
334 {
335     data_packet_t * p_data;
336
337     vlc_mutex_lock( &p_buffers->lock );
338     p_data = ShareBuffer( p_buffers, p_buf );
339     vlc_mutex_unlock( &p_buffers->lock );
340
341     return( p_data );
342 }
343
344 /*****************************************************************************
345  * input_NewPacket: allocate a packet along with a buffer
346  *****************************************************************************/
347 static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
348                                          size_t i_size )
349 {
350     data_buffer_t * p_buf;
351     data_packet_t * p_data;
352
353     p_buf = NewBuffer( p_buffers, i_size );
354
355     if( p_buf == NULL )
356     {
357         return( NULL );
358     }
359
360     p_data = ShareBuffer( p_buffers, p_buf );
361     if( p_data == NULL )
362     {
363         ReleaseBuffer( p_buffers, p_buf );
364     }
365     return( p_data );
366 }
367
368 data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
369 {
370     data_packet_t * p_data;
371
372     vlc_mutex_lock( &p_buffers->lock );
373     p_data = NewPacket( p_buffers, i_size );
374     vlc_mutex_unlock( &p_buffers->lock );
375
376     return( p_data );
377 }
378
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 )
384 {
385     while( p_data != NULL )
386     {
387         data_packet_t * p_next = p_data->p_next;
388
389         ReleaseBuffer( p_buffers, p_data->p_buffer );
390
391         if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
392         {
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++;
397         }
398         else
399         {
400             free( p_data );
401         }
402
403         p_data = p_next;
404     }
405 }
406
407 void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
408 {
409     vlc_mutex_lock( &p_buffers->lock );
410     DeletePacket( p_buffers, p_data );
411     vlc_mutex_unlock( &p_buffers->lock );
412 }
413
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 )
418 {
419     pes_packet_t * p_pes;
420
421     if( p_buffers->pes.p_stack != NULL )
422     {
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--;
427     }
428     else
429     {
430         /* Allocate a new packet */
431         p_pes = malloc( sizeof(pes_packet_t) );
432         if( p_pes == NULL )
433         {
434             return NULL;
435         }
436     }
437
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;
444
445     return( p_pes );
446 }
447
448 pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
449 {
450     pes_packet_t * p_pes;
451
452     vlc_mutex_lock( &p_buffers->lock );
453     p_pes = NewPES( p_buffers );
454     vlc_mutex_unlock( &p_buffers->lock );
455
456     return( p_pes );
457 }
458
459 /*****************************************************************************
460  * input_DeletePES: put a pes and all data packets and all buffers back into
461  *                  the cache
462  *****************************************************************************/
463 static inline void DeletePES( input_buffers_t * p_buffers,
464                               pes_packet_t * p_pes )
465 {
466     while( p_pes != NULL )
467     {
468         pes_packet_t * p_next = p_pes->p_next;
469
470         /* Delete all data packets */
471         if( p_pes->p_first != NULL )
472         {
473             DeletePacket( p_buffers, p_pes->p_first );
474         }
475
476         if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
477         {
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++;
482         }
483         else
484         {
485             free( p_pes );
486         }
487
488         p_pes = p_next;
489     }
490 }
491
492 void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
493 {
494     vlc_mutex_lock( &p_buffers->lock );
495     DeletePES( p_buffers, p_pes );
496     vlc_mutex_unlock( &p_buffers->lock );
497 }
498
499
500 /*
501  * Buffers management : external functions
502  *
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).
507  */
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 )
512 {
513     ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
514     data_buffer_t * p_buf;
515     ssize_t i_ret;
516
517     vlc_mutex_lock( &p_input->p_method_data->lock );
518
519     p_buf = NewBuffer( p_input->p_method_data,
520                        i_remains + p_input->i_bufsize );
521     if( p_buf == NULL )
522     {
523         msg_Err( p_input, "failed allocating a new buffer (decoder stuck?)" );
524         return -1;
525     }
526     p_buf->i_refcount = 1;
527
528     if( p_input->p_data_buffer != NULL )
529     {
530         if( i_remains )
531         {
532             p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
533                                        p_input->p_current_data,
534                                        (size_t)i_remains );
535         }
536         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
537     }
538
539     /* Do not hold the lock during pf_read (blocking call). */
540     vlc_mutex_unlock( &p_input->p_method_data->lock );
541
542     i_ret = p_input->pf_read( p_input,
543                               (byte_t *)p_buf + sizeof(data_buffer_t)
544                                + i_remains,
545                               p_input->i_bufsize );
546     if( i_ret < 0 ) i_ret = 0;
547
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;
551
552     return( (ssize_t)i_remains + i_ret );
553 }
554
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 )
561 {
562     if( p_input->p_last_data - p_input->p_current_data < i_size )
563     {
564         /* Go to the next buffer */
565         ssize_t i_ret = input_FillBuffer( p_input );
566
567         if( i_size == -1 )
568         {
569             return( -1 );
570         }
571         else if( i_ret < i_size )
572         {
573             i_size = i_ret;
574         }
575     }
576     *pp_byte = p_input->p_current_data;
577     return( i_size );
578 }
579
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 )
586 {
587     if( p_input->p_last_data - p_input->p_current_data < i_size )
588     {
589         /* Go to the next buffer */
590         ssize_t i_ret = input_FillBuffer( p_input );
591
592         if( i_ret == -1 )
593         {
594             return( -1 );
595         }
596         else if( i_ret < i_size )
597         {
598             i_size = i_ret;
599         }
600     }
601
602     if ( !i_size )
603     {
604         return 0;
605     }
606
607     *pp_data = input_ShareBuffer( p_input->p_method_data,
608                                   p_input->p_data_buffer );
609
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;
613
614     p_input->p_current_data += i_size;
615
616     /* Update stream position */
617     vlc_mutex_lock( &p_input->stream.stream_lock );
618     p_input->stream.p_selected_area->i_tell += i_size;
619     vlc_mutex_unlock( &p_input->stream.stream_lock );
620  
621     return( i_size );
622 }
623
624 /*****************************************************************************
625  * input_AccessInit: initialize access plug-in wrapper structures
626  *****************************************************************************/
627 int input_AccessInit( input_thread_t * p_input )
628 {
629     p_input->p_method_data = input_BuffersInit( p_input );
630     if( p_input->p_method_data == NULL ) return( -1 );
631     p_input->p_data_buffer = NULL;
632     p_input->p_current_data = NULL;
633     p_input->p_last_data = NULL;
634     return( 0 );
635 }
636
637 /*****************************************************************************
638  * input_AccessReinit: reinit structures after a random seek
639  *****************************************************************************/
640 void input_AccessReinit( input_thread_t * p_input )
641 {
642     if( p_input->p_data_buffer != NULL )
643     {
644         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
645     }
646     p_input->p_data_buffer = NULL;
647     p_input->p_current_data = NULL;
648     p_input->p_last_data = NULL;
649 }
650
651 /*****************************************************************************
652  * input_AccessEnd: free access plug-in wrapper structures
653  *****************************************************************************/
654 void input_AccessEnd( input_thread_t * p_input )
655 {
656     if( p_input->p_data_buffer != NULL )
657     {
658         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
659     }
660
661     input_BuffersEnd( p_input, p_input->p_method_data );
662 }
663
664
665 /*
666  * Optional file descriptor management functions, for use by access plug-ins
667  * base on file descriptors (file, udp, http...).
668  */
669
670 /*****************************************************************************
671  * input_FDClose: close the target
672  *****************************************************************************/
673 void __input_FDClose( vlc_object_t * p_this )
674 {
675     input_thread_t * p_input = (input_thread_t *)p_this;
676     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
677
678     msg_Info( p_input, "closing `%s/%s://%s'", 
679               p_input->psz_access, p_input->psz_demux, p_input->psz_name );
680  
681     close( p_access_data->i_handle );
682     free( p_access_data );
683 }
684
685 /*****************************************************************************
686  * input_FDNetworkClose: close a network target
687  *****************************************************************************/
688 void __input_FDNetworkClose( vlc_object_t * p_this )
689 {
690     input_thread_t * p_input = (input_thread_t *)p_this;
691     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
692
693     msg_Info( p_input, "closing network `%s/%s://%s'", 
694               p_input->psz_access, p_input->psz_demux, p_input->psz_name );
695  
696 #ifdef WIN32
697     closesocket( p_access_data->i_handle );
698 #else
699     close( p_access_data->i_handle );
700 #endif
701
702     free( p_access_data );
703 }
704
705 /*****************************************************************************
706  * input_FDRead: standard read on a file descriptor.
707  *****************************************************************************/
708 ssize_t input_FDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
709 {
710     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
711  
712     ssize_t i_ret = read( p_access_data->i_handle, p_buffer, i_len );
713  
714     if( i_ret < 0 )
715     {
716         msg_Err( p_input, "read failed (%s)", strerror(errno) );
717     }
718  
719     return( i_ret );
720 }
721
722 /*****************************************************************************
723  * NetworkSelect: Checks whether data is available on a file descriptor
724  *****************************************************************************/
725 static inline int NetworkSelect( input_thread_t * p_input )
726 {
727     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
728     struct timeval  timeout;
729     fd_set          fds;
730     int             i_ret;
731
732     /* Initialize file descriptor set */
733     FD_ZERO( &fds );
734     FD_SET( p_access_data->i_handle, &fds );
735
736     /* We'll wait 0.5 second if nothing happens */
737     timeout.tv_sec = 0;
738     timeout.tv_usec = 500000;
739  
740     /* Find if some data is available */
741     i_ret = select( p_access_data->i_handle + 1, &fds,
742                      NULL, NULL, &timeout );
743  
744     if( i_ret == -1 && errno != EINTR )
745     {
746         msg_Err( p_input, "network select error (%s)", strerror(errno) );
747     }
748
749     return( i_ret );
750 }
751
752 /*****************************************************************************
753  * input_FDNetworkRead: read on a file descriptor, checking periodically
754  * p_input->b_die
755  *****************************************************************************/
756 ssize_t input_FDNetworkRead( input_thread_t * p_input, byte_t * p_buffer,
757                              size_t i_len )
758 {
759     if( NetworkSelect( p_input ) > 0 )
760     {
761         input_socket_t * p_access_data
762                              = (input_socket_t *)p_input->p_access_data;
763
764         ssize_t i_ret = recv( p_access_data->i_handle, p_buffer, i_len, 0 );
765
766         if( i_ret > 0 )
767         {
768             vlc_mutex_lock( &p_input->stream.stream_lock );
769             p_input->stream.p_selected_area->i_tell += i_ret;
770             vlc_mutex_unlock( &p_input->stream.stream_lock );
771         }
772
773         if( i_ret < 0 )
774         {
775             msg_Err( p_input, "recv failed (%s)", strerror(errno) );
776         }
777
778         return( i_ret );
779     }
780     
781     return( 0 );
782 }
783
784 /*****************************************************************************
785  * input_FDSeek: seek to a specific location in a file
786  *****************************************************************************/
787 void input_FDSeek( input_thread_t * p_input, off_t i_pos )
788 {
789 #define S p_input->stream
790     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
791
792     lseek( p_access_data->i_handle, i_pos, SEEK_SET );
793
794     vlc_mutex_lock( &S.stream_lock );
795     S.p_selected_area->i_tell = i_pos;
796     if( S.p_selected_area->i_tell > S.p_selected_area->i_size )
797     {
798         msg_Err( p_input, "seeking too far" );
799         S.p_selected_area->i_tell = S.p_selected_area->i_size;
800     }
801     else if( S.p_selected_area->i_tell < 0 )
802     {
803         msg_Err( p_input, "seeking too early" );
804         S.p_selected_area->i_tell = 0;
805     }
806     vlc_mutex_unlock( &S.stream_lock );
807 #undef S
808 }
809
810