1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 1999-2004 VideoLAN
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
26 #include <vlc/input.h>
30 /****************************************************************************
32 ****************************************************************************/
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,
38 /* FIXME don't use stupid MAX_LINE -> do the same than net_ReadLine */
40 char *stream_ReadLine( stream_t *s )
46 i_data = stream_Peek( s, &p_data, MAX_LINE );
48 while( i < i_data && p_data[i] != '\n' )
58 p_line = malloc( i + 1 );
61 msg_Err( s, "out of memory" );
64 i = stream_Read( s, p_line, i + 1 );
65 p_line[ i - 1 ] = '\0';
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, ... )
78 /* private stream_sys_t for input_Stream* */
81 input_thread_t *p_input;
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 );
89 /****************************************************************************
90 * input_StreamNew: create a wrapper for p_input access
91 ****************************************************************************/
92 stream_t *input_StreamNew( input_thread_t *p_input )
94 stream_t *s = vlc_object_create( p_input, sizeof( stream_t ) );
95 input_stream_sys_t *p_sys;
99 s->pf_read = IStreamRead;
100 s->pf_peek = IStreamPeek;
101 s->pf_control= IStreamControl;
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;
110 /****************************************************************************
111 * input_StreamDelete:
112 ****************************************************************************/
113 void input_StreamDelete( stream_t *s )
116 vlc_object_destroy( s );
120 /****************************************************************************
122 ****************************************************************************/
123 static int IStreamControl( stream_t *s, int i_query, va_list args )
125 input_stream_sys_t * p_sys = (input_stream_sys_t*)s->p_sys;
126 input_thread_t *p_input = p_sys->p_input;
134 case STREAM_GET_SIZE:
135 p_i64 = (int64_t*) va_arg( args, int64_t * );
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 );
142 case STREAM_CAN_SEEK:
143 p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
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 );
150 case STREAM_CAN_FASTSEEK:
151 p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
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 );
159 case STREAM_GET_POSITION:
160 p_i64 = (int64_t*) va_arg( args, int64_t * );
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 );
167 case STREAM_SET_POSITION:
170 i64 = (int64_t) va_arg( args, int64_t );
172 vlc_mutex_lock( &p_input->stream.stream_lock );
174 ( p_input->stream.p_selected_area->i_size > 0 &&
175 p_input->stream.p_selected_area->i_size < i64 ) )
177 vlc_mutex_unlock( &p_input->stream.stream_lock );
178 msg_Warn( s, "seek out of bound" );
182 i_skip = i64 - p_input->stream.p_selected_area->i_tell;
186 vlc_mutex_unlock( &p_input->stream.stream_lock );
190 if( i_skip > 0 && i_skip < p_input->p_last_data -
191 p_input->p_current_data - 1 )
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 );
199 vlc_mutex_unlock( &p_input->stream.stream_lock );
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 ) ) )
206 input_AccessReinit( p_input );
207 p_input->pf_seek( p_input, i64 );
213 data_packet_t *p_data;
217 msg_Warn( s, "will skip "I64Fd" bytes, slow", i_skip );
224 i_read = input_SplitBuffer( p_input, &p_data,
225 __MIN( (int)p_input->i_bufsize, i_skip ) );
232 input_DeletePacket( p_input->p_method_data, p_data );
233 if( i_read == 0 && i_skip > 0 )
243 p_int = (int*) va_arg( args, int * );
244 *p_int = p_input->i_mtu;
248 msg_Err( s, "invalid stream_vaControl query=0x%x", i_query );
253 /****************************************************************************
255 ****************************************************************************/
256 static int IStreamRead( stream_t *s, void *p_data, int i_data )
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;
264 if( p_data == NULL && i_data > 0 )
268 stream_Control( s, STREAM_GET_POSITION, &i_pos );
271 if( stream_Control( s, STREAM_SET_POSITION, i_pos ) )
278 while( i_data > 0 && !p_input->b_die )
280 ssize_t i_count = p_input->p_last_data - p_input->p_current_data;
284 /* Go to the next buffer */
285 i_count = input_FillBuffer( p_input );
287 if( i_count < 0 ) return -1;
288 else if( i_count == 0 )
290 /* We reached the EOF */
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;
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 );
311 /****************************************************************************
313 ****************************************************************************/
314 static int IStreamPeek( stream_t *s, uint8_t **pp_peek, int i_peek )
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 );
320 /****************************************************************************
321 * stream_Demux*: create a demuxer for an outpout stream (allow demuxer chain)
322 ****************************************************************************/
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 * );
345 stream_t *__stream_DemuxNew( vlc_object_t *p_obj, char *psz_demux, es_out_t *out )
347 /* We create a stream reader, and launch a thread */
349 d_stream_sys_t *p_sys;
351 if( psz_demux == NULL || *psz_demux == '\0' )
356 s = vlc_object_create( p_obj, sizeof( stream_t ) );
358 s->pf_read = DStreamRead;
359 s->pf_peek = DStreamPeek;
360 s->pf_control= DStreamControl;
362 s->p_sys = malloc( sizeof( d_stream_sys_t) );
363 p_sys = (d_stream_sys_t*)s->p_sys;
365 vlc_mutex_init( s, &p_sys->lock );
367 p_sys->i_buffer_size = 1000000;
368 p_sys->p_buffer = malloc( p_sys->i_buffer_size );
370 p_sys->psz_name = strdup( psz_demux );
372 p_sys->p_demux = NULL;
374 if( vlc_thread_create( s, "stream out", DStreamThread, VLC_THREAD_PRIORITY_INPUT, VLC_FALSE ) )
376 vlc_mutex_destroy( &p_sys->lock );
377 vlc_object_destroy( s );
385 void stream_DemuxSend( stream_t *s, block_t *p_block )
387 d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
389 if( p_block->i_buffer > 0 )
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 )
395 if( p_sys->i_buffer_size > 5000000 )
397 vlc_mutex_unlock( &p_sys->lock );
398 msg_Err( s, "stream_DemuxSend: buffer size > 5000000" );
399 block_Release( p_block );
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 );
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;
413 vlc_mutex_unlock( &p_sys->lock );
416 block_Release( p_block );
419 void stream_DemuxDelete( stream_t *s )
421 d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
425 vlc_mutex_lock( &p_sys->lock );
428 p_sys->p_demux->b_die = VLC_TRUE;
430 vlc_mutex_unlock( &p_sys->lock );
432 vlc_thread_join( s );
436 demux2_Delete( p_sys->p_demux );
438 vlc_mutex_destroy( &p_sys->lock );
439 free( p_sys->psz_name );
440 free( p_sys->p_buffer );
442 vlc_object_destroy( s );
446 static int DStreamRead ( stream_t *s, void *p_read, int i_read )
448 d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
451 //msg_Dbg( s, "DStreamRead: wanted %d bytes", i_read );
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 )
460 vlc_mutex_unlock( &p_sys->lock );
464 //msg_Dbg( s, "DStreamRead: read %d buffer %d", i_read, p_sys->i_buffer );
466 i_copy = __MIN( i_read, p_sys->i_buffer );
471 memcpy( p_read, p_sys->p_buffer, i_copy );
473 p_sys->i_buffer -= i_copy;
474 p_sys->i_pos += i_copy;
476 if( p_sys->i_buffer > 0 )
478 memmove( p_sys->p_buffer, &p_sys->p_buffer[i_copy], p_sys->i_buffer );
482 vlc_mutex_unlock( &p_sys->lock );
486 static int DStreamPeek ( stream_t *s, uint8_t **pp_peek, int i_peek )
488 d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
491 //msg_Dbg( s, "DStreamPeek: wanted %d bytes", i_peek );
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 )
500 vlc_mutex_unlock( &p_sys->lock );
503 *pp_peek = p_sys->p_buffer;
504 i_copy = __MIN( i_peek, p_sys->i_buffer );
506 vlc_mutex_unlock( &p_sys->lock );
511 static int DStreamControl( stream_t *s, int i_query, va_list args )
513 d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
519 case STREAM_GET_SIZE:
520 p_i64 = (int64_t*) va_arg( args, int64_t * );
524 case STREAM_CAN_SEEK:
525 p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
529 case STREAM_CAN_FASTSEEK:
530 p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
534 case STREAM_GET_POSITION:
535 p_i64 = (int64_t*) va_arg( args, int64_t * );
536 *p_i64 = p_sys->i_pos;
539 case STREAM_SET_POSITION:
543 p_int = (int*) va_arg( args, int * );
548 msg_Err( s, "invalid DStreamControl query=0x%x", i_query );
553 static int DStreamThread ( stream_t *s )
555 d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
559 /* Create the demuxer */
561 psz_mrl = malloc( strlen( p_sys->psz_name ) + 3 );
562 sprintf( psz_mrl, "/%s:", p_sys->psz_name );
564 if( ( p_demux = demux2_New( s, psz_mrl, s, p_sys->out ) ) == NULL )
571 vlc_mutex_lock( &p_sys->lock );
572 p_sys->p_demux = p_demux;
573 vlc_mutex_unlock( &p_sys->lock );
576 while( !s->b_die && !p_demux->b_die )
578 if( p_demux->pf_demux( p_demux ) <= 0 )
583 p_demux->b_die = VLC_TRUE;