~ubuntu-branches/ubuntu/maverick/vlc/maverick

« back to all changes in this revision

Viewing changes to src/misc/block.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2008-09-17 21:56:14 UTC
  • mfrom: (1.1.17 upstream)
  • Revision ID: james.westby@ubuntu.com-20080917215614-tj0vx8xzd57e52t8
Tags: 0.9.2-1ubuntu1
* New Upstream Release, exception granted by
    - dktrkranz, norsetto, Hobbsee (via irc). LP: #270404

Changes done in ubuntu:

* add libxul-dev to build-depends
* make sure that vlc is build against libxul in configure. This doesn't
  change anything in the package, but makes it more robust if building
  in an 'unclean' chroot or when modifying the package.
* debian/control: make Vcs-* fields point to the motumedia branch
* add libx264-dev and libass-dev to build-depends
  LP: #210354, #199870
* actually enable libass support by passing --enable-libass to configure
* enable libdca: add libdca-dev to build depends and --enable-libdca
* install the x264 plugin.

Changes already in the pkg-multimedia branch in debian:

* don't install usr/share/vlc/mozilla in debian/mozilla-plugin-vlc.install  
* new upstream .desktop file now registers flash video mimetype LP: #261567
* add Xb-Npp-Applications to mozilla-plugin-vlc
* remove duplicate entries in debian/vlc-nox.install

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$
 
5
 * $Id: 3909d33bb232b2737a7369c47c4779f6ac6b4663 $
6
6
 *
7
7
 * Authors: Laurent Aimar <fenrir@videolan.org>
8
8
 *
24
24
/*****************************************************************************
25
25
 * Preamble
26
26
 *****************************************************************************/
27
 
#include <stdlib.h>
 
27
#ifdef HAVE_CONFIG_H
 
28
# include "config.h"
 
29
#endif
28
30
 
29
 
#include <vlc/vlc.h>
 
31
#include <vlc_common.h>
 
32
#include <sys/stat.h>
30
33
#include "vlc_block.h"
31
34
 
32
35
/*****************************************************************************
35
38
/* private */
36
39
struct block_sys_t
37
40
{
38
 
    uint8_t     *p_allocated_buffer;
39
 
    int         i_allocated_buffer;
 
41
    block_t     self;
 
42
    size_t      i_allocated_buffer;
 
43
    uint8_t     p_allocated_buffer[0];
40
44
};
41
45
 
 
46
#ifndef NDEBUG
 
47
static void BlockNoRelease( block_t *b )
 
48
{
 
49
    fprintf( stderr, "block %p has no release callback! This is a bug!\n", b );
 
50
    abort();
 
51
}
 
52
#endif
 
53
 
 
54
void block_Init( block_t *restrict b, void *buf, size_t size )
 
55
{
 
56
    /* Fill all fields to their default */
 
57
    b->p_next = b->p_prev = NULL;
 
58
    b->i_flags = 0;
 
59
    b->i_pts = b->i_dts = b->i_length = 0;
 
60
    b->i_rate = 0;
 
61
    b->p_buffer = buf;
 
62
    b->i_buffer = size;
 
63
#ifndef NDEBUG
 
64
    b->pf_release = BlockNoRelease;
 
65
#endif
 
66
}
 
67
 
 
68
static void BlockRelease( block_t *p_block )
 
69
{
 
70
    free( p_block );
 
71
}
 
72
 
 
73
/* Memory alignment */
 
74
#define BLOCK_ALIGN        16
 
75
/* Initial size of reserved header and footer */
42
76
#define BLOCK_PADDING_SIZE 32
43
 
static void BlockRelease( block_t * );
 
77
/* Maximum size of reserved footer before we release with realloc() */
 
78
#define BLOCK_WASTE_SIZE   2048
44
79
 
45
 
block_t *__block_New( vlc_object_t *p_obj, int i_size )
 
80
block_t *block_Alloc( size_t i_size )
46
81
{
47
82
    /* We do only one malloc
48
 
     * TODO bench if doing 2 malloc but keeping a pool of buffer is better
 
83
     * TODO: bench if doing 2 malloc but keeping a pool of buffer is better
 
84
     * TODO: use memalign
49
85
     * 16 -> align on 16
50
86
     * 2 * BLOCK_PADDING_SIZE -> pre + post padding
51
87
     */
52
 
    block_sys_t *p_sys;
53
 
    const int i_alloc = i_size + 2 * BLOCK_PADDING_SIZE + 16;
54
 
    block_t *p_block =
55
 
        malloc( sizeof( block_t ) + sizeof( block_sys_t ) + i_alloc );
 
88
    const size_t i_alloc = i_size + 2 * BLOCK_PADDING_SIZE + BLOCK_ALIGN;
 
89
    block_sys_t *p_sys = malloc( sizeof( *p_sys ) + i_alloc );
56
90
 
57
 
    if( p_block == NULL ) return NULL;
 
91
    if( p_sys == NULL )
 
92
        return NULL;
58
93
 
59
94
    /* Fill opaque data */
60
 
    p_sys = (block_sys_t*)( (uint8_t*)p_block + sizeof( block_t ) );
61
95
    p_sys->i_allocated_buffer = i_alloc;
62
 
    p_sys->p_allocated_buffer = (uint8_t*)p_block + sizeof( block_t ) +
63
 
        sizeof( block_sys_t );
64
 
 
65
 
    /* Fill all fields */
66
 
    p_block->p_next         = NULL;
67
 
    p_block->p_prev         = NULL;
68
 
    p_block->i_flags        = 0;
69
 
    p_block->i_pts          = 0;
70
 
    p_block->i_dts          = 0;
71
 
    p_block->i_length       = 0;
72
 
    p_block->i_rate         = 0;
73
 
    p_block->i_buffer       = i_size;
74
 
    p_block->p_buffer       =
75
 
        &p_sys->p_allocated_buffer[BLOCK_PADDING_SIZE +
76
 
            16 - ((uintptr_t)p_sys->p_allocated_buffer % 16 )];
77
 
    p_block->pf_release     = BlockRelease;
78
 
 
79
 
    /* Is ok, as no comunication between p_vlc */
80
 
    p_block->p_manager      = VLC_OBJECT( p_obj->p_vlc );
81
 
    p_block->p_sys          = p_sys;
82
 
 
83
 
    return p_block;
 
96
 
 
97
    block_Init( &p_sys->self, p_sys->p_allocated_buffer + BLOCK_PADDING_SIZE
 
98
                + BLOCK_ALIGN
 
99
                - ((uintptr_t)p_sys->p_allocated_buffer % BLOCK_ALIGN),
 
100
                i_size );
 
101
    p_sys->self.pf_release    = BlockRelease;
 
102
 
 
103
    return &p_sys->self;
84
104
}
85
105
 
86
 
block_t *block_Realloc( block_t *p_block, int i_prebody, int i_body )
 
106
block_t *block_Realloc( block_t *p_block, ssize_t i_prebody, size_t i_body )
87
107
{
88
 
    int i_buffer_size;
 
108
    block_sys_t *p_sys = (block_sys_t *)p_block;
 
109
    ssize_t i_buffer_size = i_prebody + i_body;
 
110
 
 
111
    if( i_buffer_size <= 0 )
 
112
    {
 
113
        block_Release( p_block );
 
114
        return NULL;
 
115
    }
89
116
 
90
117
    if( p_block->pf_release != BlockRelease )
91
118
    {
92
119
        /* Special case when pf_release if overloaded
93
 
         * TODO if used one day, them implement it in a smarter way */
 
120
         * TODO if used one day, then implement it in a smarter way */
94
121
        block_t *p_dup = block_Duplicate( p_block );
95
122
        block_Release( p_block );
 
123
        if( !p_dup )
 
124
            return NULL;
96
125
 
97
126
        p_block = p_dup;
98
127
    }
99
128
 
100
 
    i_buffer_size = i_prebody + i_body;
101
 
 
102
 
    if( i_body < 0 || i_buffer_size <= 0 )
103
 
    {
104
 
        block_Release( p_block );
105
 
        return NULL;
106
 
    }
107
 
 
108
 
    if( p_block->p_buffer - i_prebody > p_block->p_sys->p_allocated_buffer &&
109
 
        p_block->p_buffer - i_prebody < p_block->p_sys->p_allocated_buffer +
110
 
        p_block->p_sys->i_allocated_buffer )
 
129
    /* Adjust reserved header if there is enough room */
 
130
    if( p_block->p_buffer - i_prebody > p_sys->p_allocated_buffer &&
 
131
        p_block->p_buffer - i_prebody < p_sys->p_allocated_buffer +
 
132
        p_sys->i_allocated_buffer )
111
133
    {
112
134
        p_block->p_buffer -= i_prebody;
113
135
        p_block->i_buffer += i_prebody;
114
136
        i_prebody = 0;
115
137
    }
116
 
    if( p_block->p_buffer + i_body < p_block->p_sys->p_allocated_buffer +
117
 
        p_block->p_sys->i_allocated_buffer )
 
138
 
 
139
    /* Adjust payload size if there is enough room */
 
140
    if( p_block->p_buffer + i_body < p_sys->p_allocated_buffer +
 
141
        p_sys->i_allocated_buffer )
118
142
    {
119
143
        p_block->i_buffer = i_buffer_size;
120
144
        i_body = 0;
121
145
    }
122
146
 
 
147
    /* Not enough room, reallocate the buffer */
123
148
    if( i_body > 0 || i_prebody > 0 )
124
149
    {
125
 
        block_t *p_rea = block_New( p_block->p_manager, i_buffer_size );
126
 
 
127
 
        p_rea->i_dts     = p_block->i_dts;
128
 
        p_rea->i_pts     = p_block->i_pts;
129
 
        p_rea->i_flags   = p_block->i_flags;
130
 
        p_rea->i_length  = p_block->i_length;
131
 
        p_rea->i_rate    = p_block->i_rate;
132
 
        p_rea->i_samples = p_block->i_samples;
133
 
 
134
 
        memcpy( p_rea->p_buffer + i_prebody, p_block->p_buffer,
135
 
                __MIN( p_block->i_buffer, p_rea->i_buffer - i_prebody ) );
 
150
        /* FIXME: this is really dumb, we should use realloc() */
 
151
        block_t *p_rea = block_New( NULL, i_buffer_size );
 
152
 
 
153
        if( p_rea )
 
154
        {
 
155
            p_rea->i_dts     = p_block->i_dts;
 
156
            p_rea->i_pts     = p_block->i_pts;
 
157
            p_rea->i_flags   = p_block->i_flags;
 
158
            p_rea->i_length  = p_block->i_length;
 
159
            p_rea->i_rate    = p_block->i_rate;
 
160
            p_rea->i_samples = p_block->i_samples;
 
161
 
 
162
            memcpy( p_rea->p_buffer + i_prebody, p_block->p_buffer,
 
163
                    __MIN( p_block->i_buffer, p_rea->i_buffer - i_prebody ) );
 
164
        }
136
165
 
137
166
        block_Release( p_block );
138
167
 
139
168
        return p_rea;
140
169
    }
141
170
 
 
171
    /* We have a very large reserved footer now? Release some of it. */
 
172
    if ((p_sys->p_allocated_buffer + p_sys->i_allocated_buffer) -
 
173
        (p_block->p_buffer + p_block->i_buffer) > BLOCK_WASTE_SIZE)
 
174
    {
 
175
        const size_t news = p_block->i_buffer + 2 * BLOCK_PADDING_SIZE + 16;
 
176
        block_sys_t *newb = realloc (p_sys, sizeof (*p_sys) + news);
 
177
 
 
178
        if (newb != NULL)
 
179
        {
 
180
            p_sys = newb;
 
181
            p_sys->i_allocated_buffer = news;
 
182
            p_block = &p_sys->self;
 
183
            p_block->p_buffer = p_sys->p_allocated_buffer + BLOCK_PADDING_SIZE
 
184
                + BLOCK_ALIGN
 
185
                - ((uintptr_t)p_sys->p_allocated_buffer % BLOCK_ALIGN);
 
186
        }
 
187
    }
142
188
    return p_block;
143
189
}
144
190
 
145
 
static void BlockRelease( block_t *p_block )
146
 
{
147
 
    free( p_block );
148
 
}
149
 
 
 
191
#ifdef HAVE_MMAP
 
192
# include <sys/mman.h>
 
193
 
 
194
typedef struct block_mmap_t
 
195
{
 
196
    block_t     self;
 
197
    void       *base_addr;
 
198
    size_t      length;
 
199
} block_mmap_t;
 
200
 
 
201
static void block_mmap_Release (block_t *block)
 
202
{
 
203
    block_mmap_t *p_sys = (block_mmap_t *)block;
 
204
 
 
205
    munmap (p_sys->base_addr, p_sys->length);
 
206
    free (p_sys);
 
207
}
 
208
 
 
209
/**
 
210
 * Creates a block from a virtual address memory mapping (mmap).
 
211
 * This is provided by LibVLC so that mmap blocks can safely be deallocated
 
212
 * even after the allocating plugin has been unloaded from memory.
 
213
 *
 
214
 * @param addr base address of the mapping (as returned by mmap)
 
215
 * @param length length (bytes) of the mapping (as passed to mmap)
 
216
 * @return NULL if addr is MAP_FAILED, or an error occurred (in the later
 
217
 * case, munmap(addr, length) is invoked before returning).
 
218
 */
 
219
block_t *block_mmap_Alloc (void *addr, size_t length)
 
220
{
 
221
    if (addr == MAP_FAILED)
 
222
        return NULL;
 
223
 
 
224
    block_mmap_t *block = malloc (sizeof (*block));
 
225
    if (block == NULL)
 
226
    {
 
227
        munmap (addr, length);
 
228
        return NULL;
 
229
    }
 
230
 
 
231
    block_Init (&block->self, (uint8_t *)addr, length);
 
232
    block->self.pf_release = block_mmap_Release;
 
233
    block->base_addr = addr;
 
234
    block->length = length;
 
235
    return &block->self;
 
236
}
 
237
#else
 
238
block_t *block_mmap_Alloc (void *addr, size_t length)
 
239
{
 
240
    (void)addr; (void)length; return NULL;
 
241
}
 
242
#endif
 
243
 
 
244
 
 
245
#ifdef WIN32
 
246
static
 
247
ssize_t pread (int fd, void *buf, size_t count, off_t offset)
 
248
{
 
249
    HANDLE handle = (HANDLE)(intptr_t)_get_osfhandle (fd);
 
250
    if (handle == INVALID_HANDLE_VALUE)
 
251
        return -1;
 
252
 
 
253
    OVERLAPPED olap = { .Offset = offset, .OffsetHigh = (offset >> 32), };
 
254
    DWORD written;
 
255
    /* This braindead API will override the file pointer even if we specify
 
256
     * an explicit read offset... So do not expect this to mix well with
 
257
     * regular read() calls. */
 
258
    if (ReadFile (handle, buf, count, &written, &olap))
 
259
        return written;
 
260
    return -1;
 
261
}
 
262
#endif
 
263
 
 
264
/**
 
265
 * Loads a file into a block of memory. If possible a private file mapping is
 
266
 * created. Otherwise, the file is read normally. On 32-bits platforms, this
 
267
 * function will not work for very large files, due to memory space
 
268
 * constraints.
 
269
 *
 
270
 * @param fd file descriptor to load from
 
271
 * @return a new block with the file content at p_buffer, and file length at
 
272
 * i_buffer (release it with block_Release()), or NULL upon error (see errno).
 
273
 */
 
274
block_t *block_File (int fd)
 
275
{
 
276
    size_t length;
 
277
    struct stat st;
 
278
 
 
279
    /* First, get the file size */
 
280
    if (fstat (fd, &st))
 
281
        return NULL;
 
282
 
 
283
    /* st_size is meaningful for regular files, shared memory and typed memory.
 
284
     * It's also meaning for symlinks, but that's not possible with fstat().
 
285
     * In other cases, it's undefined, and we should really not go further. */
 
286
#ifndef S_TYPEISSHM
 
287
# define S_TYPEISSHM( buf ) (0)
 
288
#endif
 
289
    if (S_ISDIR (st.st_mode))
 
290
    {
 
291
        errno = EISDIR;
 
292
        return NULL;
 
293
    }
 
294
    if (!S_ISREG (st.st_mode) && !S_TYPEISSHM (&st))
 
295
    {
 
296
        errno = ESPIPE;
 
297
        return NULL;
 
298
    }
 
299
 
 
300
    /* Prevent an integer overflow in mmap() and malloc() */
 
301
    if (st.st_size >= SIZE_MAX)
 
302
    {
 
303
        errno = ENOMEM;
 
304
        return NULL;
 
305
    }
 
306
    length = (size_t)st.st_size;
 
307
 
 
308
#ifdef HAVE_MMAP
 
309
    if (length > 0)
 
310
    {
 
311
        void *addr;
 
312
 
 
313
        addr = mmap (NULL, length, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
 
314
        if (addr != MAP_FAILED)
 
315
            return block_mmap_Alloc (addr, length);
 
316
    }
 
317
#endif
 
318
 
 
319
    /* If mmap() is not implemented by the OS _or_ the filesystem... */
 
320
    block_t *block = block_Alloc (length);
 
321
    if (block == NULL)
 
322
        return NULL;
 
323
 
 
324
    for (size_t i = 0; i < length;)
 
325
    {
 
326
        ssize_t len = pread (fd, block->p_buffer + i, length - i, i);
 
327
        if (len == -1)
 
328
        {
 
329
            block_Release (block);
 
330
            return NULL;
 
331
        }
 
332
        i += len;
 
333
    }
 
334
    return block;
 
335
}
150
336
 
151
337
/*****************************************************************************
152
338
 * block_fifo_t management
153
339
 *****************************************************************************/
154
 
block_fifo_t *__block_FifoNew( vlc_object_t *p_obj )
155
 
{
156
 
    block_fifo_t *p_fifo;
157
 
 
158
 
    p_fifo = malloc( sizeof( block_fifo_t ) );
159
 
    vlc_mutex_init( p_obj, &p_fifo->lock );
160
 
    vlc_cond_init( p_obj, &p_fifo->wait );
161
 
    p_fifo->i_depth = p_fifo->i_size = 0;
 
340
struct block_fifo_t
 
341
{
 
342
    vlc_mutex_t         lock;                         /* fifo data lock */
 
343
    vlc_cond_t          wait;         /* fifo data conditional variable */
 
344
 
 
345
    block_t             *p_first;
 
346
    block_t             **pp_last;
 
347
    size_t              i_depth;
 
348
    size_t              i_size;
 
349
    bool          b_force_wake;
 
350
};
 
351
 
 
352
block_fifo_t *block_FifoNew( void )
 
353
{
 
354
    block_fifo_t *p_fifo = malloc( sizeof( block_fifo_t ) );
 
355
    if( !p_fifo )
 
356
        return NULL;
 
357
 
 
358
    vlc_mutex_init( &p_fifo->lock );
 
359
    vlc_cond_init( NULL, &p_fifo->wait );
162
360
    p_fifo->p_first = NULL;
163
361
    p_fifo->pp_last = &p_fifo->p_first;
 
362
    p_fifo->i_depth = p_fifo->i_size = 0;
 
363
    p_fifo->b_force_wake = false;
164
364
 
165
365
    return p_fifo;
166
366
}
193
393
    vlc_mutex_unlock( &p_fifo->lock );
194
394
}
195
395
 
196
 
int block_FifoPut( block_fifo_t *p_fifo, block_t *p_block )
 
396
size_t block_FifoPut( block_fifo_t *p_fifo, block_t *p_block )
197
397
{
198
 
    int i_size = 0;
 
398
    size_t i_size = 0;
199
399
    vlc_mutex_lock( &p_fifo->lock );
200
400
 
201
401
    do
218
418
    return i_size;
219
419
}
220
420
 
 
421
void block_FifoWake( block_fifo_t *p_fifo )
 
422
{
 
423
    vlc_mutex_lock( &p_fifo->lock );
 
424
    if( p_fifo->p_first == NULL )
 
425
        p_fifo->b_force_wake = true;
 
426
    vlc_cond_signal( &p_fifo->wait );
 
427
    vlc_mutex_unlock( &p_fifo->lock );
 
428
}
 
429
 
221
430
block_t *block_FifoGet( block_fifo_t *p_fifo )
222
431
{
223
432
    block_t *b;
224
433
 
225
434
    vlc_mutex_lock( &p_fifo->lock );
226
435
 
227
 
    /* We do a while here because there is a race condition in the
228
 
     * win32 implementation of vlc_cond_wait() (We can't be sure the fifo
229
 
     * hasn't been emptied again since we were signaled). */
230
 
    while( p_fifo->p_first == NULL )
 
436
    /* Remember vlc_cond_wait() may cause spurious wakeups
 
437
     * (on both Win32 and POSIX) */
 
438
    while( ( p_fifo->p_first == NULL ) && !p_fifo->b_force_wake )
231
439
    {
232
440
        vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
233
441
    }
234
442
 
235
443
    b = p_fifo->p_first;
236
444
 
 
445
    p_fifo->b_force_wake = false;
 
446
    if( b == NULL )
 
447
    {
 
448
        /* Forced wakeup */
 
449
        vlc_mutex_unlock( &p_fifo->lock );
 
450
        return NULL;
 
451
    }
 
452
 
237
453
    p_fifo->p_first = b->p_next;
238
454
    p_fifo->i_depth--;
239
455
    p_fifo->i_size -= b->i_buffer;
265
481
    vlc_mutex_unlock( &p_fifo->lock );
266
482
 
267
483
    return( b );
268
 
 
269
 
}
270
 
 
 
484
}
 
485
 
 
486
size_t block_FifoSize( const block_fifo_t *p_fifo )
 
487
{
 
488
    return p_fifo->i_size;
 
489
}
 
490
 
 
491
size_t block_FifoCount( const block_fifo_t *p_fifo )
 
492
{
 
493
    return p_fifo->i_depth;
 
494
}