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