]> git.sesse.net Git - vlc/blob - include/vlc_block_helper.h
SDL_INIT_EVENTTHREAD is supported on Windows now.
[vlc] / include / vlc_block_helper.h
1 /*****************************************************************************
2  * vlc_block_helper.h: Helper functions for data blocks management.
3  *****************************************************************************
4  * Copyright (C) 2003 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #ifndef VLC_BLOCK_HELPER_H
25 #define VLC_BLOCK_HELPER_H 1
26
27 #include <vlc_block.h>
28
29 typedef struct block_bytestream_t
30 {
31     block_t             *p_chain;
32     block_t             *p_block;
33     size_t              i_offset;
34
35 } block_bytestream_t;
36
37 /*****************************************************************************
38  * block_bytestream_t management
39  *****************************************************************************/
40 LIBVLC_USED
41 static inline block_bytestream_t block_BytestreamInit( void )
42 {
43     block_bytestream_t bytestream;
44
45     bytestream.i_offset = 0;
46     bytestream.p_chain = bytestream.p_block = NULL;
47
48     return bytestream;
49 }
50
51 static inline void block_BytestreamRelease( block_bytestream_t *p_bytestream )
52 {
53     while( p_bytestream->p_chain )
54     {
55         block_t *p_next;
56         p_next = p_bytestream->p_chain->p_next;
57         p_bytestream->p_chain->pf_release( p_bytestream->p_chain );
58         p_bytestream->p_chain = p_next;
59     }
60     p_bytestream->i_offset = 0;
61     p_bytestream->p_chain = p_bytestream->p_block = NULL;
62 }
63
64 /**
65  * It flush all data (read and unread) from a block_bytestream_t.
66  */
67 static inline void block_BytestreamEmpty( block_bytestream_t *p_bytestream )
68 {
69     block_BytestreamRelease( p_bytestream );
70
71     *p_bytestream = block_BytestreamInit();
72 }
73
74 /**
75  * It flushes all already read data from a block_bytestream_t.
76  */
77 static inline void block_BytestreamFlush( block_bytestream_t *p_bytestream )
78 {
79     while( p_bytestream->p_chain != p_bytestream->p_block )
80     {
81         block_t *p_next;
82         p_next = p_bytestream->p_chain->p_next;
83         p_bytestream->p_chain->pf_release( p_bytestream->p_chain );
84         p_bytestream->p_chain = p_next;
85     }
86     while( p_bytestream->p_block &&
87            (p_bytestream->p_block->i_buffer - p_bytestream->i_offset) == 0 )
88     {
89         block_t *p_next;
90         p_next = p_bytestream->p_chain->p_next;
91         p_bytestream->p_chain->pf_release( p_bytestream->p_chain );
92         p_bytestream->p_chain = p_bytestream->p_block = p_next;
93         p_bytestream->i_offset = 0;
94     }
95 }
96
97 static inline void block_BytestreamPush( block_bytestream_t *p_bytestream,
98                                          block_t *p_block )
99 {
100     block_ChainAppend( &p_bytestream->p_chain, p_block );
101     if( !p_bytestream->p_block ) p_bytestream->p_block = p_block;
102 }
103
104 LIBVLC_USED
105 static inline block_t *block_BytestreamPop( block_bytestream_t *p_bytestream )
106 {
107     block_t *p_block;
108
109     block_BytestreamFlush( p_bytestream );
110
111     p_block = p_bytestream->p_block;
112     if( p_block == NULL )
113     {
114         return NULL;
115     }
116     else if( !p_block->p_next )
117     {
118         p_block->p_buffer += p_bytestream->i_offset;
119         p_block->i_buffer -= p_bytestream->i_offset;
120         p_bytestream->i_offset = 0;
121         p_bytestream->p_chain = p_bytestream->p_block = NULL;
122         return p_block;
123     }
124
125     while( p_block->p_next && p_block->p_next->p_next )
126         p_block = p_block->p_next;
127
128     {
129         block_t *p_block_old = p_block;
130         p_block = p_block->p_next;
131         p_block_old->p_next = NULL;
132     }
133
134     return p_block;
135 }
136
137 static inline int block_SkipByte( block_bytestream_t *p_bytestream )
138 {
139     /* Most common case first */
140     if( p_bytestream->p_block->i_buffer - p_bytestream->i_offset )
141     {
142         p_bytestream->i_offset++;
143         return VLC_SUCCESS;
144     }
145     else
146     {
147         block_t *p_block;
148
149         /* Less common case which is also slower */
150         for( p_block = p_bytestream->p_block->p_next;
151              p_block != NULL; p_block = p_block->p_next )
152         {
153             if( p_block->i_buffer )
154             {
155                 p_bytestream->i_offset = 1;
156                 p_bytestream->p_block = p_block;
157                 return VLC_SUCCESS;
158             }
159         }
160     }
161
162     /* Not enough data, bail out */
163     return VLC_EGENERIC;
164 }
165
166 static inline int block_PeekByte( block_bytestream_t *p_bytestream,
167                                   uint8_t *p_data )
168 {
169     /* Most common case first */
170     if( p_bytestream->p_block->i_buffer - p_bytestream->i_offset )
171     {
172         *p_data = p_bytestream->p_block->p_buffer[p_bytestream->i_offset];
173         return VLC_SUCCESS;
174     }
175     else
176     {
177         block_t *p_block;
178
179         /* Less common case which is also slower */
180         for( p_block = p_bytestream->p_block->p_next;
181              p_block != NULL; p_block = p_block->p_next )
182         {
183             if( p_block->i_buffer )
184             {
185                 *p_data = p_block->p_buffer[0];
186                 return VLC_SUCCESS;
187             }
188         }
189     }
190
191     /* Not enough data, bail out */
192     return VLC_EGENERIC;
193 }
194
195 static inline int block_GetByte( block_bytestream_t *p_bytestream,
196                                  uint8_t *p_data )
197 {
198     /* Most common case first */
199     if( p_bytestream->p_block->i_buffer - p_bytestream->i_offset )
200     {
201         *p_data = p_bytestream->p_block->p_buffer[p_bytestream->i_offset];
202         p_bytestream->i_offset++;
203         return VLC_SUCCESS;
204     }
205     else
206     {
207         block_t *p_block;
208
209         /* Less common case which is also slower */
210         for( p_block = p_bytestream->p_block->p_next;
211              p_block != NULL; p_block = p_block->p_next )
212         {
213             if( p_block->i_buffer )
214             {
215                 *p_data = p_block->p_buffer[0];
216                 p_bytestream->i_offset = 1;
217                 p_bytestream->p_block = p_block;
218                 return VLC_SUCCESS;
219             }
220         }
221     }
222
223     /* Not enough data, bail out */
224     return VLC_EGENERIC;
225 }
226
227 static inline int block_WaitBytes( block_bytestream_t *p_bytestream,
228                                    size_t i_data )
229 {
230     block_t *p_block;
231     size_t i_offset, i_copy, i_size;
232
233     /* Check we have that much data */
234     i_offset = p_bytestream->i_offset;
235     i_size = i_data;
236     i_copy = 0;
237     for( p_block = p_bytestream->p_block;
238          p_block != NULL; p_block = p_block->p_next )
239     {
240         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
241         i_size -= i_copy;
242         i_offset = 0;
243
244         if( !i_size ) break;
245     }
246
247     if( i_size )
248     {
249         /* Not enough data, bail out */
250         return VLC_EGENERIC;
251     }
252     return VLC_SUCCESS;
253 }
254
255 static inline int block_SkipBytes( block_bytestream_t *p_bytestream,
256                                    size_t i_data )
257 {
258     block_t *p_block;
259     size_t i_offset, i_copy;
260
261     /* Check we have that much data */
262     i_offset = p_bytestream->i_offset;
263     i_copy = 0;
264     for( p_block = p_bytestream->p_block;
265          p_block != NULL; p_block = p_block->p_next )
266     {
267         i_copy = __MIN( i_data, p_block->i_buffer - i_offset );
268         i_data -= i_copy;
269
270         if( !i_data ) break;
271
272         i_offset = 0;
273     }
274
275     if( i_data )
276     {
277         /* Not enough data, bail out */
278         return VLC_EGENERIC;
279     }
280
281     p_bytestream->p_block = p_block;
282     p_bytestream->i_offset = i_offset + i_copy;
283     return VLC_SUCCESS;
284 }
285
286 static inline int block_PeekBytes( block_bytestream_t *p_bytestream,
287                                    uint8_t *p_data, size_t i_data )
288 {
289     block_t *p_block;
290     size_t i_offset, i_copy, i_size;
291
292     /* Check we have that much data */
293     i_offset = p_bytestream->i_offset;
294     i_size = i_data;
295     i_copy = 0;
296     for( p_block = p_bytestream->p_block;
297          p_block != NULL; p_block = p_block->p_next )
298     {
299         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
300         i_size -= i_copy;
301         i_offset = 0;
302
303         if( !i_size ) break;
304     }
305
306     if( i_size )
307     {
308         /* Not enough data, bail out */
309         return VLC_EGENERIC;
310     }
311
312     /* Copy the data */
313     i_offset = p_bytestream->i_offset;
314     i_size = i_data;
315     i_copy = 0;
316     for( p_block = p_bytestream->p_block;
317          p_block != NULL; p_block = p_block->p_next )
318     {
319         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
320         i_size -= i_copy;
321
322         if( i_copy )
323         {
324             memcpy( p_data, p_block->p_buffer + i_offset, i_copy );
325             p_data += i_copy;
326         }
327
328         i_offset = 0;
329
330         if( !i_size ) break;
331     }
332
333     return VLC_SUCCESS;
334 }
335
336 static inline int block_GetBytes( block_bytestream_t *p_bytestream,
337                                   uint8_t *p_data, size_t i_data )
338 {
339     block_t *p_block;
340     size_t i_offset, i_copy, i_size;
341
342     /* Check we have that much data */
343     i_offset = p_bytestream->i_offset;
344     i_size = i_data;
345     i_copy = 0;
346     for( p_block = p_bytestream->p_block;
347          p_block != NULL; p_block = p_block->p_next )
348     {
349         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
350         i_size -= i_copy;
351         i_offset = 0;
352
353         if( !i_size ) break;
354     }
355
356     if( i_size )
357     {
358         /* Not enough data, bail out */
359         return VLC_EGENERIC;
360     }
361
362     /* Copy the data */
363     i_offset = p_bytestream->i_offset;
364     i_size = i_data;
365     i_copy = 0;
366     for( p_block = p_bytestream->p_block;
367          p_block != NULL; p_block = p_block->p_next )
368     {
369         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
370         i_size -= i_copy;
371
372         if( i_copy )
373         {
374             memcpy( p_data, p_block->p_buffer + i_offset, i_copy );
375             p_data += i_copy;
376         }
377
378         if( !i_size ) break;
379
380         i_offset = 0;
381     }
382
383     /* No buffer given, just skip the data */
384     p_bytestream->p_block = p_block;
385     p_bytestream->i_offset = i_offset + i_copy;
386
387     return VLC_SUCCESS;
388 }
389
390 static inline int block_PeekOffsetBytes( block_bytestream_t *p_bytestream,
391     size_t i_peek_offset, uint8_t *p_data, size_t i_data )
392 {
393     block_t *p_block;
394     size_t i_offset, i_copy, i_size;
395
396     /* Check we have that much data */
397     i_offset = p_bytestream->i_offset;
398     i_size = i_data + i_peek_offset;
399     i_copy = 0;
400     for( p_block = p_bytestream->p_block;
401          p_block != NULL; p_block = p_block->p_next )
402     {
403         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
404         i_size -= i_copy;
405         i_offset = 0;
406
407         if( !i_size ) break;
408     }
409
410     if( i_size )
411     {
412         /* Not enough data, bail out */
413         return VLC_EGENERIC;
414     }
415
416     /* Find the right place */
417     i_offset = p_bytestream->i_offset;
418     i_size = i_peek_offset;
419     i_copy = 0;
420     for( p_block = p_bytestream->p_block;
421          p_block != NULL; p_block = p_block->p_next )
422     {
423         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
424         i_size -= i_copy;
425
426         if( !i_size ) break;
427
428         i_offset = 0;
429     }
430
431     /* Copy the data */
432     i_offset += i_copy;
433     i_size = i_data;
434     i_copy = 0;
435     for( ; p_block != NULL; p_block = p_block->p_next )
436     {
437         i_copy = __MIN( i_size, p_block->i_buffer - i_offset );
438         i_size -= i_copy;
439
440         if( i_copy )
441         {
442             memcpy( p_data, p_block->p_buffer + i_offset, i_copy );
443             p_data += i_copy;
444         }
445
446         i_offset = 0;
447
448         if( !i_size ) break;
449     }
450
451     return VLC_SUCCESS;
452 }
453
454 static inline int block_FindStartcodeFromOffset(
455     block_bytestream_t *p_bytestream, size_t *pi_offset,
456     const uint8_t *p_startcode, int i_startcode_length )
457 {
458     block_t *p_block, *p_block_backup = 0;
459     int i_size = 0;
460     size_t i_offset, i_offset_backup = 0;
461     int i_caller_offset_backup = 0, i_match;
462
463     /* Find the right place */
464     i_size = *pi_offset + p_bytestream->i_offset;
465     for( p_block = p_bytestream->p_block;
466          p_block != NULL; p_block = p_block->p_next )
467     {
468         i_size -= p_block->i_buffer;
469         if( i_size < 0 ) break;
470     }
471
472     if( i_size >= 0 )
473     {
474         /* Not enough data, bail out */
475         return VLC_EGENERIC;
476     }
477
478     /* Begin the search.
479      * We first look for an occurrence of the 1st startcode byte and
480      * if found, we do a more thorough check. */
481     i_size += p_block->i_buffer;
482     *pi_offset -= i_size;
483     i_match = 0;
484     for( ; p_block != NULL; p_block = p_block->p_next )
485     {
486         for( i_offset = i_size; i_offset < p_block->i_buffer; i_offset++ )
487         {
488             if( p_block->p_buffer[i_offset] == p_startcode[i_match] )
489             {
490                 if( !i_match )
491                 {
492                     p_block_backup = p_block;
493                     i_offset_backup = i_offset;
494                     i_caller_offset_backup = *pi_offset;
495                 }
496
497                 if( i_match + 1 == i_startcode_length )
498                 {
499                     /* We have it */
500                     *pi_offset += i_offset - i_match;
501                     return VLC_SUCCESS;
502                 }
503
504                 i_match++;
505             }
506             else if ( i_match )
507             {
508                 /* False positive */
509                 p_block = p_block_backup;
510                 i_offset = i_offset_backup;
511                 *pi_offset = i_caller_offset_backup;
512                 i_match = 0;
513             }
514
515         }
516         i_size = 0;
517         *pi_offset += i_offset;
518     }
519
520     *pi_offset -= i_match;
521     return VLC_EGENERIC;
522 }
523
524 #endif /* VLC_BLOCK_HELPER_H */