]> git.sesse.net Git - vlc/blob - src/input/input_ext-plugins.c
50f6ea6eb667ca22a41f24437067176f77ffe624
[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.5 2002/04/02 22:46:25 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 <videolan/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 typedef struct data_buffer_s
95 {
96     struct data_buffer_s * 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 } data_buffer_t;
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 typedef struct input_buffers_s
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 } input_buffers_t;
124
125
126 /*****************************************************************************
127  * input_BuffersInit: initialize the cache structures, return a pointer to it
128  *****************************************************************************/
129 void * input_BuffersInit( void )
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_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_buffers_t * p_buffers )
156 {
157     if( p_buffers != NULL )
158     {
159         if( p_main->b_stats )
160         {
161             intf_StatMsg( "input buffers stats: pes: %d packets",
162                           p_buffers->pes.i_depth );
163             intf_StatMsg( "input buffers stats: data: %d packets",
164                           p_buffers->data.i_depth );
165             intf_StatMsg( "input buffers stats: buffers: %d packets",
166                           p_buffers->buffers.i_depth );
167         }
168
169         {
170             /* Free PES */
171             pes_packet_t * p_next, * p_packet = p_buffers->pes.p_stack;
172             BUFFERS_END_PACKETS_LOOP;
173         }
174
175         {
176             /* Free data packets */
177             data_packet_t * p_next, * p_packet = p_buffers->data.p_stack;
178             BUFFERS_END_PACKETS_LOOP;
179         }
180
181         {
182             /* Free buffers */
183             data_buffer_t * p_next, * p_buf = p_buffers->buffers.p_stack;
184             while( p_buf != NULL )
185             {
186                 p_next = p_buf->p_next;
187                 p_buffers->i_allocated -= p_buf->i_size;
188                 free( p_buf );
189                 p_buf = p_next;
190             }
191         } 
192
193         if( p_buffers->i_allocated )
194         {
195             intf_ErrMsg( "input buffers error: %d bytes have not been"
196                          " freed, expect memory leak",
197                          p_buffers->i_allocated );
198         }
199
200         vlc_mutex_destroy( &p_buffers->lock );
201         free( p_buffers );
202     }
203 }
204
205 /*****************************************************************************
206  * input_NewBuffer: return a pointer to a data buffer of the appropriate size
207  *****************************************************************************/
208 static __inline__ data_buffer_t * NewBuffer( input_buffers_t * p_buffers,
209                                              size_t i_size )
210 {
211     data_buffer_t * p_buf;
212
213     /* Safety check */
214     if( p_buffers->i_allocated > INPUT_MAX_ALLOCATION )
215     {
216         intf_ErrMsg( "INPUT_MAX_ALLOCATION reached (%d)",
217                      p_buffers->i_allocated );
218         return NULL;
219     } 
220
221     if( p_buffers->buffers.p_stack != NULL )
222     {
223         /* Take the buffer from the cache */
224         p_buf = p_buffers->buffers.p_stack;
225         p_buffers->buffers.p_stack = p_buf->p_next;
226         p_buffers->buffers.i_depth--;
227
228         /* Reallocate the packet if it is too small or too large */
229         if( p_buf->i_size < i_size || p_buf->i_size > 3 * i_size )
230         {
231             p_buffers->i_allocated -= p_buf->i_size;
232             free( p_buf );
233             p_buf = malloc( sizeof(input_buffers_t) + i_size );
234             if( p_buf == NULL )
235             {
236                 intf_ErrMsg( "Out of memory" );
237                 return NULL;
238             }
239             p_buf->i_size = i_size;
240             p_buffers->i_allocated += i_size;
241         }
242     }
243     else
244     {
245         /* Allocate a new buffer */
246         p_buf = malloc( sizeof(input_buffers_t) + i_size );
247         if( p_buf == NULL )
248         {
249             intf_ErrMsg( "Out of memory" );
250             return NULL;
251         }
252         p_buf->i_size = i_size;
253         p_buffers->i_allocated += i_size;
254     }
255
256     /* Initialize data */
257     p_buf->p_next = NULL;
258     p_buf->i_refcount = 0;
259
260     return( p_buf );
261 }
262
263 data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
264 {
265     data_buffer_t * p_buf;
266
267     vlc_mutex_lock( &p_buffers->lock );
268     p_buf = NewBuffer( p_buffers, i_size );
269     vlc_mutex_unlock( &p_buffers->lock );
270
271     return( p_buf );
272 }
273
274 /*****************************************************************************
275  * input_ReleaseBuffer: put a buffer back into the cache
276  *****************************************************************************/
277 static __inline__ void ReleaseBuffer( input_buffers_t * p_buffers,
278                                       data_buffer_t * p_buf )
279 {
280     /* Decrement refcount */
281     if( --p_buf->i_refcount > 0 )
282     {
283         return;
284     }
285
286     if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
287     {
288         /* Cache not full : store the buffer in it */
289         p_buf->p_next = p_buffers->buffers.p_stack;
290         p_buffers->buffers.p_stack = p_buf;
291         p_buffers->buffers.i_depth++;
292     }
293     else
294     {
295         p_buffers->i_allocated -= p_buf->i_size;
296         free( p_buf );
297     }
298 }
299
300 void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
301 {
302     vlc_mutex_lock( &p_buffers->lock );
303     ReleaseBuffer( p_buffers, p_buf );
304     vlc_mutex_unlock( &p_buffers->lock );
305 }
306
307 /*****************************************************************************
308  * input_ShareBuffer: allocate a data_packet_t pointing to a given buffer
309  *****************************************************************************/
310 static __inline__ data_packet_t * ShareBuffer( input_buffers_t * p_buffers,
311                                                data_buffer_t * p_buf )
312 {
313     data_packet_t * p_data;
314
315     if( p_buffers->data.p_stack != NULL )
316     {
317         /* Take the packet from the cache */
318         p_data = p_buffers->data.p_stack;
319         p_buffers->data.p_stack = p_data->p_next;
320         p_buffers->data.i_depth--;
321     }
322     else
323     {
324         /* Allocate a new packet */
325         p_data = malloc( sizeof(data_packet_t) );
326         if( p_data == NULL )
327         {
328             intf_ErrMsg( "Out of memory" );
329             return NULL;
330         }
331     }
332
333     p_data->p_buffer = p_buf;
334     p_data->p_next = NULL;
335     p_data->b_discard_payload = 0;
336     p_data->p_payload_start = p_data->p_demux_start
337                             = (byte_t *)p_buf + sizeof(input_buffers_t);
338     p_data->p_payload_end = p_data->p_demux_start + p_buf->i_size;
339     p_buf->i_refcount++;
340
341     return( p_data );
342 }
343
344 data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
345                                    data_buffer_t * p_buf )
346 {
347     data_packet_t * p_data;
348
349     vlc_mutex_lock( &p_buffers->lock );
350     p_data = ShareBuffer( p_buffers, p_buf );
351     vlc_mutex_unlock( &p_buffers->lock );
352
353     return( p_data );
354 }
355
356 /*****************************************************************************
357  * input_NewPacket: allocate a packet along with a buffer
358  *****************************************************************************/
359 static __inline__ data_packet_t * NewPacket( input_buffers_t * p_buffers,
360                                              size_t i_size )
361 {
362     data_buffer_t * p_buf = NewBuffer( p_buffers, i_size );
363     data_packet_t * p_data;
364
365     if( p_buf == NULL )
366     {
367         return( NULL );
368     }
369
370     p_data = ShareBuffer( p_buffers, p_buf );
371     if( p_data == NULL )
372     {
373         ReleaseBuffer( p_buffers, p_buf );
374     }
375     return( p_data );
376 }
377
378 data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
379 {
380     data_packet_t * p_data;
381
382     vlc_mutex_lock( &p_buffers->lock );
383     p_data = NewPacket( p_buffers, i_size );
384     vlc_mutex_unlock( &p_buffers->lock );
385
386     return( p_data );
387 }
388
389 /*****************************************************************************
390  * input_DeletePacket: deallocate a packet and its buffers
391  *****************************************************************************/
392 static __inline__ void DeletePacket( input_buffers_t * p_buffers,
393                                      data_packet_t * p_data )
394 {
395     while( p_data != NULL )
396     {
397         data_packet_t * p_next = p_data->p_next;
398
399         ReleaseBuffer( p_buffers, p_data->p_buffer );
400
401         if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
402         {
403             /* Cache not full : store the packet in it */
404             p_data->p_next = p_buffers->data.p_stack;
405             p_buffers->data.p_stack = p_data;
406             p_buffers->data.i_depth++;
407         }
408         else
409         {
410             free( p_data );
411         }
412
413         p_data = p_next;
414     }
415 }
416
417 void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
418 {
419     vlc_mutex_lock( &p_buffers->lock );
420     DeletePacket( p_buffers, p_data );
421     vlc_mutex_unlock( &p_buffers->lock );
422 }
423
424 /*****************************************************************************
425  * input_NewPES: return a pointer to a new PES packet
426  *****************************************************************************/
427 static __inline__ pes_packet_t * NewPES( input_buffers_t * p_buffers )
428 {
429     pes_packet_t * p_pes;
430
431     if( p_buffers->pes.p_stack != NULL )
432     {
433         /* Take the packet from the cache */
434         p_pes = p_buffers->pes.p_stack;
435         p_buffers->pes.p_stack = p_pes->p_next;
436         p_buffers->pes.i_depth--;
437     }
438     else
439     {
440         /* Allocate a new packet */
441         p_pes = malloc( sizeof(pes_packet_t) );
442         if( p_pes == NULL )
443         {
444             intf_ErrMsg( "Out of memory" );
445             return NULL;
446         }
447     }
448
449     p_pes->p_next = NULL;
450     p_pes->b_data_alignment = p_pes->b_discontinuity =
451         p_pes->i_pts = p_pes->i_dts = 0;
452     p_pes->p_first = p_pes->p_last = NULL;
453     p_pes->i_pes_size = 0;
454     p_pes->i_nb_data = 0;
455
456     return( p_pes );
457 }
458
459 pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
460 {
461     pes_packet_t * p_pes;
462
463     vlc_mutex_lock( &p_buffers->lock );
464     p_pes = NewPES( p_buffers );
465     vlc_mutex_unlock( &p_buffers->lock );
466
467     return( p_pes );
468 }
469
470 /*****************************************************************************
471  * input_DeletePES: put a pes and all data packets and all buffers back into
472  *                  the cache
473  *****************************************************************************/
474 static __inline__ void DeletePES( input_buffers_t * p_buffers,
475                                   pes_packet_t * p_pes )
476 {
477     while( p_pes != NULL )
478     {
479         pes_packet_t * p_next = p_pes->p_next;
480
481         /* Delete all data packets */
482         if( p_pes->p_first != NULL )
483         {
484             DeletePacket( p_buffers, p_pes->p_first );
485         }
486
487         if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
488         {
489             /* Cache not full : store the packet in it */
490             p_pes->p_next = p_buffers->pes.p_stack;
491             p_buffers->pes.p_stack = p_pes;
492             p_buffers->pes.i_depth++;
493         }
494         else
495         {
496             free( p_pes );
497         }
498
499         p_pes = p_next;
500     }
501 }
502
503 void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
504 {
505     vlc_mutex_lock( &p_buffers->lock );
506     DeletePES( p_buffers, p_pes );
507     vlc_mutex_unlock( &p_buffers->lock );
508 }
509
510
511 /*
512  * Buffers management : external functions
513  *
514  * These functions make the glu between the access plug-in (pf_read) and
515  * the demux plug-in (pf_demux). We fill in a large buffer (approx. 10s kB)
516  * with a call to pf_read, then allow the demux plug-in to have a peep at
517  * it (input_Peek), and to split it in data_packet_t (input_SplitBuffer).
518  */
519 /*****************************************************************************
520  * input_FillBuffer: fill in p_data_buffer with data from pf_read
521  *****************************************************************************/
522 ssize_t input_FillBuffer( input_thread_t * p_input )
523 {
524     ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
525     data_buffer_t * p_buf;
526     ssize_t i_ret;
527
528     vlc_mutex_lock( &p_input->p_method_data->lock );
529
530     p_buf = NewBuffer( p_input->p_method_data,
531                        i_remains + p_input->i_bufsize );
532     if( p_buf == NULL )
533     {
534         return( -1 );
535     }
536     p_buf->i_refcount = 1;
537
538     if( p_input->p_data_buffer != NULL )
539     {
540         if( i_remains )
541         {
542             FAST_MEMCPY( (byte_t *)p_buf + sizeof(data_buffer_t),
543                          p_input->p_current_data, (size_t)i_remains );
544         }
545         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
546     }
547
548     /* Do not hold the lock during pf_read (blocking call). */
549     vlc_mutex_unlock( &p_input->p_method_data->lock );
550
551     i_ret = p_input->pf_read( p_input,
552                              (byte_t *)p_buf + sizeof(data_buffer_t)
553                               + i_remains,
554                              p_input->i_bufsize );
555
556     if( i_ret < 0 ) i_ret = 0;
557     p_input->p_data_buffer = p_buf;
558     p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
559     p_input->p_last_data = p_input->p_current_data + i_remains + i_ret;
560
561     return( (ssize_t)i_remains + i_ret );
562 }
563
564 /*****************************************************************************
565  * input_Peek: give a pointer to the next available bytes in the buffer
566  *             (min. i_size bytes)
567  * Returns the number of bytes read, or -1 in case of error
568  *****************************************************************************/
569 ssize_t input_Peek( input_thread_t * p_input, byte_t ** pp_byte, size_t i_size )
570 {
571     if( p_input->p_last_data - p_input->p_current_data < i_size )
572     {
573         /* Go to the next buffer */
574         ssize_t i_ret = input_FillBuffer( p_input );
575
576         if( i_size == -1 )
577         {
578             return( -1 );
579         }
580         else if( i_ret < i_size )
581         {
582             i_size = i_ret;
583         }
584     }
585     *pp_byte = p_input->p_current_data;
586     return( i_size );
587 }
588
589 /*****************************************************************************
590  * input_SplitBuffer: give a pointer to a data packet containing i_size bytes
591  * Returns the number of bytes read, or -1 in case of error
592  *****************************************************************************/
593 ssize_t input_SplitBuffer( input_thread_t * p_input,
594                            data_packet_t ** pp_data, size_t i_size )
595 {
596     if( p_input->p_last_data - p_input->p_current_data < i_size )
597     {
598         /* Go to the next buffer */
599         ssize_t i_ret = input_FillBuffer( p_input );
600
601         if( i_ret == -1 )
602         {
603             return( -1 );
604         }
605         else if( i_ret < i_size )
606         {
607             i_size = i_ret;
608         }
609     }
610
611     *pp_data = input_ShareBuffer( p_input->p_method_data,
612                                   p_input->p_data_buffer );
613
614     (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
615         = p_input->p_current_data;
616     (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
617
618     p_input->p_current_data += i_size;
619
620     return( i_size );
621 }
622
623 /*****************************************************************************
624  * input_AccessInit: initialize access plug-in wrapper structures
625  *****************************************************************************/
626 int input_AccessInit( input_thread_t * p_input )
627 {
628     p_input->p_method_data = input_BuffersInit();
629     if( p_input->p_method_data == NULL ) return( -1 );
630     p_input->p_data_buffer = NULL;
631     p_input->p_current_data = NULL;
632     p_input->p_last_data = NULL;
633     return( 0 );
634 }
635
636 /*****************************************************************************
637  * input_AccessReinit: reinit structures after a random seek
638  *****************************************************************************/
639 void input_AccessReinit( input_thread_t * p_input )
640 {
641     if( p_input->p_data_buffer != NULL )
642     {
643         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
644     }
645     p_input->p_data_buffer = NULL;
646     p_input->p_current_data = NULL;
647     p_input->p_last_data = NULL;
648 }
649
650 /*****************************************************************************
651  * input_AccessEnd: free access plug-in wrapper structures
652  *****************************************************************************/
653 void input_AccessEnd( input_thread_t * p_input )
654 {
655     if( p_input->p_data_buffer != NULL )
656     {
657         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
658     }
659
660     input_BuffersEnd( p_input->p_method_data );
661 }
662
663
664 /*
665  * Optional file descriptor management functions, for use by access plug-ins
666  * base on file descriptors (file, udp, http...).
667  */
668
669 /*****************************************************************************
670  * input_FDClose: close the target
671  *****************************************************************************/
672 void input_FDClose( input_thread_t * p_input )
673 {
674     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
675
676     intf_WarnMsg( 2, "input: closing `%s/%s:%s'", 
677                   p_input->psz_access, p_input->psz_demux, p_input->psz_name );
678  
679     close( p_access_data->i_handle );
680     free( p_access_data );
681 }
682
683 /*****************************************************************************
684  * input_FDRead: standard read on a file descriptor.
685  *****************************************************************************/
686 ssize_t input_FDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
687 {
688     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
689  
690     ssize_t i_ret = read( p_access_data->i_handle, p_buffer, i_len );
691  
692     if( i_ret > 0 )
693     {
694         vlc_mutex_lock( &p_input->stream.stream_lock );
695         p_input->stream.p_selected_area->i_tell += i_ret;
696         vlc_mutex_unlock( &p_input->stream.stream_lock );
697     }
698  
699     if( i_ret < 0 )
700     {
701         intf_ErrMsg( "input error: read() failed (%s)", strerror(errno) );
702     }
703  
704     return( i_ret );
705 }
706
707 /*****************************************************************************
708  * NetworkSelect: Checks whether data is available on a file descriptor
709  *****************************************************************************/
710 static __inline__ int NetworkSelect( input_thread_t * p_input )
711 {
712     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
713     struct timeval  timeout;
714     fd_set          fds;
715     int             i_ret;
716
717     /* Initialize file descriptor set */
718     FD_ZERO( &fds );
719     FD_SET( p_access_data->i_handle, &fds );
720
721     /* We'll wait 0.5 second if nothing happens */
722     timeout.tv_sec = 0;
723     timeout.tv_usec = 500000;
724  
725     /* Find if some data is available */
726     i_ret = select( p_access_data->i_handle + 1, &fds,
727                      NULL, NULL, &timeout );
728  
729     if( i_ret == -1 )
730     {
731         intf_ErrMsg( "input error: network select error (%s)", strerror(errno) );
732     }
733
734     return( i_ret );
735 }
736
737 /*****************************************************************************
738  * input_FDNetworkRead: read on a file descriptor, checking periodically
739  * p_input->b_die
740  *****************************************************************************/
741 ssize_t input_FDNetworkRead( input_thread_t * p_input, byte_t * p_buffer,
742                              size_t i_len )
743 {
744     if( NetworkSelect( p_input ) > 0 )
745     {
746         input_socket_t * p_access_data
747                              = (input_socket_t *)p_input->p_access_data;
748
749         ssize_t i_ret = recv( p_access_data->i_handle, p_buffer, i_len, 0 );
750
751         if( i_ret > 0 )
752         {
753             vlc_mutex_lock( &p_input->stream.stream_lock );
754             p_input->stream.p_selected_area->i_tell += i_ret;
755             vlc_mutex_unlock( &p_input->stream.stream_lock );
756         }
757
758         if( i_ret < 0 )
759         {
760             intf_ErrMsg( "input error: recv() failed (%s)", strerror(errno) );
761         }
762
763         return( i_ret );
764     }
765     
766     return( 0 );
767 }
768
769 /*****************************************************************************
770  * input_FDSeek: seek to a specific location in a file
771  *****************************************************************************/
772 void input_FDSeek( input_thread_t * p_input, off_t i_pos )
773 {
774     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
775
776     lseek( p_access_data->i_handle, i_pos, SEEK_SET );
777
778     vlc_mutex_lock( &p_input->stream.stream_lock );
779     p_input->stream.p_selected_area->i_tell = i_pos;
780     vlc_mutex_unlock( &p_input->stream.stream_lock );
781 }
782
783