~ubuntu-branches/ubuntu/natty/vlc/natty

« back to all changes in this revision

Viewing changes to src/misc/block.c

  • Committer: Bazaar Package Importer
  • Author(s): Benjamin Drung
  • Date: 2010-06-25 01:09:16 UTC
  • mfrom: (1.1.30 upstream)
  • Revision ID: james.westby@ubuntu.com-20100625010916-asxhep2mutg6g6pd
Tags: 1.1.0-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - build and install the libx264 plugin
  - add Xb-Npp header to vlc package
  - Add apport hook to include more vlc dependencies in bug reports
* Drop xulrunner patches.
* Drop 502_xulrunner_191.diff.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * block.c: Data blocks management functions
3
3
 *****************************************************************************
4
4
 * Copyright (C) 2003-2004 the VideoLAN team
5
 
 * $Id: 099c31e226f403a3fe1dd552c37a44d56427b696 $
 
5
 * Copyright (C) 2007-2009 Rémi Denis-Courmont
6
6
 *
7
7
 * Authors: Laurent Aimar <fenrir@videolan.org>
8
8
 *
30
30
 
31
31
#include <vlc_common.h>
32
32
#include <sys/stat.h>
 
33
#include <assert.h>
 
34
#include <errno.h>
33
35
#include "vlc_block.h"
34
36
 
35
37
/**
63
65
    b->i_dts = VLC_TS_INVALID;
64
66
    b->i_length = 0;
65
67
    b->i_rate = 0;
 
68
    b->i_nb_samples = 0;
66
69
    b->p_buffer = buf;
67
70
    b->i_buffer = size;
68
71
#ifndef NDEBUG
75
78
    free( p_block );
76
79
}
77
80
 
78
 
/* Memory alignment */
 
81
static void BlockMetaCopy( block_t *restrict out, const block_t *in )
 
82
{
 
83
    out->p_next    = in->p_next;
 
84
    out->i_dts     = in->i_dts;
 
85
    out->i_pts     = in->i_pts;
 
86
    out->i_flags   = in->i_flags;
 
87
    out->i_length  = in->i_length;
 
88
    out->i_rate    = in->i_rate;
 
89
    out->i_nb_samples = in->i_nb_samples;
 
90
}
 
91
 
 
92
/* Memory alignment (must be a multiple of sizeof(void*) and a power of two) */
79
93
#define BLOCK_ALIGN        16
80
 
/* Initial size of reserved header and footer */
81
 
#define BLOCK_PADDING_SIZE 32
 
94
/* Initial reserved header and footer size (must be multiple of alignment) */
 
95
#define BLOCK_PADDING      32
82
96
/* Maximum size of reserved footer before we release with realloc() */
83
97
#define BLOCK_WASTE_SIZE   2048
84
98
 
86
100
{
87
101
    /* We do only one malloc
88
102
     * TODO: bench if doing 2 malloc but keeping a pool of buffer is better
89
 
     * TODO: use memalign
90
 
     * 16 -> align on 16
91
 
     * 2 * BLOCK_PADDING_SIZE -> pre + post padding
 
103
     * 2 * BLOCK_PADDING -> pre + post padding
92
104
     */
93
 
    const size_t i_alloc = i_size + 2 * BLOCK_PADDING_SIZE + BLOCK_ALIGN;
94
 
    block_sys_t *p_sys = malloc( sizeof( *p_sys ) + i_alloc );
95
 
 
 
105
    block_sys_t *p_sys;
 
106
    uint8_t *buf;
 
107
 
 
108
#define ALIGN(x) (((x) + BLOCK_ALIGN - 1) & ~(BLOCK_ALIGN - 1))
 
109
#if 0 /*def HAVE_POSIX_MEMALIGN */
 
110
    /* posix_memalign(,16,) is much slower than malloc() on glibc.
 
111
     * -- Courmisch, September 2009, glibc 2.5 & 2.9 */
 
112
    const size_t i_alloc = ALIGN(sizeof(*p_sys)) + (2 * BLOCK_PADDING)
 
113
                         + ALIGN(i_size);
 
114
    void *ptr;
 
115
 
 
116
    if( posix_memalign( &ptr, BLOCK_ALIGN, i_alloc ) )
 
117
        return NULL;
 
118
 
 
119
    p_sys = ptr;
 
120
    buf = p_sys->p_allocated_buffer + (-sizeof(*p_sys) & (BLOCK_ALIGN - 1));
 
121
 
 
122
#else
 
123
    const size_t i_alloc = sizeof(*p_sys) + BLOCK_ALIGN + (2 * BLOCK_PADDING)
 
124
                         + ALIGN(i_size);
 
125
    p_sys = malloc( i_alloc );
96
126
    if( p_sys == NULL )
97
127
        return NULL;
98
128
 
 
129
    buf = (void *)ALIGN((uintptr_t)p_sys->p_allocated_buffer);
 
130
 
 
131
#endif
 
132
    buf += BLOCK_PADDING;
 
133
 
 
134
    block_Init( &p_sys->self, buf, i_size );
 
135
    p_sys->self.pf_release    = BlockRelease;
99
136
    /* Fill opaque data */
100
 
    p_sys->i_allocated_buffer = i_alloc;
101
 
 
102
 
    block_Init( &p_sys->self, p_sys->p_allocated_buffer + BLOCK_PADDING_SIZE
103
 
                + BLOCK_ALIGN
104
 
                - ((uintptr_t)p_sys->p_allocated_buffer % BLOCK_ALIGN),
105
 
                i_size );
106
 
    p_sys->self.pf_release    = BlockRelease;
 
137
    p_sys->i_allocated_buffer = i_alloc - sizeof(*p_sys);
107
138
 
108
139
    return &p_sys->self;
109
140
}
111
142
block_t *block_Realloc( block_t *p_block, ssize_t i_prebody, size_t i_body )
112
143
{
113
144
    block_sys_t *p_sys = (block_sys_t *)p_block;
114
 
    ssize_t i_buffer_size = i_prebody + i_body;
 
145
    size_t requested = i_prebody + i_body;
115
146
 
116
 
    if( i_buffer_size <= 0 )
 
147
    /* Corner case: empty block requested */
 
148
    if( i_prebody <= 0 && i_body <= (size_t)(-i_prebody) )
117
149
    {
118
150
        block_Release( p_block );
119
151
        return NULL;
132
164
        p_sys = (block_sys_t *)p_block;
133
165
    }
134
166
 
135
 
    /* Adjust reserved header if there is enough room */
136
 
    if( p_block->p_buffer - i_prebody > p_sys->p_allocated_buffer &&
137
 
        p_block->p_buffer - i_prebody < p_sys->p_allocated_buffer +
138
 
        p_sys->i_allocated_buffer )
139
 
    {
140
 
        p_block->p_buffer -= i_prebody;
141
 
        p_block->i_buffer += i_prebody;
142
 
        i_prebody = 0;
143
 
    }
144
 
 
145
 
    /* Adjust payload size if there is enough room */
146
 
    if( p_block->p_buffer + i_body < p_sys->p_allocated_buffer +
147
 
        p_sys->i_allocated_buffer )
148
 
    {
149
 
        p_block->i_buffer = i_buffer_size;
150
 
        i_body = 0;
151
 
    }
152
 
 
153
 
    /* Not enough room, reallocate the buffer */
154
 
    if( i_body > 0 || i_prebody > 0 )
155
 
    {
156
 
        /* FIXME: this is really dumb, we should use realloc() */
157
 
        block_t *p_rea = block_New( NULL, i_buffer_size );
158
 
 
 
167
    uint8_t *p_start = p_sys->p_allocated_buffer;
 
168
    uint8_t *p_end = p_sys->p_allocated_buffer + p_sys->i_allocated_buffer;
 
169
 
 
170
    assert( p_block->p_buffer + p_block->i_buffer <= p_end );
 
171
    assert( p_block->p_buffer >= p_start );
 
172
 
 
173
    /* Corner case: the current payload is discarded completely */
 
174
    if( i_prebody <= 0 && p_block->i_buffer <= (size_t)-i_prebody )
 
175
         p_block->i_buffer = 0; /* discard current payload */
 
176
    if( p_block->i_buffer == 0 )
 
177
    {
 
178
        size_t available = p_end - p_start;
 
179
 
 
180
        if( requested <= available )
 
181
        {   /* Enough room: recycle buffer */
 
182
            size_t extra = available - requested;
 
183
 
 
184
            p_block->p_buffer = p_start + (extra / 2);
 
185
            p_block->i_buffer = requested;
 
186
            return p_block;
 
187
        }
 
188
        /* Not enough room: allocate a new buffer */
 
189
        block_t *p_rea = block_Alloc( requested );
159
190
        if( p_rea )
160
 
        {
161
 
            p_rea->i_dts     = p_block->i_dts;
162
 
            p_rea->i_pts     = p_block->i_pts;
163
 
            p_rea->i_flags   = p_block->i_flags;
164
 
            p_rea->i_length  = p_block->i_length;
165
 
            p_rea->i_rate    = p_block->i_rate;
166
 
            p_rea->i_samples = p_block->i_samples;
167
 
 
168
 
            memcpy( p_rea->p_buffer + i_prebody, p_block->p_buffer,
169
 
                    __MIN( p_block->i_buffer, p_rea->i_buffer - i_prebody ) );
170
 
        }
171
 
 
 
191
            BlockMetaCopy( p_rea, p_block );
172
192
        block_Release( p_block );
173
 
 
174
193
        return p_rea;
175
194
    }
176
195
 
 
196
    /* First, shrink payload */
 
197
 
 
198
    /* Pull payload start */
 
199
    if( i_prebody < 0 )
 
200
    {
 
201
        assert( p_block->i_buffer >= (size_t)-i_prebody );
 
202
        p_block->p_buffer -= i_prebody;
 
203
        p_block->i_buffer += i_prebody;
 
204
        i_body += i_prebody;
 
205
        i_prebody = 0;
 
206
    }
 
207
 
 
208
    /* Trim payload end */
 
209
    if( p_block->i_buffer > i_body )
 
210
        p_block->i_buffer = i_body;
 
211
 
 
212
    /* Second, reallocate the buffer if we lack space. This is done now to
 
213
     * minimize the payload size for memory copy. */
 
214
    assert( i_prebody >= 0 );
 
215
    if( (size_t)(p_block->p_buffer - p_start) < (size_t)i_prebody
 
216
     || (size_t)(p_end - p_block->p_buffer) < i_body )
 
217
    {
 
218
        block_t *p_rea = block_Alloc( requested );
 
219
        if( p_rea )
 
220
        {
 
221
            BlockMetaCopy( p_rea, p_block );
 
222
            p_rea->p_buffer += i_prebody;
 
223
            p_rea->i_buffer -= i_prebody;
 
224
            memcpy( p_rea->p_buffer, p_block->p_buffer, p_block->i_buffer );
 
225
        }
 
226
        block_Release( p_block );
 
227
        if( p_rea == NULL )
 
228
            return NULL;
 
229
        p_block = p_rea;
 
230
    }
 
231
    else
177
232
    /* We have a very large reserved footer now? Release some of it.
178
 
     * XXX it may not keep the algniment of p_buffer */
179
 
    if( (p_sys->p_allocated_buffer + p_sys->i_allocated_buffer) -
180
 
        (p_block->p_buffer + p_block->i_buffer) > BLOCK_WASTE_SIZE )
 
233
     * XXX it might not preserve the alignment of p_buffer */
 
234
    if( p_end - (p_block->p_buffer + i_body) > BLOCK_WASTE_SIZE )
181
235
    {
182
 
        const ptrdiff_t i_prebody = p_block->p_buffer - p_sys->p_allocated_buffer;
183
 
        const size_t i_new = i_prebody + p_block->i_buffer + 1 * BLOCK_PADDING_SIZE;
184
 
        block_sys_t *p_new = realloc( p_sys, sizeof (*p_sys) + i_new );
185
 
 
186
 
        if( p_new != NULL )
 
236
        block_t *p_rea = block_Alloc( requested );
 
237
        if( p_rea )
187
238
        {
188
 
            p_sys = p_new;
189
 
            p_sys->i_allocated_buffer = i_new;
190
 
            p_block = &p_sys->self;
191
 
            p_block->p_buffer = &p_sys->p_allocated_buffer[i_prebody];
 
239
            BlockMetaCopy( p_rea, p_block );
 
240
            p_rea->p_buffer += i_prebody;
 
241
            p_rea->i_buffer -= i_prebody;
 
242
            memcpy( p_rea->p_buffer, p_block->p_buffer, p_block->i_buffer );
 
243
            block_Release( p_block );
 
244
            p_block = p_rea;
192
245
        }
193
246
    }
 
247
 
 
248
    /* NOTE: p_start and p_end are corrupted from this point */
 
249
 
 
250
    /* Third, expand payload */
 
251
 
 
252
    /* Push payload start */
 
253
    if( i_prebody > 0 )
 
254
    {
 
255
        p_block->p_buffer -= i_prebody;
 
256
        p_block->i_buffer += i_prebody;
 
257
        i_body += i_prebody;
 
258
        i_prebody = 0;
 
259
    }
 
260
 
 
261
    /* Expand payload to requested size */
 
262
    p_block->i_buffer = i_body;
 
263
 
194
264
    return p_block;
195
265
}
196
266
 
 
267
 
 
268
typedef struct
 
269
{
 
270
    block_t  self;
 
271
    void    *mem;
 
272
} block_heap_t;
 
273
 
 
274
static void block_heap_Release (block_t *self)
 
275
{
 
276
    block_heap_t *block = (block_heap_t *)self;
 
277
 
 
278
    free (block->mem);
 
279
    free (block);
 
280
}
 
281
 
 
282
/**
 
283
 * Creates a block from a heap allocation.
 
284
 * This is provided by LibVLC so that manually heap-allocated blocks can safely
 
285
 * be deallocated even after the origin plugin has been unloaded from memory.
 
286
 *
 
287
 * When block_Release() is called, VLC will free() the specified pointer.
 
288
 *
 
289
 * @param ptr base address of the heap allocation (will be free()'d)
 
290
 * @param addr base address of the useful buffer data
 
291
 * @param length bytes length of the useful buffer datan
 
292
 * @return NULL in case of error (ptr free()'d in that case), or a valid
 
293
 * block_t pointer.
 
294
 */
 
295
block_t *block_heap_Alloc (void *ptr, void *addr, size_t length)
 
296
{
 
297
    block_heap_t *block = malloc (sizeof (*block));
 
298
    if (block == NULL)
 
299
    {
 
300
        free (addr);
 
301
        return NULL;
 
302
    }
 
303
 
 
304
    block_Init (&block->self, (uint8_t *)addr, length);
 
305
    block->self.pf_release = block_heap_Release;
 
306
    block->mem = ptr;
 
307
    return &block->self;
 
308
}
 
309
 
197
310
#ifdef HAVE_MMAP
198
311
# include <sys/mman.h>
199
312
 
260
373
    if (handle == INVALID_HANDLE_VALUE)
261
374
        return -1;
262
375
 
263
 
    OVERLAPPED olap = { .Offset = offset, .OffsetHigh = (offset >> 32), };
 
376
    OVERLAPPED olap; olap.Offset = offset; olap.OffsetHigh = (offset >> 32);
264
377
    DWORD written;
265
378
    /* This braindead API will override the file pointer even if we specify
266
379
     * an explicit read offset... So do not expect this to mix well with
395
508
 
396
509
void block_FifoEmpty( block_fifo_t *p_fifo )
397
510
{
398
 
    block_t *b;
 
511
    block_t *block;
399
512
 
400
513
    vlc_mutex_lock( &p_fifo->lock );
401
 
    for( b = p_fifo->p_first; b != NULL; )
 
514
    block = p_fifo->p_first;
 
515
    if (block != NULL)
402
516
    {
403
 
        block_t *p_next;
404
 
 
405
 
        p_next = b->p_next;
406
 
        block_Release( b );
407
 
        b = p_next;
 
517
        p_fifo->i_depth = p_fifo->i_size = 0;
 
518
        p_fifo->p_first = NULL;
 
519
        p_fifo->pp_last = &p_fifo->p_first;
408
520
    }
409
 
 
410
 
    p_fifo->i_depth = p_fifo->i_size = 0;
411
 
    p_fifo->p_first = NULL;
412
 
    p_fifo->pp_last = &p_fifo->p_first;
413
521
    vlc_cond_broadcast( &p_fifo->wait_room );
414
522
    vlc_mutex_unlock( &p_fifo->lock );
 
523
 
 
524
    while (block != NULL)
 
525
    {
 
526
        block_t *buf;
 
527
 
 
528
        buf = block->p_next;
 
529
        block_Release (block);
 
530
        block = buf;
 
531
    }
415
532
}
416
533
 
417
534
/**
449
566
 * Immediately queue one block at the end of a FIFO.
450
567
 * @param fifo queue
451
568
 * @param block head of a block list to queue (may be NULL)
 
569
 * @return total number of bytes appended to the queue
452
570
 */
453
571
size_t block_FifoPut( block_fifo_t *p_fifo, block_t *p_block )
454
572
{
455
 
    size_t i_size = 0;
456
 
    vlc_mutex_lock( &p_fifo->lock );
 
573
    size_t i_size = 0, i_depth = 0;
 
574
    block_t *p_last;
457
575
 
458
 
    while (p_block != NULL)
 
576
    if (p_block == NULL)
 
577
        return 0;
 
578
    for (p_last = p_block; ; p_last = p_last->p_next)
459
579
    {
460
 
        i_size += p_block->i_buffer;
461
 
 
462
 
        *p_fifo->pp_last = p_block;
463
 
        p_fifo->pp_last = &p_block->p_next;
464
 
        p_fifo->i_depth++;
465
 
        p_fifo->i_size += p_block->i_buffer;
466
 
 
467
 
        p_block = p_block->p_next;
 
580
        i_size += p_last->i_buffer;
 
581
        i_depth++;
 
582
        if (!p_last->p_next)
 
583
            break;
468
584
    }
469
585
 
470
 
    /* We queued one block: wake up one read-waiting thread */
 
586
    vlc_mutex_lock (&p_fifo->lock);
 
587
    *p_fifo->pp_last = p_block;
 
588
    p_fifo->pp_last = &p_last->p_next;
 
589
    p_fifo->i_depth += i_depth;
 
590
    p_fifo->i_size += i_size;
 
591
    /* We queued at least one block: wake up one read-waiting thread */
471
592
    vlc_cond_signal( &p_fifo->wait );
472
593
    vlc_mutex_unlock( &p_fifo->lock );
473
594
 
483
604
    vlc_mutex_unlock( &p_fifo->lock );
484
605
}
485
606
 
 
607
/**
 
608
 * Dequeue the first block from the FIFO. If necessary, wait until there is
 
609
 * one block in the queue. This function is (always) cancellation point.
 
610
 *
 
611
 * @return a valid block, or NULL if block_FifoWake() was called.
 
612
 */
486
613
block_t *block_FifoGet( block_fifo_t *p_fifo )
487
614
{
488
615
    block_t *b;
525
652
    return b;
526
653
}
527
654
 
 
655
/**
 
656
 * Peeks the first block in the FIFO.
 
657
 * If necessary, wait until there is one block.
 
658
 * This function is (always) a cancellation point.
 
659
 *
 
660
 * @warning This function leaves the block in the FIFO.
 
661
 * You need to protect against concurrent threads who could dequeue the block.
 
662
 * Preferrably, there should be only one thread reading from the FIFO.
 
663
 *
 
664
 * @return a valid block.
 
665
 */
528
666
block_t *block_FifoShow( block_fifo_t *p_fifo )
529
667
{
530
668
    block_t *b;