]> git.sesse.net Git - vlc/blob - src/input/input_ext-plugins.c
* ALL: WinCE compilation fixes (mostly nonexistent headers). A lot of
[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.20 2002/11/10 18:04:23 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 #include <string.h>
29
30 #include <vlc/vlc.h>
31
32 #ifdef HAVE_SYS_STAT_H
33 #   include <sys/stat.h>
34 #endif
35
36 #ifdef HAVE_ERRNO_H
37 #   include <errno.h>
38 #endif
39
40 #ifdef HAVE_FCNTL_H
41 #   include <fcntl.h>
42 #endif
43
44 #ifdef HAVE_SYS_TIME_H
45 #    include <sys/time.h>
46 #endif
47
48 #ifdef HAVE_UNISTD_H
49 #   include <unistd.h>
50 #elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE )
51 #   include <io.h>
52 #endif
53
54 #ifdef UNDER_CE
55     /* No network support */
56 #elif defined( WIN32 )
57 #   include <winsock2.h>
58 #   include <ws2tcpip.h>
59 #elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
60 #   include <sys/types.h>
61 #   include <sys/socket.h>                                         /* recv() */
62 #endif
63
64 #include "stream_control.h"
65 #include "input_ext-intf.h"
66 #include "input_ext-dec.h"
67 #include "input_ext-plugins.h"
68
69
70 /*
71  * Buffers management : internal functions
72  *
73  * All functions are static, but exported versions with mutex protection
74  * start with input_*. Not all of these exported functions are actually used,
75  * but they are included here for completeness.
76  */
77
78 #define BUFFERS_CACHE_SIZE 500
79 #define DATA_CACHE_SIZE 1000
80 #define PES_CACHE_SIZE 1000
81
82 /*****************************************************************************
83  * data_buffer_t: shared data type
84  *****************************************************************************/
85 struct data_buffer_t
86 {
87     data_buffer_t * p_next;
88
89     /* number of data packets this buffer is referenced from - when it falls
90      * down to 0, the buffer is freed */
91     int i_refcount;
92
93     /* size of the current buffer (starting right after this byte) */
94     size_t i_size;
95 };
96
97 /*****************************************************************************
98  * input_buffers_t: defines a LIFO per data type to keep
99  *****************************************************************************/
100 #define PACKETS_LIFO( TYPE, NAME )                                          \
101 struct                                                                      \
102 {                                                                           \
103     TYPE * p_stack;                                                         \
104     unsigned int i_depth;                                                   \
105 } NAME;
106
107 struct input_buffers_t
108 {
109     vlc_mutex_t lock;
110     PACKETS_LIFO( pes_packet_t, pes )
111     PACKETS_LIFO( data_packet_t, data )
112     PACKETS_LIFO( data_buffer_t, buffers )
113     size_t i_allocated;
114 };
115
116
117 /*****************************************************************************
118  * input_BuffersInit: initialize the cache structures, return a pointer to it
119  *****************************************************************************/
120 void * __input_BuffersInit( vlc_object_t *p_this )
121 {
122     input_buffers_t * p_buffers = malloc( sizeof( input_buffers_t ) );
123
124     if( p_buffers == NULL )
125     {
126         return NULL;
127     }
128
129     memset( p_buffers, 0, sizeof( input_buffers_t ) );
130     vlc_mutex_init( p_this, &p_buffers->lock );
131
132     return p_buffers;
133 }
134
135 /*****************************************************************************
136  * input_BuffersEnd: free all cached structures
137  *****************************************************************************/
138 #define BUFFERS_END_PACKETS_LOOP                                            \
139     while( p_packet != NULL )                                               \
140     {                                                                       \
141         p_next = p_packet->p_next;                                          \
142         free( p_packet );                                                   \
143         p_packet = p_next;                                                  \
144     }
145
146 void input_BuffersEnd( input_thread_t * p_input, input_buffers_t * p_buffers )
147 {
148     if( p_buffers != NULL )
149     {
150         msg_Dbg( p_input, "pes: %d packets", p_buffers->pes.i_depth );
151         msg_Dbg( p_input, "data: %d packets", p_buffers->data.i_depth );
152         msg_Dbg( p_input, "buffers: %d packets", p_buffers->buffers.i_depth );
153
154         {
155             /* Free PES */
156             pes_packet_t * p_next, * p_packet = p_buffers->pes.p_stack;
157             BUFFERS_END_PACKETS_LOOP;
158         }
159
160         {
161             /* Free data packets */
162             data_packet_t * p_next, * p_packet = p_buffers->data.p_stack;
163             BUFFERS_END_PACKETS_LOOP;
164         }
165
166         {
167             /* Free buffers */
168             data_buffer_t * p_next, * p_buf = p_buffers->buffers.p_stack;
169             while( p_buf != NULL )
170             {
171                 p_next = p_buf->p_next;
172                 p_buffers->i_allocated -= p_buf->i_size;
173                 free( p_buf );
174                 p_buf = p_next;
175             }
176         } 
177
178         if( p_buffers->i_allocated )
179         {
180             msg_Err( p_input, "%d bytes have not been freed, "
181                               "expect memory leak", p_buffers->i_allocated );
182         }
183
184         vlc_mutex_destroy( &p_buffers->lock );
185         free( p_buffers );
186     }
187 }
188
189 /*****************************************************************************
190  * input_NewBuffer: return a pointer to a data buffer of the appropriate size
191  *****************************************************************************/
192 static inline data_buffer_t * NewBuffer( input_buffers_t * p_buffers,
193                                          size_t i_size )
194 {
195     data_buffer_t * p_buf;
196
197     /* Safety check */
198     if( p_buffers->i_allocated > INPUT_MAX_ALLOCATION )
199     {
200         return NULL;
201     } 
202
203     if( p_buffers->buffers.p_stack != NULL )
204     {
205         /* Take the buffer from the cache */
206         p_buf = p_buffers->buffers.p_stack;
207         p_buffers->buffers.p_stack = p_buf->p_next;
208         p_buffers->buffers.i_depth--;
209
210         /* Reallocate the packet if it is too small or too large */
211         if( p_buf->i_size < i_size || p_buf->i_size > 3 * i_size )
212         {
213             p_buffers->i_allocated -= p_buf->i_size;
214             free( p_buf );
215             p_buf = malloc( sizeof(input_buffers_t) + i_size );
216             if( p_buf == NULL )
217             {
218                 return NULL;
219             }
220             p_buf->i_size = i_size;
221             p_buffers->i_allocated += i_size;
222         }
223     }
224     else
225     {
226         /* Allocate a new buffer */
227         p_buf = malloc( sizeof(input_buffers_t) + i_size );
228         if( p_buf == NULL )
229         {
230             return NULL;
231         }
232         p_buf->i_size = i_size;
233         p_buffers->i_allocated += i_size;
234     }
235
236     /* Initialize data */
237     p_buf->p_next = NULL;
238     p_buf->i_refcount = 0;
239
240     return p_buf;
241 }
242
243 data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
244 {
245     data_buffer_t * p_buf;
246
247     vlc_mutex_lock( &p_buffers->lock );
248     p_buf = NewBuffer( p_buffers, i_size );
249     vlc_mutex_unlock( &p_buffers->lock );
250
251     return p_buf;
252 }
253
254 /*****************************************************************************
255  * input_ReleaseBuffer: put a buffer back into the cache
256  *****************************************************************************/
257 static inline void ReleaseBuffer( input_buffers_t * p_buffers,
258                                   data_buffer_t * p_buf )
259 {
260     /* Decrement refcount */
261     if( --p_buf->i_refcount > 0 )
262     {
263         return;
264     }
265
266     if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
267     {
268         /* Cache not full : store the buffer in it */
269         p_buf->p_next = p_buffers->buffers.p_stack;
270         p_buffers->buffers.p_stack = p_buf;
271         p_buffers->buffers.i_depth++;
272     }
273     else
274     {
275         p_buffers->i_allocated -= p_buf->i_size;
276         free( p_buf );
277     }
278 }
279
280 void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
281 {
282     vlc_mutex_lock( &p_buffers->lock );
283     ReleaseBuffer( p_buffers, p_buf );
284     vlc_mutex_unlock( &p_buffers->lock );
285 }
286
287 /*****************************************************************************
288  * input_ShareBuffer: allocate a data_packet_t pointing to a given buffer
289  *****************************************************************************/
290 static inline data_packet_t * ShareBuffer( input_buffers_t * p_buffers,
291                                            data_buffer_t * p_buf )
292 {
293     data_packet_t * p_data;
294
295     if( p_buffers->data.p_stack != NULL )
296     {
297         /* Take the packet from the cache */
298         p_data = p_buffers->data.p_stack;
299         p_buffers->data.p_stack = p_data->p_next;
300         p_buffers->data.i_depth--;
301     }
302     else
303     {
304         /* Allocate a new packet */
305         p_data = malloc( sizeof(data_packet_t) );
306         if( p_data == NULL )
307         {
308             return NULL;
309         }
310     }
311
312     p_data->p_buffer = p_buf;
313     p_data->p_next = NULL;
314     p_data->b_discard_payload = 0;
315     p_data->p_payload_start = p_data->p_demux_start
316                             = (byte_t *)p_buf + sizeof(input_buffers_t);
317     p_data->p_payload_end = p_data->p_demux_start + p_buf->i_size;
318     p_buf->i_refcount++;
319
320     return p_data;
321 }
322
323 data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
324                                    data_buffer_t * p_buf )
325 {
326     data_packet_t * p_data;
327
328     vlc_mutex_lock( &p_buffers->lock );
329     p_data = ShareBuffer( p_buffers, p_buf );
330     vlc_mutex_unlock( &p_buffers->lock );
331
332     return p_data;
333 }
334
335 /*****************************************************************************
336  * input_NewPacket: allocate a packet along with a buffer
337  *****************************************************************************/
338 static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
339                                          size_t i_size )
340 {
341     data_buffer_t * p_buf;
342     data_packet_t * p_data;
343
344     p_buf = NewBuffer( p_buffers, i_size );
345
346     if( p_buf == NULL )
347     {
348         return NULL;
349     }
350
351     p_data = ShareBuffer( p_buffers, p_buf );
352     if( p_data == NULL )
353     {
354         ReleaseBuffer( p_buffers, p_buf );
355     }
356     return p_data;
357 }
358
359 data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
360 {
361     data_packet_t * p_data;
362
363     vlc_mutex_lock( &p_buffers->lock );
364     p_data = NewPacket( p_buffers, i_size );
365     vlc_mutex_unlock( &p_buffers->lock );
366
367     return p_data;
368 }
369
370 /*****************************************************************************
371  * input_DeletePacket: deallocate a packet and its buffers
372  *****************************************************************************/
373 static inline void DeletePacket( input_buffers_t * p_buffers,
374                                  data_packet_t * p_data )
375 {
376     while( p_data != NULL )
377     {
378         data_packet_t * p_next = p_data->p_next;
379
380         ReleaseBuffer( p_buffers, p_data->p_buffer );
381
382         if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
383         {
384             /* Cache not full : store the packet in it */
385             p_data->p_next = p_buffers->data.p_stack;
386             p_buffers->data.p_stack = p_data;
387             p_buffers->data.i_depth++;
388         }
389         else
390         {
391             free( p_data );
392         }
393
394         p_data = p_next;
395     }
396 }
397
398 void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
399 {
400     vlc_mutex_lock( &p_buffers->lock );
401     DeletePacket( p_buffers, p_data );
402     vlc_mutex_unlock( &p_buffers->lock );
403 }
404
405 /*****************************************************************************
406  * input_NewPES: return a pointer to a new PES packet
407  *****************************************************************************/
408 static inline pes_packet_t * NewPES( input_buffers_t * p_buffers )
409 {
410     pes_packet_t * p_pes;
411
412     if( p_buffers->pes.p_stack != NULL )
413     {
414         /* Take the packet from the cache */
415         p_pes = p_buffers->pes.p_stack;
416         p_buffers->pes.p_stack = p_pes->p_next;
417         p_buffers->pes.i_depth--;
418     }
419     else
420     {
421         /* Allocate a new packet */
422         p_pes = malloc( sizeof(pes_packet_t) );
423         if( p_pes == NULL )
424         {
425             return NULL;
426         }
427     }
428
429     p_pes->p_next = NULL;
430     p_pes->b_data_alignment = p_pes->b_discontinuity =
431         p_pes->i_pts = p_pes->i_dts = 0;
432     p_pes->p_first = p_pes->p_last = NULL;
433     p_pes->i_pes_size = 0;
434     p_pes->i_nb_data = 0;
435
436     return p_pes;
437 }
438
439 pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
440 {
441     pes_packet_t * p_pes;
442
443     vlc_mutex_lock( &p_buffers->lock );
444     p_pes = NewPES( p_buffers );
445     vlc_mutex_unlock( &p_buffers->lock );
446
447     return p_pes;
448 }
449
450 /*****************************************************************************
451  * input_DeletePES: put a pes and all data packets and all buffers back into
452  *                  the cache
453  *****************************************************************************/
454 static inline void DeletePES( input_buffers_t * p_buffers,
455                               pes_packet_t * p_pes )
456 {
457     while( p_pes != NULL )
458     {
459         pes_packet_t * p_next = p_pes->p_next;
460
461         /* Delete all data packets */
462         if( p_pes->p_first != NULL )
463         {
464             DeletePacket( p_buffers, p_pes->p_first );
465         }
466
467         if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
468         {
469             /* Cache not full : store the packet in it */
470             p_pes->p_next = p_buffers->pes.p_stack;
471             p_buffers->pes.p_stack = p_pes;
472             p_buffers->pes.i_depth++;
473         }
474         else
475         {
476             free( p_pes );
477         }
478
479         p_pes = p_next;
480     }
481 }
482
483 void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
484 {
485     vlc_mutex_lock( &p_buffers->lock );
486     DeletePES( p_buffers, p_pes );
487     vlc_mutex_unlock( &p_buffers->lock );
488 }
489
490
491 /*
492  * Buffers management : external functions
493  *
494  * These functions make the glu between the access plug-in (pf_read) and
495  * the demux plug-in (pf_demux). We fill in a large buffer (approx. 10s kB)
496  * with a call to pf_read, then allow the demux plug-in to have a peep at
497  * it (input_Peek), and to split it in data_packet_t (input_SplitBuffer).
498  */
499 /*****************************************************************************
500  * input_FillBuffer: fill in p_data_buffer with data from pf_read
501  *****************************************************************************/
502 ssize_t input_FillBuffer( input_thread_t * p_input )
503 {
504     ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
505     data_buffer_t * p_buf;
506     ssize_t i_ret;
507
508     vlc_mutex_lock( &p_input->p_method_data->lock );
509
510     p_buf = NewBuffer( p_input->p_method_data,
511                        i_remains + p_input->i_bufsize );
512     if( p_buf == NULL )
513     {
514         msg_Err( p_input, "failed allocating a new buffer (decoder stuck?)" );
515         return -1;
516     }
517     p_buf->i_refcount = 1;
518
519     if( p_input->p_data_buffer != NULL )
520     {
521         if( i_remains )
522         {
523             p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
524                                        p_input->p_current_data,
525                                        (size_t)i_remains );
526         }
527         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
528     }
529
530     /* Do not hold the lock during pf_read (blocking call). */
531     vlc_mutex_unlock( &p_input->p_method_data->lock );
532
533     i_ret = p_input->pf_read( p_input,
534                               (byte_t *)p_buf + sizeof(data_buffer_t)
535                                + i_remains,
536                               p_input->i_bufsize );
537     if( i_ret < 0 ) i_ret = 0;
538
539     p_input->p_data_buffer = p_buf;
540     p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
541     p_input->p_last_data = p_input->p_current_data + i_remains + i_ret;
542
543     return (ssize_t)i_remains + i_ret;
544 }
545
546 /*****************************************************************************
547  * input_Peek: give a pointer to the next available bytes in the buffer
548  *             (min. i_size bytes)
549  * Returns the number of bytes read, or -1 in case of error
550  *****************************************************************************/
551 ssize_t input_Peek( input_thread_t * p_input, byte_t ** pp_byte, size_t i_size )
552 {
553     if( p_input->p_last_data - p_input->p_current_data < i_size )
554     {
555         /* Go to the next buffer */
556         ssize_t i_ret = input_FillBuffer( p_input );
557
558         if( i_size == -1 )
559         {
560             return -1;
561         }
562         else if( i_ret < i_size )
563         {
564             i_size = i_ret;
565         }
566     }
567     *pp_byte = p_input->p_current_data;
568     return i_size;
569 }
570
571 /*****************************************************************************
572  * input_SplitBuffer: give a pointer to a data packet containing i_size bytes
573  * Returns the number of bytes read, or -1 in case of error
574  *****************************************************************************/
575 ssize_t input_SplitBuffer( input_thread_t * p_input,
576                            data_packet_t ** pp_data, size_t i_size )
577 {
578     if( p_input->p_last_data - p_input->p_current_data < i_size )
579     {
580         /* Go to the next buffer */
581         ssize_t i_ret = input_FillBuffer( p_input );
582
583         if( i_ret == -1 )
584         {
585             return -1;
586         }
587         else if( i_ret < i_size )
588         {
589             i_size = i_ret;
590         }
591     }
592
593     if ( !i_size )
594     {
595         return 0;
596     }
597
598     *pp_data = input_ShareBuffer( p_input->p_method_data,
599                                   p_input->p_data_buffer );
600
601     (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
602         = p_input->p_current_data;
603     (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
604
605     p_input->p_current_data += i_size;
606
607     /* Update stream position */
608     vlc_mutex_lock( &p_input->stream.stream_lock );
609     p_input->stream.p_selected_area->i_tell += i_size;
610     vlc_mutex_unlock( &p_input->stream.stream_lock );
611  
612     return i_size;
613 }
614
615 /*****************************************************************************
616  * input_AccessInit: initialize access plug-in wrapper structures
617  *****************************************************************************/
618 int input_AccessInit( input_thread_t * p_input )
619 {
620     p_input->p_method_data = input_BuffersInit( p_input );
621     if( p_input->p_method_data == NULL ) return -1;
622     p_input->p_data_buffer = NULL;
623     p_input->p_current_data = NULL;
624     p_input->p_last_data = NULL;
625     return 0;
626 }
627
628 /*****************************************************************************
629  * input_AccessReinit: reinit structures after a random seek
630  *****************************************************************************/
631 void input_AccessReinit( input_thread_t * p_input )
632 {
633     if( p_input->p_data_buffer != NULL )
634     {
635         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
636     }
637     p_input->p_data_buffer = NULL;
638     p_input->p_current_data = NULL;
639     p_input->p_last_data = NULL;
640 }
641
642 /*****************************************************************************
643  * input_AccessEnd: free access plug-in wrapper structures
644  *****************************************************************************/
645 void input_AccessEnd( input_thread_t * p_input )
646 {
647     if( p_input->p_data_buffer != NULL )
648     {
649         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
650     }
651
652     input_BuffersEnd( p_input, p_input->p_method_data );
653 }
654
655
656 /*
657  * Optional file descriptor management functions, for use by access plug-ins
658  * base on file descriptors (file, udp, http...).
659  */
660
661 /*****************************************************************************
662  * input_FDClose: close the target
663  *****************************************************************************/
664 void __input_FDClose( vlc_object_t * p_this )
665 {
666     input_thread_t * p_input = (input_thread_t *)p_this;
667     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
668
669     msg_Info( p_input, "closing `%s/%s://%s'", 
670               p_input->psz_access, p_input->psz_demux, p_input->psz_name );
671  
672     close( p_access_data->i_handle );
673     free( p_access_data );
674 }
675
676 /*****************************************************************************
677  * input_FDNetworkClose: close a network target
678  *****************************************************************************/
679 void __input_FDNetworkClose( vlc_object_t * p_this )
680 {
681     input_thread_t * p_input = (input_thread_t *)p_this;
682     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
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 #if defined( WIN32 ) && !defined( UNDER_CE )
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 #ifdef HAVE_ERRNO_H
708         msg_Err( p_input, "read failed (%s)", strerror(errno) );
709 #else
710         msg_Err( p_input, "read failed" );
711 #endif
712     }
713  
714     return i_ret;
715 }
716
717 /*****************************************************************************
718  * NetworkSelect: Checks whether data is available on a file descriptor
719  *****************************************************************************/
720 static inline int NetworkSelect( input_thread_t * p_input )
721 {
722 #ifdef UNDER_CE
723     return -1;
724
725 #else
726     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
727     struct timeval  timeout;
728     fd_set          fds;
729     int             i_ret;
730
731     /* Initialize file descriptor set */
732     FD_ZERO( &fds );
733     FD_SET( p_access_data->i_handle, &fds );
734
735     /* We'll wait 0.5 second if nothing happens */
736     timeout.tv_sec = 0;
737     timeout.tv_usec = 500000;
738  
739     /* Find if some data is available */
740     i_ret = select( p_access_data->i_handle + 1, &fds,
741                      NULL, NULL, &timeout );
742  
743     if( i_ret == -1 && errno != EINTR )
744     {
745         msg_Err( p_input, "network select error (%s)", strerror(errno) );
746     }
747
748     return i_ret;
749
750 #endif
751 }
752
753 /*****************************************************************************
754  * input_FDNetworkRead: read on a file descriptor, checking periodically
755  * p_input->b_die
756  *****************************************************************************/
757 ssize_t input_FDNetworkRead( input_thread_t * p_input, byte_t * p_buffer,
758                              size_t i_len )
759 {
760 #ifdef UNDER_CE
761     return -1;
762
763 #else
764     if( NetworkSelect( p_input ) > 0 )
765     {
766         input_socket_t * p_access_data
767                              = (input_socket_t *)p_input->p_access_data;
768
769         ssize_t i_ret = recv( p_access_data->i_handle, p_buffer, i_len, 0 );
770
771         if( i_ret > 0 )
772         {
773             vlc_mutex_lock( &p_input->stream.stream_lock );
774             p_input->stream.p_selected_area->i_tell += i_ret;
775             vlc_mutex_unlock( &p_input->stream.stream_lock );
776         }
777
778         if( i_ret < 0 )
779         {
780             msg_Err( p_input, "recv failed (%s)", strerror(errno) );
781         }
782
783         return i_ret;
784     }
785     
786     return 0;
787
788 #endif
789 }
790
791 /*****************************************************************************
792  * input_FDSeek: seek to a specific location in a file
793  *****************************************************************************/
794 void input_FDSeek( input_thread_t * p_input, off_t i_pos )
795 {
796 #define S p_input->stream
797     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
798
799     lseek( p_access_data->i_handle, i_pos, SEEK_SET );
800
801     vlc_mutex_lock( &S.stream_lock );
802     S.p_selected_area->i_tell = i_pos;
803     if( S.p_selected_area->i_tell > S.p_selected_area->i_size )
804     {
805         msg_Err( p_input, "seeking too far" );
806         S.p_selected_area->i_tell = S.p_selected_area->i_size;
807     }
808     else if( S.p_selected_area->i_tell < 0 )
809     {
810         msg_Err( p_input, "seeking too early" );
811         S.p_selected_area->i_tell = 0;
812     }
813     vlc_mutex_unlock( &S.stream_lock );
814 #undef S
815 }
816
817