]> git.sesse.net Git - vlc/blob - src/input/stream.c
* src/libvlc.h, src/input/input.c:
[vlc] / src / input / stream.c
1 /*****************************************************************************
2  * stream.c
3  *****************************************************************************
4  * Copyright (C) 1999-2004 VideoLAN
5  * $Id: stream.c,v 1.15 2004/02/02 13:00:53 fenrir Exp $
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     msg_Dbg( s, "i_data %d", i_data );
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         msg_Dbg( s, "found %d chars long line", i );
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 struct stream_sys_t
80 {
81     input_thread_t *p_input;
82 };
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     if( s )
96     {
97         s->pf_block  = NULL;
98         s->pf_read   = IStreamRead;
99         s->pf_peek   = IStreamPeek;
100         s->pf_control= IStreamControl;
101
102         s->p_sys = malloc( sizeof( stream_sys_t ) );
103         s->p_sys->p_input = p_input;
104     }
105     return s;
106 }
107
108 /****************************************************************************
109  * input_StreamDelete:
110  ****************************************************************************/
111 void input_StreamDelete( stream_t *s )
112 {
113     free( s->p_sys );
114     vlc_object_destroy( s );
115 }
116
117
118 /****************************************************************************
119  * IStreamControl:
120  ****************************************************************************/
121 static int IStreamControl( stream_t *s, int i_query, va_list args )
122 {
123     input_thread_t *p_input = s->p_sys->p_input;
124
125     vlc_bool_t *p_b;
126     int64_t    *p_i64, i64;
127     int        *p_int;
128
129     switch( i_query )
130     {
131         case STREAM_GET_SIZE:
132             p_i64 = (int64_t*) va_arg( args, int64_t * );
133
134             vlc_mutex_lock( &p_input->stream.stream_lock );
135             *p_i64 = p_input->stream.p_selected_area->i_size;
136             vlc_mutex_unlock( &p_input->stream.stream_lock );
137             return VLC_SUCCESS;
138
139         case STREAM_CAN_SEEK:
140             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
141
142             vlc_mutex_lock( &p_input->stream.stream_lock );
143             *p_b = p_input->stream.b_seekable;
144             vlc_mutex_unlock( &p_input->stream.stream_lock );
145             return VLC_SUCCESS;
146
147         case STREAM_CAN_FASTSEEK:
148             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
149
150             vlc_mutex_lock( &p_input->stream.stream_lock );
151             *p_b = p_input->stream.b_seekable &&
152                    p_input->stream.i_method == INPUT_METHOD_FILE;
153             vlc_mutex_unlock( &p_input->stream.stream_lock );
154             return VLC_SUCCESS;
155
156         case STREAM_GET_POSITION:
157             p_i64 = (int64_t*) va_arg( args, int64_t * );
158
159             vlc_mutex_lock( &p_input->stream.stream_lock );
160             *p_i64 = p_input->stream.p_selected_area->i_tell;
161             vlc_mutex_unlock( &p_input->stream.stream_lock );
162             return VLC_SUCCESS;
163
164         case STREAM_SET_POSITION:
165         {
166             int64_t i_skip;
167             i64 = (int64_t) va_arg( args, int64_t );
168
169             vlc_mutex_lock( &p_input->stream.stream_lock );
170             if( i64 < 0 ||
171                 ( p_input->stream.p_selected_area->i_size > 0 &&
172                   p_input->stream.p_selected_area->i_size < i64 ) )
173             {
174                 vlc_mutex_unlock( &p_input->stream.stream_lock );
175                 msg_Warn( s, "seek out of bound" );
176                 return VLC_EGENERIC;
177             }
178
179             i_skip = i64 - p_input->stream.p_selected_area->i_tell;
180
181             if( i_skip == 0 )
182             {
183                 vlc_mutex_unlock( &p_input->stream.stream_lock );
184                 return VLC_SUCCESS;
185             }
186
187             if( i_skip > 0 && i_skip < p_input->p_last_data -
188                             p_input->p_current_data - 1 )
189             {
190                 /* We can skip without reading/seeking */
191                 p_input->p_current_data += i_skip;
192                 p_input->stream.p_selected_area->i_tell = i64;
193                 vlc_mutex_unlock( &p_input->stream.stream_lock );
194                 return VLC_SUCCESS;
195             }
196             vlc_mutex_unlock( &p_input->stream.stream_lock );
197
198             if( p_input->stream.b_seekable &&
199                 ( p_input->stream.i_method == INPUT_METHOD_FILE ||
200                   i_skip < 0 || i_skip >= ( p_input->i_mtu > 0 ?
201                                             p_input->i_mtu : 4096 ) ) )
202             {
203                 input_AccessReinit( p_input );
204                 p_input->pf_seek( p_input, i64 );
205                 return VLC_SUCCESS;
206             }
207
208             if( i_skip > 0 )
209             {
210                 data_packet_t *p_data;
211
212                 if( i_skip > 1000 )
213                 {
214                     msg_Warn( s, "will skip "I64Fd" bytes, slow", i_skip );
215                 }
216
217                 while( i_skip > 0 )
218                 {
219                     int i_read;
220
221                     i_read = input_SplitBuffer( p_input, &p_data,
222                                  __MIN( (int)p_input->i_bufsize, i_skip ) );
223                     if( i_read < 0 )
224                     {
225                         return VLC_EGENERIC;
226                     }
227                     i_skip -= i_read;
228
229                     input_DeletePacket( p_input->p_method_data, p_data );
230                     if( i_read == 0 && i_skip > 0 )
231                     {
232                         return VLC_EGENERIC;
233                     }
234                 }
235             }
236             return VLC_SUCCESS;
237         }
238
239         case STREAM_GET_MTU:
240             p_int = (int*) va_arg( args, int * );
241             *p_int = p_input->i_mtu;
242             return VLC_SUCCESS;
243
244         default:
245             msg_Err( s, "invalid stream_vaControl query=0x%x", i_query );
246             return VLC_EGENERIC;
247     }
248 }
249
250 /****************************************************************************
251  * IStreamRead:
252  ****************************************************************************/
253 static int IStreamRead( stream_t *s, void *p_data, int i_data )
254 {
255     input_thread_t *p_input = s->p_sys->p_input;
256     uint8_t       *p = (uint8_t*)p_data;
257     data_packet_t *p_packet;
258
259     int i_read = 0;
260
261     if( p_data == NULL && i_data > 0 )
262     {
263         int64_t i_pos;
264
265         stream_Control( s, STREAM_GET_POSITION, &i_pos );
266
267         i_pos += i_data;
268         if( stream_Control( s, STREAM_SET_POSITION, i_pos ) )
269         {
270             return 0;
271         }
272         return i_data;
273     }
274
275     while( i_data > 0 && !p_input->b_die )
276     {
277         int i_count;
278
279         i_count = input_SplitBuffer( p_input, &p_packet,
280                       __MIN( i_data, (int)p_input->i_bufsize ) );
281
282         if( i_count <= 0 )
283         {
284             if( i_count == 0 )
285                 input_DeletePacket( p_input->p_method_data, p_packet );
286
287             return i_read;
288         }
289
290         if( p )
291         {
292             memcpy( p, p_packet->p_payload_start, i_count );
293             p += i_count;
294         }
295
296         input_DeletePacket( p_input->p_method_data, p_packet );
297
298         i_data -= i_count;
299         i_read += i_count;
300     }
301
302     return i_read;
303 }
304 /****************************************************************************
305  * IStreamPeek:
306  ****************************************************************************/
307 static int IStreamPeek( stream_t *s, uint8_t **pp_peek, int i_peek )
308 {
309     return input_Peek( s->p_sys->p_input, pp_peek, i_peek );
310 }