]> git.sesse.net Git - vlc/blob - src/input/stream.c
* src/input/demux.c, src/misc/objects.c: demux2 has the VLC_OBJECT_DEMUX type.
[vlc] / src / input / stream.c
1 /*****************************************************************************
2  * stream.c
3  *****************************************************************************
4  * Copyright (C) 1999-2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@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 #include <stdlib.h>
25 #include <vlc/vlc.h>
26 #include <vlc/input.h>
27
28 #include "ninput.h"
29
30 /****************************************************************************
31  * stream_ReadLine:
32  ****************************************************************************/
33 /**
34  * Read from the stream untill first newline.
35  * \param s Stream handle to read from
36  * \return A null-terminated string. This must be freed,
37  */
38 /* FIXME don't use stupid MAX_LINE -> do the same than net_ReadLine */
39 #define MAX_LINE 1024
40 char *stream_ReadLine( stream_t *s )
41 {
42     uint8_t *p_data;
43     char    *p_line;
44     int      i_data;
45     int      i = 0;
46     i_data = stream_Peek( s, &p_data, MAX_LINE );
47
48     while( i < i_data && p_data[i] != '\n' )
49     {
50         i++;
51     }
52     if( i_data <= 0 )
53     {
54         return NULL;
55     }
56     else
57     {
58         p_line = malloc( i + 1 );
59         if( p_line == NULL )
60         {
61             msg_Err( s, "out of memory" );
62             return NULL;
63         }
64         i = stream_Read( s, p_line, i + 1 );
65         p_line[ i - 1 ] = '\0';
66
67         return p_line;
68     }
69 }
70
71
72
73 /* TODO: one day we should create a special module stream
74  * when we would have a access wrapper, and stream filter
75  * (like caching, progessive, gunzip, ... )
76  */
77
78 /* private stream_sys_t for input_Stream* */
79 typedef struct
80 {
81     input_thread_t *p_input;
82 } input_stream_sys_t;
83
84 /* private pf_* functions declarations */
85 static int      IStreamRead   ( stream_t *, void *p_read, int i_read );
86 static int      IStreamPeek   ( stream_t *, uint8_t **pp_peek, int i_peek );
87 static int      IStreamControl( stream_t *, int i_query, va_list );
88
89 /****************************************************************************
90  * input_StreamNew: create a wrapper for p_input access
91  ****************************************************************************/
92 stream_t *input_StreamNew( input_thread_t *p_input )
93 {
94     stream_t *s = vlc_object_create( p_input, sizeof( stream_t ) );
95     input_stream_sys_t *p_sys;
96     if( s )
97     {
98         s->pf_block  = NULL;
99         s->pf_read   = IStreamRead;
100         s->pf_peek   = IStreamPeek;
101         s->pf_control= IStreamControl;
102
103         s->p_sys = malloc( sizeof( input_stream_sys_t ) );
104         p_sys = (input_stream_sys_t*)s->p_sys;
105         p_sys->p_input = p_input;
106     }
107     return s;
108 }
109
110 /****************************************************************************
111  * input_StreamDelete:
112  ****************************************************************************/
113 void input_StreamDelete( stream_t *s )
114 {
115     free( s->p_sys );
116     vlc_object_destroy( s );
117 }
118
119
120 /****************************************************************************
121  * IStreamControl:
122  ****************************************************************************/
123 static int IStreamControl( stream_t *s, int i_query, va_list args )
124 {
125     input_stream_sys_t * p_sys = (input_stream_sys_t*)s->p_sys;
126     input_thread_t *p_input = p_sys->p_input;
127
128     vlc_bool_t *p_b;
129     int64_t    *p_i64, i64;
130     int        *p_int;
131
132     switch( i_query )
133     {
134         case STREAM_GET_SIZE:
135             p_i64 = (int64_t*) va_arg( args, int64_t * );
136
137             vlc_mutex_lock( &p_input->stream.stream_lock );
138             *p_i64 = p_input->stream.p_selected_area->i_size;
139             vlc_mutex_unlock( &p_input->stream.stream_lock );
140             return VLC_SUCCESS;
141
142         case STREAM_CAN_SEEK:
143             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
144
145             vlc_mutex_lock( &p_input->stream.stream_lock );
146             *p_b = p_input->stream.b_seekable;
147             vlc_mutex_unlock( &p_input->stream.stream_lock );
148             return VLC_SUCCESS;
149
150         case STREAM_CAN_FASTSEEK:
151             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
152
153             vlc_mutex_lock( &p_input->stream.stream_lock );
154             *p_b = p_input->stream.b_seekable &&
155                    p_input->stream.i_method == INPUT_METHOD_FILE;
156             vlc_mutex_unlock( &p_input->stream.stream_lock );
157             return VLC_SUCCESS;
158
159         case STREAM_GET_POSITION:
160             p_i64 = (int64_t*) va_arg( args, int64_t * );
161
162             vlc_mutex_lock( &p_input->stream.stream_lock );
163             *p_i64 = p_input->stream.p_selected_area->i_tell;
164             vlc_mutex_unlock( &p_input->stream.stream_lock );
165             return VLC_SUCCESS;
166
167         case STREAM_SET_POSITION:
168         {
169             int64_t i_skip;
170             i64 = (int64_t) va_arg( args, int64_t );
171
172             vlc_mutex_lock( &p_input->stream.stream_lock );
173             if( i64 < 0 ||
174                 ( p_input->stream.p_selected_area->i_size > 0 &&
175                   p_input->stream.p_selected_area->i_size < i64 ) )
176             {
177                 vlc_mutex_unlock( &p_input->stream.stream_lock );
178                 msg_Warn( s, "seek out of bound" );
179                 return VLC_EGENERIC;
180             }
181
182             i_skip = i64 - p_input->stream.p_selected_area->i_tell;
183
184             if( i_skip == 0 )
185             {
186                 vlc_mutex_unlock( &p_input->stream.stream_lock );
187                 return VLC_SUCCESS;
188             }
189
190             if( i_skip > 0 && i_skip < p_input->p_last_data -
191                             p_input->p_current_data - 1 )
192             {
193                 /* We can skip without reading/seeking */
194                 p_input->p_current_data += i_skip;
195                 p_input->stream.p_selected_area->i_tell = i64;
196                 vlc_mutex_unlock( &p_input->stream.stream_lock );
197                 return VLC_SUCCESS;
198             }
199             vlc_mutex_unlock( &p_input->stream.stream_lock );
200
201             if( p_input->stream.b_seekable &&
202                 ( p_input->stream.i_method == INPUT_METHOD_FILE ||
203                   i_skip < 0 || i_skip >= ( p_input->i_mtu > 0 ?
204                                             p_input->i_mtu : 4096 ) ) )
205             {
206                 input_AccessReinit( p_input );
207                 p_input->pf_seek( p_input, i64 );
208                 return VLC_SUCCESS;
209             }
210
211             if( i_skip > 0 )
212             {
213                 data_packet_t *p_data;
214
215                 if( i_skip > 1000 )
216                 {
217                     msg_Warn( s, "will skip "I64Fd" bytes, slow", i_skip );
218                 }
219
220                 while( i_skip > 0 )
221                 {
222                     int i_read;
223
224                     i_read = input_SplitBuffer( p_input, &p_data,
225                                  __MIN( (int)p_input->i_bufsize, i_skip ) );
226                     if( i_read < 0 )
227                     {
228                         return VLC_EGENERIC;
229                     }
230                     i_skip -= i_read;
231
232                     input_DeletePacket( p_input->p_method_data, p_data );
233                     if( i_read == 0 && i_skip > 0 )
234                     {
235                         return VLC_EGENERIC;
236                     }
237                 }
238             }
239             return VLC_SUCCESS;
240         }
241
242         case STREAM_GET_MTU:
243             p_int = (int*) va_arg( args, int * );
244             *p_int = p_input->i_mtu;
245             return VLC_SUCCESS;
246
247         default:
248             msg_Err( s, "invalid stream_vaControl query=0x%x", i_query );
249             return VLC_EGENERIC;
250     }
251 }
252
253 /****************************************************************************
254  * IStreamRead:
255  ****************************************************************************/
256 static int IStreamRead( stream_t *s, void *p_data, int i_data )
257 {
258     input_stream_sys_t * p_sys = (input_stream_sys_t*)s->p_sys;
259     input_thread_t *p_input = p_sys->p_input;
260     uint8_t *p = (uint8_t*)p_data;
261
262     int i_read = 0;
263
264     if( p_data == NULL && i_data > 0 )
265     {
266         int64_t i_pos;
267
268         stream_Control( s, STREAM_GET_POSITION, &i_pos );
269
270         i_pos += i_data;
271         if( stream_Control( s, STREAM_SET_POSITION, i_pos ) )
272         {
273             return 0;
274         }
275         return i_data;
276     }
277
278     while( i_data > 0 && !p_input->b_die )
279     {
280         ssize_t i_count = p_input->p_last_data - p_input->p_current_data;
281
282         if( i_count <= 0 )
283         {
284             /* Go to the next buffer */
285             i_count = input_FillBuffer( p_input );
286
287             if( i_count < 0 ) return -1;
288             else if( i_count == 0 )
289             {
290                 /* We reached the EOF */
291                 break;
292             }
293         }
294
295         i_count = __MIN( i_data, i_count );
296         memcpy( p, p_input->p_current_data, i_count );
297         p_input->p_current_data += i_count;
298         p += i_count;
299         i_data -= i_count;
300         i_read += i_count;
301
302         /* Update stream position */
303         vlc_mutex_lock( &p_input->stream.stream_lock );
304         p_input->stream.p_selected_area->i_tell += i_count;
305         vlc_mutex_unlock( &p_input->stream.stream_lock );
306     }
307
308     return i_read;
309 }
310
311 /****************************************************************************
312  * IStreamPeek:
313  ****************************************************************************/
314 static int IStreamPeek( stream_t *s, uint8_t **pp_peek, int i_peek )
315 {
316     input_stream_sys_t * p_sys = (input_stream_sys_t*)s->p_sys;
317     return input_Peek( p_sys->p_input, pp_peek, i_peek );
318 }
319
320 /****************************************************************************
321  * stream_Demux*: create a demuxer for an outpout stream (allow demuxer chain)
322  ****************************************************************************/
323 typedef struct
324 {
325     /* Data buffer */
326     vlc_mutex_t lock;
327     int         i_buffer;
328     int         i_buffer_size;
329     uint8_t     *p_buffer;
330
331     int64_t     i_pos;
332
333     /* Demuxer */
334     char        *psz_name;
335     es_out_t    *out;
336     demux_t     *p_demux;
337 } d_stream_sys_t;
338
339 static int DStreamRead   ( stream_t *, void *p_read, int i_read );
340 static int DStreamPeek   ( stream_t *, uint8_t **pp_peek, int i_peek );
341 static int DStreamControl( stream_t *, int i_query, va_list );
342 static int DStreamThread ( stream_t * );
343
344
345 stream_t *__stream_DemuxNew( vlc_object_t *p_obj, char *psz_demux, es_out_t *out )
346 {
347     /* We create a stream reader, and launch a thread */
348     stream_t       *s;
349     d_stream_sys_t *p_sys;
350
351     if( psz_demux == NULL || *psz_demux == '\0' )
352     {
353         return NULL;
354     }
355
356     s = vlc_object_create( p_obj, sizeof( stream_t ) );
357     s->pf_block  = NULL;
358     s->pf_read   = DStreamRead;
359     s->pf_peek   = DStreamPeek;
360     s->pf_control= DStreamControl;
361
362     s->p_sys = malloc( sizeof( d_stream_sys_t) );
363     p_sys = (d_stream_sys_t*)s->p_sys;
364
365     vlc_mutex_init( s, &p_sys->lock );
366     p_sys->i_buffer = 0;
367     p_sys->i_buffer_size = 1000000;
368     p_sys->p_buffer = malloc( p_sys->i_buffer_size );
369     p_sys->i_pos = 0;
370     p_sys->psz_name = strdup( psz_demux );
371     p_sys->out = out;
372     p_sys->p_demux = NULL;
373
374     if( vlc_thread_create( s, "stream out", DStreamThread, VLC_THREAD_PRIORITY_INPUT, VLC_FALSE ) )
375     {
376         vlc_mutex_destroy( &p_sys->lock );
377         vlc_object_destroy( s );
378         free( p_sys );
379         return NULL;
380     }
381
382     return s;
383 }
384
385 void     stream_DemuxSend( stream_t *s, block_t *p_block )
386 {
387     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
388
389     if( p_block->i_buffer > 0 )
390     {
391         vlc_mutex_lock( &p_sys->lock );
392         /* Realloc if needed */
393         if( p_sys->i_buffer + p_block->i_buffer > p_sys->i_buffer_size )
394         {
395             if( p_sys->i_buffer_size > 5000000 )
396             {
397                 vlc_mutex_unlock( &p_sys->lock );
398                 msg_Err( s, "stream_DemuxSend: buffer size > 5000000" );
399                 block_Release( p_block );
400                 return;
401             }
402             /* I know, it's more than needed but that's perfect */
403             p_sys->i_buffer_size += p_block->i_buffer;
404             /* FIXME won't work with PEEK -> segfault */
405             p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size );
406             msg_Dbg( s, "stream_DemuxSend: realloc to %d", p_sys->i_buffer_size );
407         }
408
409         /* copy data */
410         memcpy( &p_sys->p_buffer[p_sys->i_buffer], p_block->p_buffer, p_block->i_buffer );
411         p_sys->i_buffer += p_block->i_buffer;
412
413         vlc_mutex_unlock( &p_sys->lock );
414     }
415
416     block_Release( p_block );
417 }
418
419 void     stream_DemuxDelete( stream_t *s )
420 {
421     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
422
423     s->b_die = VLC_TRUE;
424
425     vlc_mutex_lock( &p_sys->lock );
426     if( p_sys->p_demux )
427     {
428         p_sys->p_demux->b_die = VLC_TRUE;
429     }
430     vlc_mutex_unlock( &p_sys->lock );
431
432     vlc_thread_join( s );
433
434     if( p_sys->p_demux )
435     {
436         demux2_Delete( p_sys->p_demux );
437     }
438     vlc_mutex_destroy( &p_sys->lock );
439     free( p_sys->psz_name );
440     free( p_sys->p_buffer );
441     free( p_sys );
442     vlc_object_destroy( s );
443 }
444
445
446 static int      DStreamRead   ( stream_t *s, void *p_read, int i_read )
447 {
448     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
449     int           i_copy;
450
451     //msg_Dbg( s, "DStreamRead: wanted %d bytes", i_read );
452     for( ;; )
453     {
454         vlc_mutex_lock( &p_sys->lock );
455         //msg_Dbg( s, "DStreamRead: buffer %d", p_sys->i_buffer );
456         if( p_sys->i_buffer >= i_read || s->b_die )
457         {
458             break;
459         }
460         vlc_mutex_unlock( &p_sys->lock );
461         msleep( 10000 );
462     }
463
464     //msg_Dbg( s, "DStreamRead: read %d buffer %d", i_read, p_sys->i_buffer );
465
466     i_copy = __MIN( i_read, p_sys->i_buffer );
467     if( i_copy > 0 )
468     {
469         if( p_read )
470         {
471             memcpy( p_read, p_sys->p_buffer, i_copy );
472         }
473         p_sys->i_buffer -= i_copy;
474         p_sys->i_pos += i_copy;
475
476         if( p_sys->i_buffer > 0 )
477         {
478             memmove( p_sys->p_buffer, &p_sys->p_buffer[i_copy], p_sys->i_buffer );
479         }
480
481     }
482     vlc_mutex_unlock( &p_sys->lock );
483
484     return i_copy;
485 }
486 static int      DStreamPeek   ( stream_t *s, uint8_t **pp_peek, int i_peek )
487 {
488     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
489     int           i_copy;
490
491     //msg_Dbg( s, "DStreamPeek: wanted %d bytes", i_peek );
492     for( ;; )
493     {
494         vlc_mutex_lock( &p_sys->lock );
495         //msg_Dbg( s, "DStreamPeek: buffer %d", p_sys->i_buffer );
496         if( p_sys->i_buffer >= i_peek || s->b_die )
497         {
498             break;
499         }
500         vlc_mutex_unlock( &p_sys->lock );
501         msleep( 10000 );
502     }
503     *pp_peek = p_sys->p_buffer;
504     i_copy = __MIN( i_peek, p_sys->i_buffer );
505
506     vlc_mutex_unlock( &p_sys->lock );
507
508     return i_copy;
509 }
510
511 static int      DStreamControl( stream_t *s, int i_query, va_list args )
512 {
513     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
514     int64_t    *p_i64;
515     vlc_bool_t *p_b;
516     int        *p_int;
517     switch( i_query )
518     {
519         case STREAM_GET_SIZE:
520             p_i64 = (int64_t*) va_arg( args, int64_t * );
521             *p_i64 = 0;
522             return VLC_SUCCESS;
523
524         case STREAM_CAN_SEEK:
525             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
526             *p_b = VLC_FALSE;
527             return VLC_SUCCESS;
528
529         case STREAM_CAN_FASTSEEK:
530             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
531             *p_b = VLC_FALSE;
532             return VLC_SUCCESS;
533
534         case STREAM_GET_POSITION:
535             p_i64 = (int64_t*) va_arg( args, int64_t * );
536             *p_i64 = p_sys->i_pos;
537             return VLC_SUCCESS;
538
539         case STREAM_SET_POSITION:
540             return VLC_EGENERIC;
541
542         case STREAM_GET_MTU:
543             p_int = (int*) va_arg( args, int * );
544             *p_int = 0;
545             return VLC_SUCCESS;
546
547         default:
548             msg_Err( s, "invalid DStreamControl query=0x%x", i_query );
549             return VLC_EGENERIC;
550     }
551 }
552
553 static int      DStreamThread ( stream_t *s )
554 {
555     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
556     char         *psz_mrl;
557     demux_t      *p_demux;
558
559     /* Create the demuxer */
560
561     psz_mrl = malloc( strlen( p_sys->psz_name ) + 3 );
562     sprintf( psz_mrl, "/%s:", p_sys->psz_name );
563
564     if( ( p_demux = demux2_New( s, psz_mrl, s, p_sys->out ) ) == NULL )
565     {
566         free( psz_mrl );
567         return VLC_EGENERIC;
568     }
569     free( psz_mrl );
570
571     vlc_mutex_lock( &p_sys->lock );
572     p_sys->p_demux = p_demux;
573     vlc_mutex_unlock( &p_sys->lock );
574
575     /* Main loop */
576     while( !s->b_die && !p_demux->b_die )
577     {
578         if( p_demux->pf_demux( p_demux ) <= 0 )
579         {
580             break;
581         }
582     }
583     p_demux->b_die = VLC_TRUE;
584     return VLC_SUCCESS;
585 }
586
587
588
589
590