]> git.sesse.net Git - vlc/blob - src/input/input_ext-plugins.c
* ALL: changed "struct foo_s" into "struct foo_t" to make greppers happy.
[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.14 2002/07/20 18:01:43 sam 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
550     if( i_ret < 0 ) i_ret = 0;
551     p_input->p_data_buffer = p_buf;
552     p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
553     p_input->p_last_data = p_input->p_current_data + i_remains + i_ret;
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     *pp_data = input_ShareBuffer( p_input->p_method_data,
606                                   p_input->p_data_buffer );
607
608     (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
609         = p_input->p_current_data;
610     (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
611
612     p_input->p_current_data += i_size;
613
614     return( i_size );
615 }
616
617 /*****************************************************************************
618  * input_AccessInit: initialize access plug-in wrapper structures
619  *****************************************************************************/
620 int input_AccessInit( input_thread_t * p_input )
621 {
622     p_input->p_method_data = input_BuffersInit( p_input );
623     if( p_input->p_method_data == NULL ) return( -1 );
624     p_input->p_data_buffer = NULL;
625     p_input->p_current_data = NULL;
626     p_input->p_last_data = NULL;
627     return( 0 );
628 }
629
630 /*****************************************************************************
631  * input_AccessReinit: reinit structures after a random seek
632  *****************************************************************************/
633 void input_AccessReinit( input_thread_t * p_input )
634 {
635     if( p_input->p_data_buffer != NULL )
636     {
637         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
638     }
639     p_input->p_data_buffer = NULL;
640     p_input->p_current_data = NULL;
641     p_input->p_last_data = NULL;
642 }
643
644 /*****************************************************************************
645  * input_AccessEnd: free access plug-in wrapper structures
646  *****************************************************************************/
647 void input_AccessEnd( input_thread_t * p_input )
648 {
649     if( p_input->p_data_buffer != NULL )
650     {
651         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
652     }
653
654     input_BuffersEnd( p_input, p_input->p_method_data );
655 }
656
657
658 /*
659  * Optional file descriptor management functions, for use by access plug-ins
660  * base on file descriptors (file, udp, http...).
661  */
662
663 /*****************************************************************************
664  * input_FDClose: close the target
665  *****************************************************************************/
666 void input_FDClose( input_thread_t * p_input )
667 {
668     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
669
670     msg_Info( p_input, "closing `%s/%s://%s'", 
671               p_input->psz_access, p_input->psz_demux, p_input->psz_name );
672  
673     close( p_access_data->i_handle );
674     free( p_access_data );
675 }
676
677 /*****************************************************************************
678  * input_FDNetworkClose: close a network target
679  *****************************************************************************/
680 void input_FDNetworkClose( input_thread_t * p_input )
681 {
682     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
683
684     msg_Info( p_input, "closing network `%s/%s://%s'", 
685               p_input->psz_access, p_input->psz_demux, p_input->psz_name );
686  
687 #ifdef WIN32
688     closesocket( p_access_data->i_handle );
689 #else
690     close( p_access_data->i_handle );
691 #endif
692
693     free( p_access_data );
694 }
695
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 )
700 {
701     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
702  
703     ssize_t i_ret = read( p_access_data->i_handle, p_buffer, i_len );
704  
705     if( i_ret > 0 )
706     {
707         vlc_mutex_lock( &p_input->stream.stream_lock );
708         p_input->stream.p_selected_area->i_tell += i_ret;
709         vlc_mutex_unlock( &p_input->stream.stream_lock );
710     }
711  
712     if( i_ret < 0 )
713     {
714         msg_Err( p_input, "read failed (%s)", strerror(errno) );
715     }
716  
717     return( i_ret );
718 }
719
720 /*****************************************************************************
721  * NetworkSelect: Checks whether data is available on a file descriptor
722  *****************************************************************************/
723 static inline int NetworkSelect( input_thread_t * p_input )
724 {
725     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
726     struct timeval  timeout;
727     fd_set          fds;
728     int             i_ret;
729
730     /* Initialize file descriptor set */
731     FD_ZERO( &fds );
732     FD_SET( p_access_data->i_handle, &fds );
733
734     /* We'll wait 0.5 second if nothing happens */
735     timeout.tv_sec = 0;
736     timeout.tv_usec = 500000;
737  
738     /* Find if some data is available */
739     i_ret = select( p_access_data->i_handle + 1, &fds,
740                      NULL, NULL, &timeout );
741  
742     if( i_ret == -1 && errno != EINTR )
743     {
744         msg_Err( p_input, "network select error (%s)", strerror(errno) );
745     }
746
747     return( i_ret );
748 }
749
750 /*****************************************************************************
751  * input_FDNetworkRead: read on a file descriptor, checking periodically
752  * p_input->b_die
753  *****************************************************************************/
754 ssize_t input_FDNetworkRead( input_thread_t * p_input, byte_t * p_buffer,
755                              size_t i_len )
756 {
757     if( NetworkSelect( p_input ) > 0 )
758     {
759         input_socket_t * p_access_data
760                              = (input_socket_t *)p_input->p_access_data;
761
762         ssize_t i_ret = recv( p_access_data->i_handle, p_buffer, i_len, 0 );
763
764         if( i_ret > 0 )
765         {
766             vlc_mutex_lock( &p_input->stream.stream_lock );
767             p_input->stream.p_selected_area->i_tell += i_ret;
768             vlc_mutex_unlock( &p_input->stream.stream_lock );
769         }
770
771         if( i_ret < 0 )
772         {
773             msg_Err( p_input, "recv failed (%s)", strerror(errno) );
774         }
775
776         return( i_ret );
777     }
778     
779     return( 0 );
780 }
781
782 /*****************************************************************************
783  * input_FDSeek: seek to a specific location in a file
784  *****************************************************************************/
785 void input_FDSeek( input_thread_t * p_input, off_t i_pos )
786 {
787 #define S p_input->stream
788     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
789
790     lseek( p_access_data->i_handle, i_pos, SEEK_SET );
791
792     vlc_mutex_lock( &S.stream_lock );
793     S.p_selected_area->i_tell = i_pos;
794     if( S.p_selected_area->i_tell > S.p_selected_area->i_size )
795     {
796         msg_Err( p_input, "seeking too far" );
797         S.p_selected_area->i_tell = S.p_selected_area->i_size;
798     }
799     else if( S.p_selected_area->i_tell < 0 )
800     {
801         msg_Err( p_input, "seeking too early" );
802         S.p_selected_area->i_tell = 0;
803     }
804     vlc_mutex_unlock( &S.stream_lock );
805 #undef S
806 }
807
808