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