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