]> git.sesse.net Git - vlc/blob - src/misc/block.c
* ALL: Introduction of a new api for decoders.
[vlc] / src / misc / block.c
1 /*****************************************************************************
2  * block.c: Data blocks management functions
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: block.c,v 1.2 2003/09/02 20:19:26 gbazin Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@videolan.org>
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 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28 #include <stdarg.h>
29
30 #include <vlc/vlc.h>
31 #include "vlc_block.h"
32
33 /* private */
34 struct block_sys_t
35 {
36     vlc_mutex_t lock;
37
38     uint8_t     *p_allocated_buffer;
39     int         i_allocated_buffer;
40
41     vlc_bool_t  b_modify;       /* has it been put in modified state */
42     int         i_duplicated;   /* how many times has the content been
43                                  * duplicated */
44
45 };
46
47 static void BlockRelease( block_t *p_block )
48 {
49     vlc_mutex_lock( &p_block->p_sys->lock );
50
51     p_block->p_sys->i_duplicated--;
52     if( p_block->p_sys->i_duplicated < 0 )
53     {
54         vlc_mutex_unlock( &p_block->p_sys->lock );
55         free( p_block->p_sys->p_allocated_buffer );
56         free( p_block->p_sys );
57         free( p_block );
58
59         return;
60     }
61
62     vlc_mutex_unlock( &p_block->p_sys->lock );
63     free( p_block );
64 }
65
66 static block_t *__BlockDupContent( block_t *p_block )
67 {
68     block_t *p_dup;
69
70     p_dup = block_New( p_block->p_manager, p_block->i_buffer );
71     memcpy( p_dup->p_buffer, p_block->p_buffer, p_block->i_buffer );
72     p_dup->b_frame_display = p_block->b_frame_display;
73     p_dup->b_frame_start   = p_block->b_frame_start;
74     p_dup->i_pts           = p_block->i_pts;
75     p_dup->i_dts           = p_block->i_dts;
76
77     return p_dup;
78 }
79
80 static block_t *BlockModify( block_t *p_block, vlc_bool_t b_will_modify )
81 {
82     block_t *p_mod = p_block;   /* by default */
83
84     vlc_mutex_lock( &p_block->p_sys->lock );
85
86     if( p_block->p_sys->b_modify == b_will_modify )
87     {
88         vlc_mutex_unlock( &p_block->p_sys->lock );
89         return p_block;
90     }
91
92     if( p_block->p_sys->i_duplicated == 0 )
93     {
94         p_block->p_sys->b_modify = b_will_modify;
95         vlc_mutex_unlock( &p_block->p_sys->lock );
96         return p_block;
97     }
98
99     /* FIXME we could avoid that
100      * we just need to create a new p_sys with new mem FIXME */
101     p_mod = __BlockDupContent( p_block );
102     vlc_mutex_unlock( &p_block->p_sys->lock );
103
104     BlockRelease( p_block );
105
106     return p_mod;
107 }
108
109 static block_t *BlockDuplicate( block_t *p_block )
110 {
111     block_t *p_dup;
112
113     vlc_mutex_lock( &p_block->p_sys->lock );
114     if( !p_block->p_sys->b_modify )
115     {
116         p_block->p_sys->i_duplicated++;
117         vlc_mutex_unlock( &p_block->p_sys->lock );
118         p_dup = block_NewEmpty();
119         memcpy( p_dup, p_block, sizeof( block_t ) );
120         p_dup->p_next = NULL;
121         return p_dup;
122     }
123     p_dup = __BlockDupContent( p_block );
124     vlc_mutex_unlock( &p_block->p_sys->lock );
125
126     return p_dup;
127 }
128
129 static block_t *BlockRealloc( block_t *p_block, int i_prebody, int i_body )
130 {
131
132     vlc_mutex_lock( &p_block->p_sys->lock );
133     if( i_prebody < 0 || p_block->p_buffer - i_prebody >
134         p_block->p_sys->p_allocated_buffer )
135     {
136         p_block->p_buffer -= i_prebody;
137         p_block->i_buffer += i_prebody;
138         i_prebody = 0;
139     }
140     if( i_body < 0 ||
141         p_block->p_buffer + i_body < p_block->p_sys->p_allocated_buffer +
142         p_block->p_sys->i_allocated_buffer )
143     {
144         p_block->i_buffer = i_body;
145         i_body = 0;
146     }
147     vlc_mutex_unlock( &p_block->p_sys->lock );
148
149     if( i_prebody > 0 )
150     {
151         block_t *p_rea = block_New( p_block->p_manager, i_prebody + i_body );
152
153         memcpy( &p_rea->p_buffer[i_prebody], p_block->p_buffer,
154                 p_block->i_buffer );
155
156         return p_rea;
157     }
158
159     if( i_body > 0 )
160     {
161         int i_start;
162         block_t *p_rea = BlockModify( p_block, VLC_TRUE );
163
164         i_start = p_rea->p_buffer - p_rea->p_sys->p_allocated_buffer;
165
166         p_rea->p_sys->i_allocated_buffer += i_body - p_rea->i_buffer;
167         p_rea->p_sys->p_allocated_buffer =
168             realloc( p_rea->p_sys->p_allocated_buffer,
169                      p_rea->p_sys->i_allocated_buffer );
170
171         p_rea->p_buffer = &p_rea->p_sys->p_allocated_buffer[i_start];
172         p_rea->i_buffer = i_body;
173
174         return p_rea;
175     }
176
177     return p_block;
178 }
179
180 /*****************************************************************************
181  * Standard block management
182  *
183  *****************************************************************************/
184 /* to be used by other block managment */
185 block_t *block_NewEmpty( void )
186 {
187     block_t *p_block;
188
189     p_block = malloc( sizeof( block_t ) );
190     p_block->p_next         = NULL;
191     p_block->b_frame_display= VLC_TRUE;
192     p_block->b_frame_start  = VLC_FALSE;
193     p_block->i_pts          = 0;
194     p_block->i_dts          = 0;
195
196     p_block->i_buffer       = 0;
197     p_block->p_buffer       = NULL;
198
199     p_block->pf_release     = NULL;
200     p_block->pf_duplicate   = NULL;
201     p_block->pf_modify      = NULL;
202     p_block->pf_realloc     = NULL;
203
204     p_block->p_sys = NULL;
205     return p_block;
206 }
207
208 block_t *__block_New( vlc_object_t *p_obj, int i_size )
209 {
210     block_t     *p_block;
211     block_sys_t *p_sys;
212
213     p_block = block_NewEmpty();
214
215     p_block->i_buffer       = i_size;
216     if( i_size > 0 )
217     {
218         p_block->p_buffer   = malloc( i_size );
219     }
220
221     p_block->pf_release     = BlockRelease;
222     p_block->pf_duplicate   = BlockDuplicate;
223     p_block->pf_modify      = BlockModify;
224     p_block->pf_realloc     = BlockRealloc;
225
226     /* that should be ok (no comunication between multiple p_vlc) */
227     p_block->p_manager      = VLC_OBJECT( p_obj->p_vlc );
228
229     p_block->p_sys = p_sys = malloc( sizeof( block_sys_t ) );
230     vlc_mutex_init( p_obj, &p_sys->lock );
231     p_sys->p_allocated_buffer = p_block->p_buffer;
232     p_sys->i_allocated_buffer = p_block->i_buffer;
233     p_sys->i_duplicated = 0;
234     p_sys->b_modify = VLC_TRUE;
235
236     return p_block;
237 }
238
239 void block_ChainAppend( block_t **pp_list, block_t *p_block )
240 {
241
242     if( *pp_list == NULL )
243     {
244         *pp_list = p_block;
245     }
246     else
247     {
248         block_t *p = *pp_list;
249
250         while( p->p_next )
251         {
252             p = p->p_next;
253         }
254         p->p_next = p_block;
255     }
256 }
257
258 void block_ChainRelease( block_t *p_block )
259 {
260     while( p_block )
261     {
262         block_t *p_next;
263         p_next = p_block->p_next;
264         p_block->pf_release( p_block );
265         p_block = p_next;
266     }
267 }
268
269 int block_ChainExtract( block_t *p_list, void *p_data, int i_max )
270 {
271     block_t *b;
272     int     i_total = 0;
273     uint8_t *p = p_data;
274
275     for( b = p_list; b != NULL; b = b->p_next )
276     {
277         int i_copy;
278
279         i_copy = __MIN( i_max, b->i_buffer );
280         if( i_copy > 0 )
281         {
282             memcpy( p, b->p_buffer, i_copy );
283             i_max   -= i_copy;
284             i_total += i_copy;
285             p       += i_copy;
286
287             if( i_max == 0 )
288             {
289                 return i_total;
290             }
291         }
292     }
293     return i_total;
294 }
295
296 block_t *block_ChainGather( block_t *p_list )
297 {
298     int     i_total = 0;
299     block_t *b, *g;
300
301     if( p_list->p_next == NULL )
302     {
303         /* only one, so no need */
304         return p_list;
305     }
306
307     for( b = p_list; b != NULL; b = b->p_next )
308     {
309         i_total += b->i_buffer;
310     }
311
312     g = block_New( p_list->p_manager, i_total );
313     block_ChainExtract( p_list, g->p_buffer, g->i_buffer );
314
315     g->b_frame_display = p_list->b_frame_display;
316     g->b_frame_start   = p_list->b_frame_start;
317     g->i_pts           = p_list->i_pts;
318     g->i_dts           = p_list->i_dts;
319
320     /* free p_list */
321     block_ChainRelease( p_list );
322     return g;
323 }
324
325
326 /*****************************************************************************
327  * block_fifo_t managment
328  *****************************************************************************/
329 block_fifo_t *__block_FifoNew( vlc_object_t *p_obj )
330 {
331     block_fifo_t *p_fifo;
332
333     p_fifo = malloc( sizeof( vlc_object_t ) );
334     vlc_mutex_init( p_obj, &p_fifo->lock );
335     vlc_cond_init( p_obj, &p_fifo->wait );
336     p_fifo->i_depth = 0;
337     p_fifo->p_first = NULL;
338     p_fifo->pp_last = &p_fifo->p_first;
339
340     return p_fifo;
341 }
342
343 void block_FifoRelease( block_fifo_t *p_fifo )
344 {
345     block_FifoEmpty( p_fifo );
346     vlc_cond_destroy( &p_fifo->wait );
347     vlc_mutex_destroy( &p_fifo->lock );
348     free( p_fifo );
349 }
350
351 void block_FifoEmpty( block_fifo_t *p_fifo )
352 {
353     block_t *b;
354
355     vlc_mutex_lock( &p_fifo->lock );
356     for( b = p_fifo->p_first; b != NULL; )
357     {
358         block_t *p_next;
359
360         p_next = b->p_next;
361         block_Release( b );
362         b = p_next;
363     }
364
365     p_fifo->i_depth = 0;
366     p_fifo->p_first = NULL;
367     p_fifo->pp_last = &p_fifo->p_first;
368     vlc_mutex_unlock( &p_fifo->lock );
369 }
370
371 int block_FifoPut( block_fifo_t *p_fifo, block_t *p_block )
372 {
373     int i_size = 0;
374     vlc_mutex_lock( &p_fifo->lock );
375
376     do
377     {
378         i_size += p_block->i_buffer;
379
380         *p_fifo->pp_last = p_block;
381         p_fifo->pp_last = &p_block->p_next;
382         p_fifo->i_depth++;
383
384         p_block = p_block->p_next;
385
386     } while( p_block );
387
388     /* warn there is data in this fifo */
389     vlc_cond_signal( &p_fifo->wait );
390     vlc_mutex_unlock( &p_fifo->lock );
391
392     return i_size;
393 }
394
395 block_t *block_FifoGet( block_fifo_t *p_fifo )
396 {
397     block_t *b;
398
399     vlc_mutex_lock( &p_fifo->lock );
400
401     if( p_fifo->p_first == NULL )
402     {
403         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
404     }
405
406     b = p_fifo->p_first;
407
408     p_fifo->p_first = b->p_next;
409     p_fifo->i_depth--;
410
411     if( p_fifo->p_first == NULL )
412     {
413         p_fifo->pp_last = &p_fifo->p_first;
414     }
415
416     vlc_mutex_unlock( &p_fifo->lock );
417
418     b->p_next = NULL;
419     return( b );
420 }
421
422 block_t *block_FifoShow( block_fifo_t *p_fifo )
423 {
424     block_t *b;
425
426     vlc_mutex_lock( &p_fifo->lock );
427
428     if( p_fifo->p_first == NULL )
429     {
430         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
431     }
432
433     b = p_fifo->p_first;
434
435     vlc_mutex_unlock( &p_fifo->lock );
436
437     return( b );
438
439 }
440
441 block_t *block_FifoGetFrame( block_fifo_t *p_fifo )
442 {
443     block_t *b = NULL;
444
445     for( ;; )
446     {
447         block_t *p_next;
448         block_ChainAppend( &b, block_FifoGet( p_fifo ) );
449         p_next = block_FifoShow( p_fifo );
450         if( p_next == NULL || p_next->b_frame_start )
451         {
452             break;
453         }
454     }
455
456     return b;
457 }