Refer to transitions in the presence-or-lack-thereof of progressive flags on MPEG...
[HandBrake.git] / libhb / fifo.c
blob4f844795c1a9453386aa8b5762f37fbf1b706748
1 /* $Id: fifo.c,v 1.17 2005/10/15 18:05:03 titer Exp $
3 This file is part of the HandBrake source code.
4 Homepage: <http://handbrake.m0k.org/>.
5 It may be used under the terms of the GNU General Public License. */
7 #include "hb.h"
9 #ifndef SYS_DARWIN
10 #include <malloc.h>
11 #endif
13 /* Fifo */
14 struct hb_fifo_s
16 hb_lock_t * lock;
17 int capacity;
18 int size;
19 int buffer_size;
20 hb_buffer_t * first;
21 hb_buffer_t * last;
24 #define MAX_BUFFER_POOLS 15
25 #define BUFFER_POOL_MAX_ELEMENTS 2048
27 struct hb_buffer_pools_s
29 int entries;
30 int allocated;
31 hb_fifo_t *pool[MAX_BUFFER_POOLS];
32 hb_lock_t *lock;
35 struct hb_buffer_pools_s buffers;
37 void hb_buffer_pool_init( void )
39 hb_fifo_t *buffer_pool;
40 int size = 512;
41 int max_size = 32768;;
43 buffers.entries = 0;
44 buffers.lock = hb_lock_init();
45 buffers.allocated = 0;
47 while(size <= max_size) {
48 buffer_pool = buffers.pool[buffers.entries++] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS);
49 buffer_pool->buffer_size = size;
50 size *= 2;
54 void hb_buffer_pool_free( void )
56 int i;
57 int count;
58 int freed = 0;
59 hb_buffer_t *b;
61 hb_lock(buffers.lock);
63 for( i = 0; i < buffers.entries; i++)
65 count = 0;
66 while( ( b = hb_fifo_get(buffers.pool[i]) ) )
68 freed += b->alloc;
69 if( b->data )
71 free( b->data );
72 b->data = NULL;
74 free( b );
75 count++;
77 hb_log("Freed %d buffers of size %d", count, buffers.pool[i]->buffer_size);
80 hb_log("Allocated %d bytes of buffers on this pass and Freed %d bytes, %d bytes leaked",
81 buffers.allocated, freed, buffers.allocated - freed);
82 buffers.allocated = 0;
83 hb_unlock(buffers.lock);
87 hb_buffer_t * hb_buffer_init( int size )
89 hb_buffer_t * b;
90 int i;
91 hb_fifo_t *buffer_pool = NULL;
92 uint8_t *data;
93 int b_alloc;
94 int resize = 0;
96 if( size > 0 )
99 * The buffer pools are allocated in increasing size
101 for( i = 0; i < buffers.entries; i++ )
103 if( buffers.pool[i]->buffer_size >= size )
106 * This pool is big enough, but are there any buffers in it?
108 if( hb_fifo_size( buffers.pool[i] ) )
111 * We've found a matching buffer pool, with buffers.
113 buffer_pool = buffers.pool[i];
114 resize = buffers.pool[i]->buffer_size;
115 } else {
117 * Buffer pool is empty,
119 if( resize ) {
121 * This is the second time through, so break
122 * out of here to avoid using too large a
123 * buffer for a small job.
125 break;
127 resize = buffers.pool[i]->buffer_size;
133 * Don't reuse the 0 size buffers, not much gain.
135 if( size != 0 && buffer_pool )
137 b = hb_fifo_get( buffer_pool );
139 if( b )
142 * Zero the contents of the buffer, would be nice if we
143 * didn't have to do this.
145 hb_log("Reused buffer size %d for size %d from pool %d depth %d",
146 b->alloc, size, smallest_pool->buffer_size,
147 hb_fifo_size(smallest_pool));
149 data = b->data;
150 b_alloc = b->alloc;
151 memset( b, 0, sizeof(hb_buffer_t) );
152 b->alloc = b_alloc;
153 b->size = size;
154 b->data = data;
155 return( b );
160 * No existing buffers, create a new one
162 if( !( b = calloc( sizeof( hb_buffer_t ), 1 ) ) )
164 hb_log( "out of memory" );
165 return NULL;
168 b->size = size;
170 if( resize )
172 size = resize;
174 b->alloc = size;
177 hb_log("Allocating new buffer of size %d for size %d",
178 b->alloc,
179 b->size);
182 if (!size)
183 return b;
184 #if defined( SYS_DARWIN ) || defined( SYS_FREEBSD )
185 b->data = malloc( b->alloc );
186 #elif defined( SYS_CYGWIN )
187 /* FIXME */
188 b->data = malloc( b->alloc + 17 );
189 #else
190 b->data = memalign( 16, b->alloc );
191 #endif
193 if( !b->data )
195 hb_log( "out of memory" );
196 free( b );
197 return NULL;
200 buffers.allocated += b->alloc;
202 return b;
205 void hb_buffer_realloc( hb_buffer_t * b, int size )
207 /* No more alignment, but we don't care */
208 if( size < 2048 ) {
209 size = 2048;
211 b->data = realloc( b->data, size );
212 buffers.allocated -= b->alloc;
213 b->alloc = size;
214 buffers.allocated += b->alloc;
217 void hb_buffer_close( hb_buffer_t ** _b )
219 hb_buffer_t * b = *_b;
220 hb_fifo_t *buffer_pool = NULL;
221 int i;
224 * Put the buffer into our free list in the matching buffer pool, if there is one.
226 if( b->alloc != 0 )
228 for( i = 0; i < buffers.entries; i++ )
230 if( b->alloc == buffers.pool[i]->buffer_size )
232 buffer_pool = buffers.pool[i];
233 break;
238 if( buffer_pool )
240 if( !hb_fifo_is_full( buffer_pool ) )
242 if(b->data)
245 hb_log("Putting a buffer of size %d on pool %d, depth %d",
246 b->alloc,
247 buffer_pool->buffer_size,
248 hb_fifo_size(buffer_pool));
250 hb_fifo_push( buffer_pool, b );
251 } else {
252 free(b);
254 } else {
256 * Got a load of these size ones already, free this buffer.
258 hb_log("Buffer pool for size %d full, freeing buffer", b->alloc);
260 if( b->data )
262 free( b->data );
264 buffers.allocated -= b->alloc;
265 free( b );
267 } else {
269 * Need a new buffer pool for this size.
271 hb_lock(buffers.lock);
272 if ( b->alloc != 0 && buffers.entries < MAX_BUFFER_POOLS)
274 buffer_pool = buffers.pool[buffers.entries++] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS);
275 buffer_pool->buffer_size = b->alloc;
276 hb_fifo_push( buffer_pool, b );
278 hb_log("*** Allocated a new buffer pool for size %d [%d]", b->alloc,
279 buffers.entries );
281 } else {
282 if( b->alloc != 0 )
284 for( i = buffers.entries-1; i >= 0; i-- )
286 if( hb_fifo_size(buffers.pool[i]) == 0 )
289 * Reuse this pool as it is empty.
291 buffers.pool[i]->buffer_size = b->alloc;
292 hb_fifo_push( buffers.pool[i], b );
293 b = NULL;
294 break;
299 if( b )
301 if( b->data )
303 free( b->data );
304 b->data = NULL;
305 buffers.allocated -= b->alloc;
307 free( b );
310 hb_unlock(buffers.lock);
313 *_b = NULL;
317 void hb_buffer_copy_settings( hb_buffer_t * dst, const hb_buffer_t * src )
319 dst->start = src->start;
320 dst->stop = src->stop;
321 dst->new_chap = src->new_chap;
322 dst->frametype = src->frametype;
323 dst->flags = src->flags;
326 hb_fifo_t * hb_fifo_init( int capacity )
328 hb_fifo_t * f;
329 f = calloc( sizeof( hb_fifo_t ), 1 );
330 f->lock = hb_lock_init();
331 f->capacity = capacity;
332 f->buffer_size = 0;
333 return f;
336 int hb_fifo_size( hb_fifo_t * f )
338 int ret;
340 hb_lock( f->lock );
341 ret = f->size;
342 hb_unlock( f->lock );
344 return ret;
347 int hb_fifo_is_full( hb_fifo_t * f )
349 int ret;
351 hb_lock( f->lock );
352 ret = ( f->size >= f->capacity );
353 hb_unlock( f->lock );
355 return ret;
358 float hb_fifo_percent_full( hb_fifo_t * f )
360 float ret;
362 hb_lock( f->lock );
363 ret = f->size / f->capacity;
364 hb_unlock( f->lock );
366 return ret;
369 hb_buffer_t * hb_fifo_get( hb_fifo_t * f )
371 hb_buffer_t * b;
373 hb_lock( f->lock );
374 if( f->size < 1 )
376 hb_unlock( f->lock );
377 return NULL;
379 b = f->first;
380 f->first = b->next;
381 b->next = NULL;
382 f->size -= 1;
383 hb_unlock( f->lock );
385 return b;
388 hb_buffer_t * hb_fifo_see( hb_fifo_t * f )
390 hb_buffer_t * b;
392 hb_lock( f->lock );
393 if( f->size < 1 )
395 hb_unlock( f->lock );
396 return NULL;
398 b = f->first;
399 hb_unlock( f->lock );
401 return b;
404 hb_buffer_t * hb_fifo_see2( hb_fifo_t * f )
406 hb_buffer_t * b;
408 hb_lock( f->lock );
409 if( f->size < 2 )
411 hb_unlock( f->lock );
412 return NULL;
414 b = f->first->next;
415 hb_unlock( f->lock );
417 return b;
420 void hb_fifo_push( hb_fifo_t * f, hb_buffer_t * b )
422 if( !b )
424 return;
427 hb_lock( f->lock );
428 if( f->size > 0 )
430 f->last->next = b;
432 else
434 f->first = b;
436 f->last = b;
437 f->size += 1;
438 while( f->last->next )
440 f->size += 1;
441 f->last = f->last->next;
443 hb_unlock( f->lock );
446 void hb_fifo_close( hb_fifo_t ** _f )
448 hb_fifo_t * f = *_f;
449 hb_buffer_t * b;
451 hb_log( "fifo_close: trashing %d buffer(s)", hb_fifo_size( f ) );
452 while( ( b = hb_fifo_get( f ) ) )
454 hb_buffer_close( &b );
457 hb_lock_close( &f->lock );
458 free( f );
460 *_f = NULL;