libmp4.c 108 KB
Newer Older
1
2
3
/*****************************************************************************
 * libmp4.c : LibMP4 library for mp4 module for vlc
 *****************************************************************************
4
 * Copyright (C) 2001-2004, 2010 the VideoLAN team
5
 * $Id$
6
7
 *
 * Author: Laurent Aimar <fenrir@via.ecp.fr>
8
 *
9
10
11
12
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
13
 *
14
15
16
17
18
19
20
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
 *****************************************************************************/
23

24
25
26
27
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

28
#include <vlc_common.h>
zorglub's avatar
zorglub committed
29
#include <vlc_demux.h>
30

31
#ifdef HAVE_ZLIB_H
32
#   include <zlib.h>                                  /* for compressed moov */
33
34
#endif

35
#include "libmp4.h"
36
#include "drms.h"
37
38

/*****************************************************************************
39
 * Here are defined some macro to make life simpler but before using it
40
 * *look* at the code.
41
42
 *
 *****************************************************************************/
43

44
45
46
47
48
49
static inline size_t mp4_box_headersize( MP4_Box_t *p_box )
{
    return 8
        + ( p_box->i_shortsize == 1 ? 8 : 0 )
        + ( p_box->i_type == FOURCC_uuid ? 16 : 0 );
}
50

51
52
53
54
55
#define MP4_GETX_PRIVATE(dst, code, size) do { \
    if( (i_read) >= (size) ) { dst = (code); p_peek += (size); } \
    else { dst = 0; }   \
    i_read -= (size);   \
  } while(0)
56

57
58
59
60
61
62
63
#define MP4_GET1BYTE( dst )  MP4_GETX_PRIVATE( dst, *p_peek, 1 )
#define MP4_GET2BYTES( dst ) MP4_GETX_PRIVATE( dst, GetWBE(p_peek), 2 )
#define MP4_GET3BYTES( dst ) MP4_GETX_PRIVATE( dst, Get24bBE(p_peek), 3 )
#define MP4_GET4BYTES( dst ) MP4_GETX_PRIVATE( dst, GetDWBE(p_peek), 4 )
#define MP4_GET8BYTES( dst ) MP4_GETX_PRIVATE( dst, GetQWBE(p_peek), 8 )
#define MP4_GETFOURCC( dst ) MP4_GETX_PRIVATE( dst, \
                VLC_FOURCC(p_peek[0],p_peek[1],p_peek[2],p_peek[3]), 4)
64

65
66
67
#define MP4_GETVERSIONFLAGS( p_void ) \
    MP4_GET1BYTE( p_void->i_version ); \
    MP4_GET3BYTES( p_void->i_flags )
68

69
70
71
72
#define MP4_GETSTRINGZ( p_str )         \
    if( (i_read > 0) && (p_peek[0]) )   \
    {       \
        const int __i_copy__ = strnlen( (char*)p_peek, i_read-1 );  \
73
        p_str = malloc( __i_copy__+1 );               \
74
75
76
77
78
        if( p_str ) \
        { \
             memcpy( p_str, p_peek, __i_copy__ ); \
             p_str[__i_copy__] = 0; \
        } \
79
80
81
82
83
        p_peek += __i_copy__ + 1;   \
        i_read -= __i_copy__ + 1;   \
    }       \
    else    \
    {       \
84
85
        p_str = NULL; \
    }
86

87
#define MP4_READBOX_ENTER( MP4_Box_data_TYPE_t ) \
zorglub's avatar
zorglub committed
88
    int64_t  i_read = p_box->i_size; \
89
    uint8_t *p_peek, *p_buff; \
zorglub's avatar
zorglub committed
90
    int i_actually_read; \
91
92
93
94
    if( !( p_peek = p_buff = malloc( i_read ) ) ) \
    { \
        return( 0 ); \
    } \
zorglub's avatar
zorglub committed
95
    i_actually_read = stream_Read( p_stream, p_peek, i_read ); \
zorglub's avatar
zorglub committed
96
    if( i_actually_read < 0 || (int64_t)i_actually_read < i_read )\
97
98
99
100
    { \
        free( p_buff ); \
        return( 0 ); \
    } \
101
102
    p_peek += mp4_box_headersize( p_box ); \
    i_read -= mp4_box_headersize( p_box ); \
103
    if( !( p_box->data.p_data = calloc( 1, sizeof( MP4_Box_data_TYPE_t ) ) ) ) \
104
    { \
105
106
        free( p_buff ); \
        return( 0 ); \
107
108
    }

109
#define MP4_READBOX_EXIT( i_code ) \
110
    do \
111
    { \
112
113
114
115
116
        free( p_buff ); \
        if( i_read < 0 ) \
            msg_Warn( p_stream, "Not enough data" ); \
        return( i_code ); \
    } while (0)
117

118

119
/* Some assumptions:
120
 * The input method HAS to be seekable
121

122
123
*/

124
125
126
127
128
129
130
/* This macro is used when we want to printf the box type
 * APPLE annotation box is :
 *  either 0xA9 + 24-bit ASCII text string (and 0xA9 isn't printable)
 *  either 32-bit ASCII text string
 */
#define MP4_BOX_TYPE_ASCII() ( ((char*)&p_box->i_type)[0] != (char)0xA9 )

131
static uint32_t Get24bBE( const uint8_t *p )
132
{
Laurent Aimar's avatar
Laurent Aimar committed
133
    return( ( p[0] <<16 ) + ( p[1] <<8 ) + p[2] );
134
135
}

136
static void GetUUID( UUID_t *p_uuid, const uint8_t *p_buff )
137
{
Laurent Aimar's avatar
Laurent Aimar committed
138
    memcpy( p_uuid, p_buff, 16 );
139
140
}

141
static void CreateUUID( UUID_t *p_uuid, uint32_t i_fourcc )
142
{
143
    /* made by 0xXXXXXXXX-0011-0010-8000-00aa00389b71
144
145
            where XXXXXXXX is the fourcc */
    /* FIXME implement this */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
146
147
    (void)p_uuid;
    (void)i_fourcc;
148
149
150
151
}

/* some functions for mp4 encoding of variables */

Laurent Aimar's avatar
Laurent Aimar committed
152
static void MP4_ConvertDate2Str( char *psz, uint64_t i_date )
153
154
155
156
157
158
{
    int i_day;
    int i_hour;
    int i_min;
    int i_sec;

Laurent Aimar's avatar
Laurent Aimar committed
159
    /* date begin at 1 jan 1904 */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
160
    i_date += ((INT64_C(1904) * 365) + 17) * 24 * 60 * 60;
Laurent Aimar's avatar
Laurent Aimar committed
161

162
163
164
165
    i_day = i_date / ( 60*60*24);
    i_hour = ( i_date /( 60*60 ) ) % 60;
    i_min  = ( i_date / 60 ) % 60;
    i_sec =  i_date % 60;
166
    sprintf( psz, "%dd-%2.2dh:%2.2dm:%2.2ds", i_day, i_hour, i_min, i_sec );
167
168
}

Laurent Aimar's avatar
Laurent Aimar committed
169
170
171
/*****************************************************************************
 * Some prototypes.
 *****************************************************************************/
sigmunau's avatar
sigmunau committed
172
static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father );
173
174
175


/*****************************************************************************
176
 * MP4_ReadBoxCommon : Load only common parameters for all boxes
177
 *****************************************************************************
178
 * p_box need to be an already allocated MP4_Box_t, and all data
179
180
181
182
 *  will only be peek not read
 *
 * RETURN : 0 if it fail, 1 otherwise
 *****************************************************************************/
sigmunau's avatar
sigmunau committed
183
int MP4_ReadBoxCommon( stream_t *p_stream, MP4_Box_t *p_box )
184
{
185
    int      i_read;
186
    const uint8_t  *p_peek;
187

sigmunau's avatar
sigmunau committed
188
    if( ( ( i_read = stream_Peek( p_stream, &p_peek, 32 ) ) < 8 ) )
189
    {
190
        return 0;
191
    }
sigmunau's avatar
sigmunau committed
192
    p_box->i_pos = stream_Tell( p_stream );
193
194
195
196
197
198

    p_box->data.p_data = NULL;
    p_box->p_father = NULL;
    p_box->p_first  = NULL;
    p_box->p_last  = NULL;
    p_box->p_next   = NULL;
199

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    MP4_GET4BYTES( p_box->i_shortsize );
    MP4_GETFOURCC( p_box->i_type );

    /* Now special case */

    if( p_box->i_shortsize == 1 )
    {
        /* get the true size on 64 bits */
        MP4_GET8BYTES( p_box->i_size );
    }
    else
    {
        p_box->i_size = p_box->i_shortsize;
        /* XXX size of 0 means that the box extends to end of file */
    }
215

216
217
218
219
220
221
222
223
224
225
226
227
228
    if( p_box->i_type == FOURCC_uuid )
    {
        /* get extented type on 16 bytes */
        GetUUID( &p_box->i_uuid, p_peek );
        p_peek += 16; i_read -= 16;
    }
    else
    {
        CreateUUID( &p_box->i_uuid, p_box->i_type );
    }
#ifdef MP4_VERBOSE
    if( p_box->i_size )
    {
229
        if MP4_BOX_TYPE_ASCII()
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
230
            msg_Dbg( p_stream, "found Box: %4.4s size %"PRId64,
231
232
                    (char*)&p_box->i_type, p_box->i_size );
        else
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
233
            msg_Dbg( p_stream, "found Box: c%3.3s size %"PRId64,
234
                    (char*)&p_box->i_type+1, p_box->i_size );
235
236
237
    }
#endif

238
    return 1;
239
240
241
}

/*****************************************************************************
242
 * MP4_NextBox : Go to the next box
243
 *****************************************************************************
244
 * if p_box == NULL, go to the next box in which we are( at the begining ).
245
 *****************************************************************************/
sigmunau's avatar
sigmunau committed
246
static int MP4_NextBox( stream_t *p_stream, MP4_Box_t *p_box )
247
248
249
250
251
252
253
254
255
256
257
{
    MP4_Box_t box;

    if( !p_box )
    {
        MP4_ReadBoxCommon( p_stream, &box );
        p_box = &box;
    }

    if( !p_box->i_size )
    {
258
        return 2; /* Box with infinite size */
259
260
261
262
    }

    if( p_box->p_father )
    {
263
264
        const off_t i_box_end = p_box->i_size + p_box->i_pos;
        const off_t i_father_end = p_box->p_father->i_size + p_box->p_father->i_pos;
265

266
        /* check if it's within p-father */
267
        if( i_box_end >= i_father_end )
268
        {
269
270
            if( i_box_end > i_father_end )
                msg_Dbg( p_stream, "out of bound child" );
271
            return 0; /* out of bound */
272
273
        }
    }
sigmunau's avatar
sigmunau committed
274
    if( stream_Seek( p_stream, p_box->i_size + p_box->i_pos ) )
275
276
277
278
279
    {
        return 0;
    }

    return 1;
280
281
282
}

/*****************************************************************************
283
 * For all known box a loader is given,
284
285
 *  XXX: all common struct have to be already read by MP4_ReadBoxCommon
 *       after called one of theses functions, file position is unknown
286
 *       you need to call MP4_GotoBox to go where you want
287
 *****************************************************************************/
sigmunau's avatar
sigmunau committed
288
static int MP4_ReadBoxContainerRaw( stream_t *p_stream, MP4_Box_t *p_container )
289
290
{
    MP4_Box_t *p_box;
291

sigmunau's avatar
sigmunau committed
292
    if( stream_Tell( p_stream ) + 8 >
293
        (off_t)(p_container->i_pos + p_container->i_size) )
294
295
    {
        /* there is no box to load */
296
        return 0;
297
    }
298

299
300
    do
    {
301
302
        if( ( p_box = MP4_ReadBox( p_stream, p_container ) ) == NULL ) break;

Laurent Aimar's avatar
Laurent Aimar committed
303
        /* chain this box with the father and the other at same level */
304
305
        if( !p_container->p_first ) p_container->p_first = p_box;
        else p_container->p_last->p_next = p_box;
Laurent Aimar's avatar
Laurent Aimar committed
306
        p_container->p_last = p_box;
307

Laurent Aimar's avatar
Laurent Aimar committed
308
    } while( MP4_NextBox( p_stream, p_box ) == 1 );
309

310
    return 1;
311
312
}

sigmunau's avatar
sigmunau committed
313
static int MP4_ReadBoxContainer( stream_t *p_stream, MP4_Box_t *p_container )
314
{
315
    if( p_container->i_size <= (size_t)mp4_box_headersize(p_container ) + 8 )
316
317
    {
        /* container is empty, 8 stand for the first header in this box */
318
        return 1;
319
    }
320

321
    /* enter box */
322
    stream_Seek( p_stream, p_container->i_pos +
323
                 mp4_box_headersize( p_container ) );
324

325
    return MP4_ReadBoxContainerRaw( p_stream, p_container );
326
327
}

328
static void MP4_FreeBox_Common( MP4_Box_t *p_box )
329
330
{
    /* Up to now do nothing */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
331
    (void)p_box;
332
333
}

sigmunau's avatar
sigmunau committed
334
static int MP4_ReadBoxSkip( stream_t *p_stream, MP4_Box_t *p_box )
335
{
336
    /* XXX sometime moov is hiden in a free box */
337
338
    if( p_box->p_father &&
        p_box->p_father->i_type == VLC_FOURCC( 'r', 'o', 'o', 't' ) &&
339
340
        p_box->i_type == FOURCC_free )
    {
341
        const uint8_t *p_peek;
342
343
344
        int     i_read;
        vlc_fourcc_t i_fcc;

sigmunau's avatar
sigmunau committed
345
        i_read  = stream_Peek( p_stream, &p_peek, 44 );
346

347
348
        p_peek += mp4_box_headersize( p_box ) + 4;
        i_read -= mp4_box_headersize( p_box ) + 4;
349
350
351
352
353
354
355

        if( i_read >= 8 )
        {
            i_fcc = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] );

            if( i_fcc == FOURCC_cmov || i_fcc == FOURCC_mvhd )
            {
sigmunau's avatar
sigmunau committed
356
                msg_Warn( p_stream, "detected moov hidden in a free box ..." );
357
358
359
360
361
362

                p_box->i_type = FOURCC_foov;
                return MP4_ReadBoxContainer( p_stream, p_box );
            }
        }
    }
363

364
365
    /* Nothing to do */
#ifdef MP4_VERBOSE
366
367
368
369
    if MP4_BOX_TYPE_ASCII()
        msg_Dbg( p_stream, "skip box: \"%4.4s\"", (char*)&p_box->i_type );
    else
        msg_Dbg( p_stream, "skip box: \"c%3.3s\"", (char*)&p_box->i_type+1 );
370
#endif
371
    return 1;
372
373
}

sigmunau's avatar
sigmunau committed
374
static int MP4_ReadBox_ftyp( stream_t *p_stream, MP4_Box_t *p_box )
375
376
{
    MP4_READBOX_ENTER( MP4_Box_data_ftyp_t );
377

378
379
    MP4_GETFOURCC( p_box->data.p_ftyp->i_major_brand );
    MP4_GET4BYTES( p_box->data.p_ftyp->i_minor_version );
380

381
382
    if( ( p_box->data.p_ftyp->i_compatible_brands_count = i_read / 4 ) )
    {
383
        unsigned int i;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
384
385
386
387
388
        uint32_t *tab = p_box->data.p_ftyp->i_compatible_brands =
            calloc( p_box->data.p_ftyp->i_compatible_brands_count,
                    sizeof(uint32_t));

        if( tab == NULL )
389
            MP4_READBOX_EXIT( 0 );
390
391
392

        for( i =0; i < p_box->data.p_ftyp->i_compatible_brands_count; i++ )
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
393
            MP4_GETFOURCC( tab[i] );
394
395
396
397
398
399
400
        }
    }
    else
    {
        p_box->data.p_ftyp->i_compatible_brands = NULL;
    }

401
    MP4_READBOX_EXIT( 1 );
402
403
}

404
static void MP4_FreeBox_ftyp( MP4_Box_t *p_box )
405
{
zorglub's avatar
zorglub committed
406
    FREENULL( p_box->data.p_ftyp->i_compatible_brands );
407
408
409
}


sigmunau's avatar
sigmunau committed
410
static int MP4_ReadBox_mvhd(  stream_t *p_stream, MP4_Box_t *p_box )
411
{
412
    unsigned int i;
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
#ifdef MP4_VERBOSE
    char s_creation_time[128];
    char s_modification_time[128];
    char s_duration[128];
#endif
    MP4_READBOX_ENTER( MP4_Box_data_mvhd_t );

    MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );

    if( p_box->data.p_mvhd->i_version )
    {
        MP4_GET8BYTES( p_box->data.p_mvhd->i_creation_time );
        MP4_GET8BYTES( p_box->data.p_mvhd->i_modification_time );
        MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
        MP4_GET8BYTES( p_box->data.p_mvhd->i_duration );
    }
    else
    {
        MP4_GET4BYTES( p_box->data.p_mvhd->i_creation_time );
        MP4_GET4BYTES( p_box->data.p_mvhd->i_modification_time );
        MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
        MP4_GET4BYTES( p_box->data.p_mvhd->i_duration );
    }
436
437
    MP4_GET4BYTES( p_box->data.p_mvhd->i_rate );
    MP4_GET2BYTES( p_box->data.p_mvhd->i_volume );
438
439
    MP4_GET2BYTES( p_box->data.p_mvhd->i_reserved1 );

440

441
442
443
444
445
446
447
448
449
450
451
452
    for( i = 0; i < 2; i++ )
    {
        MP4_GET4BYTES( p_box->data.p_mvhd->i_reserved2[i] );
    }
    for( i = 0; i < 9; i++ )
    {
        MP4_GET4BYTES( p_box->data.p_mvhd->i_matrix[i] );
    }
    for( i = 0; i < 6; i++ )
    {
        MP4_GET4BYTES( p_box->data.p_mvhd->i_predefined[i] );
    }
453

454
    MP4_GET4BYTES( p_box->data.p_mvhd->i_next_track_id );
455
456


457
458
#ifdef MP4_VERBOSE
    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
459
    MP4_ConvertDate2Str( s_modification_time,
460
461
462
                         p_box->data.p_mvhd->i_modification_time );
    if( p_box->data.p_mvhd->i_rate )
    {
463
        MP4_ConvertDate2Str( s_duration,
464
465
466
467
468
                 p_box->data.p_mvhd->i_duration / p_box->data.p_mvhd->i_rate );
    }
    else
    {
        s_duration[0] = 0;
469
    }
sigmunau's avatar
sigmunau committed
470
    msg_Dbg( p_stream, "read box: \"mvhd\" creation %s modification %s time scale %d duration %s rate %f volume %f next track id %d",
471
472
                  s_creation_time,
                  s_modification_time,
473
                  (uint32_t)p_box->data.p_mvhd->i_timescale,
474
475
476
                  s_duration,
                  (float)p_box->data.p_mvhd->i_rate / (1<<16 ),
                  (float)p_box->data.p_mvhd->i_volume / 256 ,
477
                  (uint32_t)p_box->data.p_mvhd->i_next_track_id );
478
479
480
481
#endif
    MP4_READBOX_EXIT( 1 );
}

482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
static int MP4_ReadBox_mfhd(  stream_t *p_stream, MP4_Box_t *p_box )
{
    MP4_READBOX_ENTER( MP4_Box_data_mfhd_t );

    MP4_GET4BYTES( p_box->data.p_mfhd->i_sequence_number );

#ifdef MP4_VERBOSE
    msg_Dbg( p_stream, "read box: \"mfhd\" sequence number %d",
                  p_box->data.p_mfhd->i_sequence_number );
#endif
    MP4_READBOX_EXIT( 1 );
}

static int MP4_ReadBox_tfhd(  stream_t *p_stream, MP4_Box_t *p_box )
{
    MP4_READBOX_ENTER( MP4_Box_data_tfhd_t );

    MP4_GETVERSIONFLAGS( p_box->data.p_tfhd );

    MP4_GET4BYTES( p_box->data.p_tfhd->i_track_ID );

    if( p_box->data.p_tfhd->i_version == 0 )
    {
        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
            MP4_GET8BYTES( p_box->data.p_tfhd->i_base_data_offset );
        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
            MP4_GET4BYTES( p_box->data.p_tfhd->i_sample_description_index );
        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
            MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_duration );
        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
            MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_size );
        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
            MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_flags );

#ifdef MP4_VERBOSE
        char psz_base[128] = "\0";
        char psz_desc[128] = "\0";
        char psz_dura[128] = "\0";
        char psz_size[128] = "\0";
        char psz_flag[128] = "\0";
        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
            snprintf(psz_base, sizeof(psz_base), "base offset %lld", p_box->data.p_tfhd->i_base_data_offset);
        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
            snprintf(psz_desc, sizeof(psz_desc), "sample description index %d", p_box->data.p_tfhd->i_sample_description_index);
        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
            snprintf(psz_dura, sizeof(psz_dura), "sample duration %d", p_box->data.p_tfhd->i_default_sample_duration);
        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
            snprintf(psz_size, sizeof(psz_size), "sample size %d", p_box->data.p_tfhd->i_default_sample_size);
        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
            snprintf(psz_flag, sizeof(psz_flag), "sample flags 0x%x", p_box->data.p_tfhd->i_default_sample_flags);

        msg_Dbg( p_stream, "read box: \"tfhd\" version %d flags 0x%x track ID %d %s %s %s %s %s",
                    p_box->data.p_tfhd->i_version,
                    p_box->data.p_tfhd->i_flags,
                    p_box->data.p_tfhd->i_track_ID,
                    psz_base, psz_desc, psz_dura, psz_size, psz_flag );
#endif
    }

    MP4_READBOX_EXIT( 1 );
}

static int MP4_ReadBox_trun(  stream_t *p_stream, MP4_Box_t *p_box )
{
    MP4_READBOX_ENTER( MP4_Box_data_trun_t );

    MP4_GETVERSIONFLAGS( p_box->data.p_trun );

    MP4_GET4BYTES( p_box->data.p_trun->i_sample_count );

    if( p_box->data.p_trun->i_flags & MP4_TRUN_DATA_OFFSET )
        MP4_GET8BYTES( p_box->data.p_trun->i_data_offset );
    if( p_box->data.p_trun->i_flags & MP4_TRUN_FIRST_FLAGS )
        MP4_GET4BYTES( p_box->data.p_trun->i_first_sample_flags );

    p_box->data.p_trun->p_samples =
      calloc( p_box->data.p_trun->i_sample_count, sizeof(MP4_descriptor_trun_sample_t) );
    if ( p_box->data.p_trun->p_samples == NULL )
560
        MP4_READBOX_EXIT( 0 );
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599

    for( unsigned int i = 0; i<p_box->data.p_trun->i_sample_count; i++ )
    {
        MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
        if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_DURATION )
            MP4_GET4BYTES( p_sample->i_duration );
        if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_SIZE )
            MP4_GET4BYTES( p_sample->i_size );
        if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_FLAGS )
            MP4_GET4BYTES( p_sample->i_flags );
        if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_TIME_OFFSET )
            MP4_GET4BYTES( p_sample->i_composition_time_offset );
    }

#ifdef MP4_VERBOSE
    msg_Dbg( p_stream, "read box: \"trun\" version %d flags 0x%x sample count %d",
                  p_box->data.p_trun->i_version,
                  p_box->data.p_trun->i_flags,
                  p_box->data.p_trun->i_sample_count );

    for( unsigned int i = 0; i<p_box->data.p_trun->i_sample_count; i++ )
    {
        MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
        msg_Dbg( p_stream, "read box: \"trun\" sample %4.4d flags 0x%x duration %d size %d composition time offset %d",
                        i, p_sample->i_flags, p_sample->i_duration,
                        p_sample->i_size, p_sample->i_composition_time_offset );
    }
#endif

    MP4_READBOX_EXIT( 1 );
}

static void MP4_FreeBox_trun( MP4_Box_t *p_box )
{
    FREENULL( p_box->data.p_trun->p_samples );
}



sigmunau's avatar
sigmunau committed
600
static int MP4_ReadBox_tkhd(  stream_t *p_stream, MP4_Box_t *p_box )
601
{
602
    unsigned int i;
603
604
605
606
607
608
#ifdef MP4_VERBOSE
    char s_creation_time[128];
    char s_modification_time[128];
    char s_duration[128];
#endif
    MP4_READBOX_ENTER( MP4_Box_data_tkhd_t );
609

610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
    MP4_GETVERSIONFLAGS( p_box->data.p_tkhd );

    if( p_box->data.p_tkhd->i_version )
    {
        MP4_GET8BYTES( p_box->data.p_tkhd->i_creation_time );
        MP4_GET8BYTES( p_box->data.p_tkhd->i_modification_time );
        MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
        MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
        MP4_GET8BYTES( p_box->data.p_tkhd->i_duration );
    }
    else
    {
        MP4_GET4BYTES( p_box->data.p_tkhd->i_creation_time );
        MP4_GET4BYTES( p_box->data.p_tkhd->i_modification_time );
        MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
        MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
        MP4_GET4BYTES( p_box->data.p_tkhd->i_duration );
    }
628

629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
    for( i = 0; i < 2; i++ )
    {
        MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved2[i] );
    }
    MP4_GET2BYTES( p_box->data.p_tkhd->i_layer );
    MP4_GET2BYTES( p_box->data.p_tkhd->i_predefined );
    MP4_GET2BYTES( p_box->data.p_tkhd->i_volume );
    MP4_GET2BYTES( p_box->data.p_tkhd->i_reserved3 );

    for( i = 0; i < 9; i++ )
    {
        MP4_GET4BYTES( p_box->data.p_tkhd->i_matrix[i] );
    }
    MP4_GET4BYTES( p_box->data.p_tkhd->i_width );
    MP4_GET4BYTES( p_box->data.p_tkhd->i_height );
644

645
646
647
648
#ifdef MP4_VERBOSE
    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
    MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mvhd->i_modification_time );
    MP4_ConvertDate2Str( s_duration, p_box->data.p_mvhd->i_duration );
649

sigmunau's avatar
sigmunau committed
650
    msg_Dbg( p_stream, "read box: \"tkhd\" creation %s modification %s duration %s track ID %d layer %d volume %f width %f height %f",
651
652
653
654
655
656
657
658
659
660
661
662
663
                  s_creation_time,
                  s_modification_time,
                  s_duration,
                  p_box->data.p_tkhd->i_track_ID,
                  p_box->data.p_tkhd->i_layer,
                  (float)p_box->data.p_tkhd->i_volume / 256 ,
                  (float)p_box->data.p_tkhd->i_width / 65536,
                  (float)p_box->data.p_tkhd->i_height / 65536 );
#endif
    MP4_READBOX_EXIT( 1 );
}


sigmunau's avatar
sigmunau committed
664
static int MP4_ReadBox_mdhd( stream_t *p_stream, MP4_Box_t *p_box )
665
{
666
    unsigned int i;
667
    uint16_t i_language;
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
#ifdef MP4_VERBOSE
    char s_creation_time[128];
    char s_modification_time[128];
    char s_duration[128];
#endif
    MP4_READBOX_ENTER( MP4_Box_data_mdhd_t );

    MP4_GETVERSIONFLAGS( p_box->data.p_mdhd );

    if( p_box->data.p_mdhd->i_version )
    {
        MP4_GET8BYTES( p_box->data.p_mdhd->i_creation_time );
        MP4_GET8BYTES( p_box->data.p_mdhd->i_modification_time );
        MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
        MP4_GET8BYTES( p_box->data.p_mdhd->i_duration );
    }
    else
    {
        MP4_GET4BYTES( p_box->data.p_mdhd->i_creation_time );
        MP4_GET4BYTES( p_box->data.p_mdhd->i_modification_time );
        MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
        MP4_GET4BYTES( p_box->data.p_mdhd->i_duration );
    }
691
    p_box->data.p_mdhd->i_language_code = i_language = GetWBE( p_peek );
692
693
    for( i = 0; i < 3; i++ )
    {
694
        p_box->data.p_mdhd->i_language[i] =
695
696
697
698
                    ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
    }

    MP4_GET2BYTES( p_box->data.p_mdhd->i_predefined );
699

700
701
702
703
#ifdef MP4_VERBOSE
    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mdhd->i_creation_time );
    MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mdhd->i_modification_time );
    MP4_ConvertDate2Str( s_duration, p_box->data.p_mdhd->i_duration );
sigmunau's avatar
sigmunau committed
704
    msg_Dbg( p_stream, "read box: \"mdhd\" creation %s modification %s time scale %d duration %s language %c%c%c",
705
706
                  s_creation_time,
                  s_modification_time,
707
                  (uint32_t)p_box->data.p_mdhd->i_timescale,
708
709
710
711
712
713
714
715
716
                  s_duration,
                  p_box->data.p_mdhd->i_language[0],
                  p_box->data.p_mdhd->i_language[1],
                  p_box->data.p_mdhd->i_language[2] );
#endif
    MP4_READBOX_EXIT( 1 );
}


sigmunau's avatar
sigmunau committed
717
static int MP4_ReadBox_hdlr( stream_t *p_stream, MP4_Box_t *p_box )
718
{
719
720
    int32_t i_reserved;

721
    MP4_READBOX_ENTER( MP4_Box_data_hdlr_t );
722
723

    MP4_GETVERSIONFLAGS( p_box->data.p_hdlr );
724

725
    MP4_GETFOURCC( p_box->data.p_hdlr->i_predefined );
726
727
    MP4_GETFOURCC( p_box->data.p_hdlr->i_handler_type );

728
729
730
    MP4_GET4BYTES( i_reserved );
    MP4_GET4BYTES( i_reserved );
    MP4_GET4BYTES( i_reserved );
731
    p_box->data.p_hdlr->psz_name = NULL;
732

733
    if( i_read > 0 )
734
    {
735
736
        uint8_t *psz = p_box->data.p_hdlr->psz_name = malloc( i_read + 1 );
        if( psz == NULL )
737
            MP4_READBOX_EXIT( 0 );
738

739
740
741
742
743
        /* Yes, I love .mp4 :( */
        if( p_box->data.p_hdlr->i_predefined == VLC_FOURCC( 'm', 'h', 'l', 'r' ) )
        {
            uint8_t i_len;
            int i_copy;
744

745
746
            MP4_GET1BYTE( i_len );
            i_copy = __MIN( i_read, i_len );
747

748
            memcpy( psz, p_peek, i_copy );
749
750
751
752
            p_box->data.p_hdlr->psz_name[i_copy] = '\0';
        }
        else
        {
753
            memcpy( psz, p_peek, i_read );
754
755
756
            p_box->data.p_hdlr->psz_name[i_read] = '\0';
        }
    }
757
758

#ifdef MP4_VERBOSE
759
        msg_Dbg( p_stream, "read box: \"hdlr\" handler type: \"%4.4s\" name: \"%s\"",
760
761
                   (char*)&p_box->data.p_hdlr->i_handler_type,
                   p_box->data.p_hdlr->psz_name );
762
763

#endif
764
    MP4_READBOX_EXIT( 1 );
765
766
}

767
static void MP4_FreeBox_hdlr( MP4_Box_t *p_box )
768
{
zorglub's avatar
zorglub committed
769
    FREENULL( p_box->data.p_hdlr->psz_name );
770
771
}

sigmunau's avatar
sigmunau committed
772
static int MP4_ReadBox_vmhd( stream_t *p_stream, MP4_Box_t *p_box )
773
{
774
    unsigned int i;
775
776

    MP4_READBOX_ENTER( MP4_Box_data_vmhd_t );
777
778

    MP4_GETVERSIONFLAGS( p_box->data.p_vmhd );
779

780
781
782
783
784
    MP4_GET2BYTES( p_box->data.p_vmhd->i_graphics_mode );
    for( i = 0; i < 3; i++ )
    {
        MP4_GET2BYTES( p_box->data.p_vmhd->i_opcolor[i] );
    }
785

786
#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
787
    msg_Dbg( p_stream, "read box: \"vmhd\" graphics-mode %d opcolor (%d, %d, %d)",
788
789
790
791
792
793
794
795
                      p_box->data.p_vmhd->i_graphics_mode,
                      p_box->data.p_vmhd->i_opcolor[0],
                      p_box->data.p_vmhd->i_opcolor[1],
                      p_box->data.p_vmhd->i_opcolor[2] );
#endif
    MP4_READBOX_EXIT( 1 );
}

sigmunau's avatar
sigmunau committed
796
static int MP4_ReadBox_smhd( stream_t *p_stream, MP4_Box_t *p_box )
797
{
798
    MP4_READBOX_ENTER( MP4_Box_data_smhd_t );
799
800
801
802
803
804
805
806

    MP4_GETVERSIONFLAGS( p_box->data.p_smhd );



    MP4_GET2BYTES( p_box->data.p_smhd->i_balance );

    MP4_GET2BYTES( p_box->data.p_smhd->i_reserved );
807

808
#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
809
    msg_Dbg( p_stream, "read box: \"smhd\" balance %f",
810
811
812
813
814
815
                      (float)p_box->data.p_smhd->i_balance / 256 );
#endif
    MP4_READBOX_EXIT( 1 );
}


sigmunau's avatar
sigmunau committed
816
static int MP4_ReadBox_hmhd( stream_t *p_stream, MP4_Box_t *p_box )
817
{
818
    MP4_READBOX_ENTER( MP4_Box_data_hmhd_t );
819
820
821
822
823
824
825
826
827
828
829
830

    MP4_GETVERSIONFLAGS( p_box->data.p_hmhd );

    MP4_GET2BYTES( p_box->data.p_hmhd->i_max_PDU_size );
    MP4_GET2BYTES( p_box->data.p_hmhd->i_avg_PDU_size );

    MP4_GET4BYTES( p_box->data.p_hmhd->i_max_bitrate );
    MP4_GET4BYTES( p_box->data.p_hmhd->i_avg_bitrate );

    MP4_GET4BYTES( p_box->data.p_hmhd->i_reserved );

#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
831
    msg_Dbg( p_stream, "read box: \"hmhd\" maxPDU-size %d avgPDU-size %d max-bitrate %d avg-bitrate %d",
832
833
834
835
836
837
838
839
                      p_box->data.p_hmhd->i_max_PDU_size,
                      p_box->data.p_hmhd->i_avg_PDU_size,
                      p_box->data.p_hmhd->i_max_bitrate,
                      p_box->data.p_hmhd->i_avg_bitrate );
#endif
    MP4_READBOX_EXIT( 1 );
}

sigmunau's avatar
sigmunau committed
840
static int MP4_ReadBox_url( stream_t *p_stream, MP4_Box_t *p_box )
841
{
842
    MP4_READBOX_ENTER( MP4_Box_data_url_t );
843
844
845
846
847

    MP4_GETVERSIONFLAGS( p_box->data.p_url );
    MP4_GETSTRINGZ( p_box->data.p_url->psz_location );

#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
848
    msg_Dbg( p_stream, "read box: \"url\" url: %s",
849
850
851
852
853
854
855
                       p_box->data.p_url->psz_location );

#endif
    MP4_READBOX_EXIT( 1 );
}


856
static void MP4_FreeBox_url( MP4_Box_t *p_box )
857
{
858
    FREENULL( p_box->data.p_url->psz_location );
859
860
}

sigmunau's avatar
sigmunau committed
861
static int MP4_ReadBox_urn( stream_t *p_stream, MP4_Box_t *p_box )
862
863
864
865
866
867
{
    MP4_READBOX_ENTER( MP4_Box_data_urn_t );

    MP4_GETVERSIONFLAGS( p_box->data.p_urn );

    MP4_GETSTRINGZ( p_box->data.p_urn->psz_name );
868
869
    MP4_GETSTRINGZ( p_box->data.p_urn->psz_location );

870
#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
871
    msg_Dbg( p_stream, "read box: \"urn\" name %s location %s",
872
873
874
875
876
                      p_box->data.p_urn->psz_name,
                      p_box->data.p_urn->psz_location );
#endif
    MP4_READBOX_EXIT( 1 );
}
877
static void MP4_FreeBox_urn( MP4_Box_t *p_box )
878
{
zorglub's avatar
zorglub committed
879
880
    FREENULL( p_box->data.p_urn->psz_name );
    FREENULL( p_box->data.p_urn->psz_location );
881
882
883
}


sigmunau's avatar
sigmunau committed
884
static int MP4_ReadBox_dref( stream_t *p_stream, MP4_Box_t *p_box )
885
886
{
    MP4_READBOX_ENTER( MP4_Box_data_dref_t );
887

888
889
890
    MP4_GETVERSIONFLAGS( p_box->data.p_dref );

    MP4_GET4BYTES( p_box->data.p_dref->i_entry_count );
891

892
    stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 8 );
893
894
895
    MP4_ReadBoxContainerRaw( p_stream, p_box );

#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
896
    msg_Dbg( p_stream, "read box: \"dref\" entry-count %d",
897
898
899
900
901
902
                      p_box->data.p_dref->i_entry_count );

#endif
    MP4_READBOX_EXIT( 1 );
}

903
904
905
906
907
static void MP4_FreeBox_stts( MP4_Box_t *p_box )
{
    FREENULL( p_box->data.p_stts->i_sample_count );
    FREENULL( p_box->data.p_stts->i_sample_delta );
}
908

sigmunau's avatar
sigmunau committed
909
static int MP4_ReadBox_stts( stream_t *p_stream, MP4_Box_t *p_box )
910
{
911
    unsigned int i;
912
    MP4_READBOX_ENTER( MP4_Box_data_stts_t );
913
914
915
916

    MP4_GETVERSIONFLAGS( p_box->data.p_stts );
    MP4_GET4BYTES( p_box->data.p_stts->i_entry_count );

917
    p_box->data.p_stts->i_sample_count =
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
918
        calloc( p_box->data.p_stts->i_entry_count, sizeof(uint32_t) );
919
    p_box->data.p_stts->i_sample_delta =
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
920
        calloc( p_box->data.p_stts->i_entry_count, sizeof(uint32_t) );
921
922
923
    if( p_box->data.p_stts->i_sample_count == NULL
     || p_box->data.p_stts->i_sample_delta == NULL )
    {
924
        MP4_READBOX_EXIT( 0 );
925
    }
926

927
928
929
930
931
    for( i = 0; (i < p_box->data.p_stts->i_entry_count )&&( i_read >=8 ); i++ )
    {
        MP4_GET4BYTES( p_box->data.p_stts->i_sample_count[i] );
        MP4_GET4BYTES( p_box->data.p_stts->i_sample_delta[i] );
    }
932

933
#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
934
    msg_Dbg( p_stream, "read box: \"stts\" entry-count %d",
935
936
937
                      p_box->data.p_stts->i_entry_count );

#endif
938
    MP4_READBOX_EXIT( 1 );
939
940
}

941
942
943
944
945
946
947

static void MP4_FreeBox_ctts( MP4_Box_t *p_box )
{
    FREENULL( p_box->data.p_ctts->i_sample_count );
    FREENULL( p_box->data.p_ctts->i_sample_offset );
}

sigmunau's avatar
sigmunau committed
948
static int MP4_ReadBox_ctts( stream_t *p_stream, MP4_Box_t *p_box )
949
{
950
    unsigned int i;
951
    MP4_READBOX_ENTER( MP4_Box_data_ctts_t );
952

953
    MP4_GETVERSIONFLAGS( p_box->data.p_ctts );
954

955
956
    MP4_GET4BYTES( p_box->data.p_ctts->i_entry_count );

957
    p_box->data.p_ctts->i_sample_count =
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
958
        calloc( p_box->data.p_ctts->i_entry_count, sizeof(uint32_t) );
959
    p_box->data.p_ctts->i_sample_offset =
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
960
        calloc( p_box->data.p_ctts->i_entry_count, sizeof(uint32_t) );
961
962
963
    if( ( p_box->data.p_ctts->i_sample_count == NULL )
     || ( p_box->data.p_ctts->i_sample_offset == NULL ) )
    {
964
        MP4_READBOX_EXIT( 0 );
965
    }
966

967
968
969
970
971
    for( i = 0; (i < p_box->data.p_ctts->i_entry_count )&&( i_read >=8 ); i++ )
    {
        MP4_GET4BYTES( p_box->data.p_ctts->i_sample_count[i] );
        MP4_GET4BYTES( p_box->data.p_ctts->i_sample_offset[i] );
    }
972

973
#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
974
    msg_Dbg( p_stream, "read box: \"ctts\" entry-count %d",
975
976
977
                      p_box->data.p_ctts->i_entry_count );

#endif
978
    MP4_READBOX_EXIT( 1 );
979
980
981
}


982
static int MP4_ReadLengthDescriptor( uint8_t **pp_peek, int64_t  *i_read )
983
{
984
985
    unsigned int i_b;
    unsigned int i_len = 0;
986
987
988
989
990
991
992
993
    do
    {
        i_b = **pp_peek;

        (*pp_peek)++;
        (*i_read)--;
        i_len = ( i_len << 7 ) + ( i_b&0x7f );
    } while( i_b&0x80 );
994
    return( i_len );
995
996
}

997
998
999
1000
1001
1002
1003
1004
1005
1006
1007

static void MP4_FreeBox_esds( MP4_Box_t *p_box )
{
    FREENULL( p_box->data.p_esds->es_descriptor.psz_URL );
    if( p_box->data.p_esds->es_descriptor.p_decConfigDescr )
    {
        FREENULL( p_box->data.p_esds->es_descriptor.p_decConfigDescr->p_decoder_specific_info );
        FREENULL( p_box->data.p_esds->es_descriptor.p_decConfigDescr );
    }
}

sigmunau's avatar
sigmunau committed
1008
static int MP4_ReadBox_esds( stream_t *p_stream, MP4_Box_t *p_box )
1009
1010
{
#define es_descriptor p_box->data.p_esds->es_descriptor
1011
1012
1013
    unsigned int i_len;
    unsigned int i_flags;
    unsigned int i_type;
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024

    MP4_READBOX_ENTER( MP4_Box_data_esds_t );

    MP4_GETVERSIONFLAGS( p_box->data.p_esds );


    MP4_GET1BYTE( i_type );
    if( i_type == 0x03 ) /* MP4ESDescrTag */
    {
        i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );

1025
#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
1026
        msg_Dbg( p_stream, "found esds MPEG4ESDescr (%dBytes)",
1027
                 i_len );
1028
1029
#endif

1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
        MP4_GET2BYTES( es_descriptor.i_ES_ID );
        MP4_GET1BYTE( i_flags );
        es_descriptor.b_stream_dependence = ( (i_flags&0x80) != 0);
        es_descriptor.b_url = ( (i_flags&0x40) != 0);
        es_descriptor.b_OCRstream = ( (i_flags&0x20) != 0);

        es_descriptor.i_stream_priority = i_flags&0x1f;
        if( es_descriptor.b_stream_dependence )
        {
            MP4_GET2BYTES( es_descriptor.i_depend_on_ES_ID );
        }
        if( es_descriptor.b_url )
        {
1043
            unsigned int i_len;
1044

1045
            MP4_GET1BYTE( i_len );
1046
            es_descriptor.psz_URL = malloc( i_len + 1 );
1047
1048
1049
1050
1051
            if( es_descriptor.psz_URL )
            {
                memcpy( es_descriptor.psz_URL, p_peek, i_len );
                es_descriptor.psz_URL[i_len] = 0;
            }
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
            p_peek += i_len;
            i_read -= i_len;
        }
        else
        {
            es_descriptor.psz_URL = NULL;
        }
        if( es_descriptor.b_OCRstream )
        {
            MP4_GET2BYTES( es_descriptor.i_OCR_ES_ID );
        }
        MP4_GET1BYTE( i_type ); /* get next type */
    }

    if( i_type != 0x04)/* MP4DecConfigDescrTag */
    {
1068
1069
         es_descriptor.p_decConfigDescr = NULL;
         MP4_READBOX_EXIT( 1 ); /* rest isn't interesting up to now */
1070
1071
1072
    }

    i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1073
1074

#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
1075
        msg_Dbg( p_stream, "found esds MP4DecConfigDescr (%dBytes)",