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

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

27
#include <vlc_common.h>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
28
#include <vlc_stream.h>                               /* stream_Peek*/
29

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

34
#include "libmp4.h"
35
#include "languages.h"
gnarula's avatar
gnarula committed
36
#include <math.h>
37
38

/* Some assumptions:
39
 * The input method HAS to be seekable
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
40
 */
41

gnarula's avatar
gnarula committed
42
43
44
45
46
47
48
/* convert 16.16 fixed point to floating point */
static double conv_fx( int32_t fx ) {
    double fp = fx;
    fp /= 65536.;
    return fp;
}

49
/* some functions for mp4 encoding of variables */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
50
#ifdef MP4_VERBOSE
51
static void MP4_ConvertDate2Str( char *psz, uint64_t i_date, bool b_relative )
52
53
54
55
56
57
{
    int i_day;
    int i_hour;
    int i_min;
    int i_sec;

Laurent Aimar's avatar
Laurent Aimar committed
58
    /* date begin at 1 jan 1904 */
59
60
    if ( !b_relative )
        i_date += ((INT64_C(1904) * 365) + 17) * 24 * 60 * 60;
Laurent Aimar's avatar
Laurent Aimar committed
61

62
63
64
65
    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;
66
    sprintf( psz, "%dd-%2.2dh:%2.2dm:%2.2ds", i_day, i_hour, i_min, i_sec );
67
}
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
68
#endif
69

Laurent Aimar's avatar
Laurent Aimar committed
70
71
72
/*****************************************************************************
 * Some prototypes.
 *****************************************************************************/
sigmunau's avatar
sigmunau committed
73
static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father );
74
75
76


/*****************************************************************************
77
 * MP4_ReadBoxCommon : Load only common parameters for all boxes
78
 *****************************************************************************
79
 * p_box need to be an already allocated MP4_Box_t, and all data
80
81
82
83
 *  will only be peek not read
 *
 * RETURN : 0 if it fail, 1 otherwise
 *****************************************************************************/
sigmunau's avatar
sigmunau committed
84
int MP4_ReadBoxCommon( stream_t *p_stream, MP4_Box_t *p_box )
85
{
86
    int      i_read;
87
    const uint8_t  *p_peek;
88

sigmunau's avatar
sigmunau committed
89
    if( ( ( i_read = stream_Peek( p_stream, &p_peek, 32 ) ) < 8 ) )
90
    {
91
        return 0;
92
    }
sigmunau's avatar
sigmunau committed
93
    p_box->i_pos = stream_Tell( p_stream );
94

95
    p_box->data.p_payload = NULL;
96
97
98
99
    p_box->p_father = NULL;
    p_box->p_first  = NULL;
    p_box->p_last  = NULL;
    p_box->p_next   = NULL;
100

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
    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 */
    }
116

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
117
    if( p_box->i_type == ATOM_uuid )
118
119
120
121
122
123
124
125
126
    {
        /* 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 );
    }
127
#ifdef MP4_ULTRA_VERBOSE
128
129
    if( p_box->i_size )
    {
130
        if MP4_BOX_TYPE_ASCII()
131
132
            msg_Dbg( p_stream, "found Box: %4.4s size %"PRId64" %"PRId64,
                    (char*)&p_box->i_type, p_box->i_size, p_box->i_pos );
133
        else
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
134
            msg_Dbg( p_stream, "found Box: c%3.3s size %"PRId64,
135
                    (char*)&p_box->i_type+1, p_box->i_size );
136
137
138
    }
#endif

139
    return 1;
140
141
142
}

/*****************************************************************************
143
 * MP4_NextBox : Go to the next box
144
 *****************************************************************************
145
 * if p_box == NULL, go to the next box in which we are( at the begining ).
146
 *****************************************************************************/
sigmunau's avatar
sigmunau committed
147
static int MP4_NextBox( stream_t *p_stream, MP4_Box_t *p_box )
148
149
150
151
152
153
154
155
156
157
158
{
    MP4_Box_t box;

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

    if( !p_box->i_size )
    {
159
        return 2; /* Box with infinite size */
160
161
162
163
    }

    if( p_box->p_father )
    {
164
165
166
        /* if father's size == 0, it means unknown or infinite size,
         * and we skip the followong check */
        if( p_box->p_father->i_size > 0 )
167
        {
168
169
170
171
172
173
174
175
176
177
            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;

            /* check if it's within p-father */
            if( i_box_end >= i_father_end )
            {
                if( i_box_end > i_father_end )
                    msg_Dbg( p_stream, "out of bound child" );
                return 0; /* out of bound */
            }
178
179
        }
    }
sigmunau's avatar
sigmunau committed
180
    if( stream_Seek( p_stream, p_box->i_size + p_box->i_pos ) )
181
182
183
184
185
    {
        return 0;
    }

    return 1;
186
187
188
}

/*****************************************************************************
189
 * For all known box a loader is given,
190
191
 *  XXX: all common struct have to be already read by MP4_ReadBoxCommon
 *       after called one of theses functions, file position is unknown
192
 *       you need to call MP4_GotoBox to go where you want
193
 *****************************************************************************/
194
195
static int MP4_ReadBoxContainerChildrenIndexed( stream_t *p_stream,
               MP4_Box_t *p_container, uint32_t i_last_child, bool b_indexed )
196
197
{
    MP4_Box_t *p_box;
198

199
200
201
    /* Size of root container is set to 0 when unknown, for exemple
     * with a DASH stream. In that case, we skip the following check */
    if( p_container->i_size
202
            && ( stream_Tell( p_stream ) + ((b_indexed)?16:8) >
203
        (off_t)(p_container->i_pos + p_container->i_size) )
204
      )
205
206
    {
        /* there is no box to load */
207
        return 0;
208
    }
209

210
211
    do
    {
212
213
214
215
216
217
218
219
        uint32_t i_index = 0;
        if ( b_indexed )
        {
            uint8_t read[8];
            if ( stream_Read( p_stream, read, 8 ) < 8 )
                return 0;
            i_index = GetDWBE(&read[4]);
        }
220
        if( ( p_box = MP4_ReadBox( p_stream, p_container ) ) == NULL ) break;
221
        p_box->i_index = i_index;
222

Laurent Aimar's avatar
Laurent Aimar committed
223
        /* chain this box with the father and the other at same level */
224
225
        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
226
        p_container->p_last = p_box;
227

228
        if( p_box->i_type == i_last_child )
yhuelf's avatar
yhuelf committed
229
230
        {
            MP4_NextBox( p_stream, p_box );
231
            break;
yhuelf's avatar
yhuelf committed
232
        }
233

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

236
    return 1;
237
238
}

239
240
241
242
243
244
245
int MP4_ReadBoxContainerChildren( stream_t *p_stream, MP4_Box_t *p_container,
                                  uint32_t i_last_child )
{
    return MP4_ReadBoxContainerChildrenIndexed( p_stream, p_container,
                                                i_last_child, false );
}

246
static int MP4_ReadBoxContainerRaw( stream_t *p_stream, MP4_Box_t *p_container )
247
248
249
250
{
    return MP4_ReadBoxContainerChildren( p_stream, p_container, 0 );
}

sigmunau's avatar
sigmunau committed
251
static int MP4_ReadBoxContainer( stream_t *p_stream, MP4_Box_t *p_container )
252
{
253
254
    if( p_container->i_size &&
        ( p_container->i_size <= (size_t)mp4_box_headersize(p_container ) + 8 ) )
255
256
    {
        /* container is empty, 8 stand for the first header in this box */
257
        return 1;
258
    }
259

260
    /* enter box */
261
    stream_Seek( p_stream, p_container->i_pos +
262
                 mp4_box_headersize( p_container ) );
263

264
    return MP4_ReadBoxContainerRaw( p_stream, p_container );
265
266
}

267
static void MP4_FreeBox_Common( MP4_Box_t *p_box )
268
269
{
    /* Up to now do nothing */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
270
    (void)p_box;
271
272
}

sigmunau's avatar
sigmunau committed
273
static int MP4_ReadBoxSkip( stream_t *p_stream, MP4_Box_t *p_box )
274
{
275
    /* XXX sometime moov is hiden in a free box */
276
    if( p_box->p_father &&
277
        p_box->p_father->i_type == ATOM_root &&
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
278
        p_box->i_type == ATOM_free )
279
    {
280
        const uint8_t *p_peek;
281
282
283
        int     i_read;
        vlc_fourcc_t i_fcc;

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

286
287
        p_peek += mp4_box_headersize( p_box ) + 4;
        i_read -= mp4_box_headersize( p_box ) + 4;
288
289
290
291
292

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

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
293
            if( i_fcc == ATOM_cmov || i_fcc == ATOM_mvhd )
294
            {
sigmunau's avatar
sigmunau committed
295
                msg_Warn( p_stream, "detected moov hidden in a free box ..." );
296

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
297
                p_box->i_type = ATOM_foov;
298
299
300
301
                return MP4_ReadBoxContainer( p_stream, p_box );
            }
        }
    }
302

303
    /* Nothing to do */
304
#ifdef MP4_ULTRA_VERBOSE
305
306
307
308
    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 );
309
#endif
310
    return 1;
311
312
}

313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
static int MP4_ReadBox_ilst( stream_t *p_stream, MP4_Box_t *p_box )
{
    if( p_box->i_size < 8 || stream_Read( p_stream, NULL, 8 ) < 8 )
        return 0;

    /* Find our handler */
    if ( !p_box->i_handler && p_box->p_father )
    {
        const MP4_Box_t *p_sibling = p_box->p_father->p_first;
        while( p_sibling )
        {
            if ( p_sibling->i_type == ATOM_hdlr && p_sibling->data.p_hdlr )
            {
                p_box->i_handler = p_sibling->data.p_hdlr->i_handler_type;
                break;
            }
            p_sibling = p_sibling->p_next;
        }
    }

    switch( p_box->i_handler )
    {
    case 0:
        msg_Warn( p_stream, "no handler for ilst atom" );
        return 0;
338
    case HANDLER_mdta:
339
        return MP4_ReadBoxContainerChildrenIndexed( p_stream, p_box, 0, true );
340
    case HANDLER_mdir:
341
342
343
344
345
346
347
        return MP4_ReadBoxContainerChildren( p_stream, p_box, 0 );
    default:
        msg_Warn( p_stream, "Unknown ilst handler type '%4.4s'", (char*)&p_box->i_handler );
        return 0;
    }
}

sigmunau's avatar
sigmunau committed
348
static int MP4_ReadBox_ftyp( stream_t *p_stream, MP4_Box_t *p_box )
349
350
{
    MP4_READBOX_ENTER( MP4_Box_data_ftyp_t );
351

352
353
    MP4_GETFOURCC( p_box->data.p_ftyp->i_major_brand );
    MP4_GET4BYTES( p_box->data.p_ftyp->i_minor_version );
354

355
356
    if( ( p_box->data.p_ftyp->i_compatible_brands_count = i_read / 4 ) )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
357
358
359
360
        uint32_t *tab = p_box->data.p_ftyp->i_compatible_brands =
            calloc( p_box->data.p_ftyp->i_compatible_brands_count,
                    sizeof(uint32_t));

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
361
        if( unlikely( tab == NULL ) )
362
            MP4_READBOX_EXIT( 0 );
363

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
364
        for( unsigned i = 0; i < p_box->data.p_ftyp->i_compatible_brands_count; i++ )
365
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
366
            MP4_GETFOURCC( tab[i] );
367
368
369
370
371
372
373
        }
    }
    else
    {
        p_box->data.p_ftyp->i_compatible_brands = NULL;
    }

374
    MP4_READBOX_EXIT( 1 );
375
376
}

377
static void MP4_FreeBox_ftyp( MP4_Box_t *p_box )
378
{
zorglub's avatar
zorglub committed
379
    FREENULL( p_box->data.p_ftyp->i_compatible_brands );
380
381
382
}


sigmunau's avatar
sigmunau committed
383
static int MP4_ReadBox_mvhd(  stream_t *p_stream, MP4_Box_t *p_box )
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
{
#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 );
    }
408
409
    MP4_GET4BYTES( p_box->data.p_mvhd->i_rate );
    MP4_GET2BYTES( p_box->data.p_mvhd->i_volume );
410
411
    MP4_GET2BYTES( p_box->data.p_mvhd->i_reserved1 );

412

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
413
    for( unsigned i = 0; i < 2; i++ )
414
415
416
    {
        MP4_GET4BYTES( p_box->data.p_mvhd->i_reserved2[i] );
    }
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
417
    for( unsigned i = 0; i < 9; i++ )
418
419
420
    {
        MP4_GET4BYTES( p_box->data.p_mvhd->i_matrix[i] );
    }
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
421
    for( unsigned i = 0; i < 6; i++ )
422
423
424
    {
        MP4_GET4BYTES( p_box->data.p_mvhd->i_predefined[i] );
    }
425

426
    MP4_GET4BYTES( p_box->data.p_mvhd->i_next_track_id );
427
428


429
#ifdef MP4_VERBOSE
430
    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time, false );
431
    MP4_ConvertDate2Str( s_modification_time,
432
                         p_box->data.p_mvhd->i_modification_time, false );
433
434
    if( p_box->data.p_mvhd->i_rate )
    {
435
        MP4_ConvertDate2Str( s_duration,
436
                 p_box->data.p_mvhd->i_duration / p_box->data.p_mvhd->i_rate, true );
437
438
439
440
    }
    else
    {
        s_duration[0] = 0;
441
    }
sigmunau's avatar
sigmunau committed
442
    msg_Dbg( p_stream, "read box: \"mvhd\" creation %s modification %s time scale %d duration %s rate %f volume %f next track id %d",
443
444
                  s_creation_time,
                  s_modification_time,
445
                  (uint32_t)p_box->data.p_mvhd->i_timescale,
446
447
448
                  s_duration,
                  (float)p_box->data.p_mvhd->i_rate / (1<<16 ),
                  (float)p_box->data.p_mvhd->i_volume / 256 ,
449
                  (uint32_t)p_box->data.p_mvhd->i_next_track_id );
450
451
452
453
#endif
    MP4_READBOX_EXIT( 1 );
}

454
455
456
457
static int MP4_ReadBox_mfhd(  stream_t *p_stream, MP4_Box_t *p_box )
{
    MP4_READBOX_ENTER( MP4_Box_data_mfhd_t );

F. Yhuel's avatar
F. Yhuel committed
458
459
    MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );

460
461
462
463
464
465
466
467
468
    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 );
}

469
470
471
472
473
474
475
476
477
478
479
480
481
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
static int MP4_ReadBox_tfxd(  stream_t *p_stream, MP4_Box_t *p_box )
{
    MP4_READBOX_ENTER( MP4_Box_data_tfxd_t );

    MP4_Box_data_tfxd_t *p_tfxd_data = p_box->data.p_tfxd;
    MP4_GETVERSIONFLAGS( p_tfxd_data );

    if( p_tfxd_data->i_version == 0 )
    {
        MP4_GET4BYTES( p_tfxd_data->i_fragment_abs_time );
        MP4_GET4BYTES( p_tfxd_data->i_fragment_duration );
    }
    else
    {
        MP4_GET8BYTES( p_tfxd_data->i_fragment_abs_time );
        MP4_GET8BYTES( p_tfxd_data->i_fragment_duration );
    }

#ifdef MP4_VERBOSE
    msg_Dbg( p_stream, "read box: \"tfxd\" version %d, flags 0x%x, "\
            "fragment duration %"PRIu64", fragment abs time %"PRIu64,
                p_tfxd_data->i_version,
                p_tfxd_data->i_flags,
                p_tfxd_data->i_fragment_duration,
                p_tfxd_data->i_fragment_abs_time
           );
#endif

    MP4_READBOX_EXIT( 1 );
}

static int MP4_ReadBox_tfrf(  stream_t *p_stream, MP4_Box_t *p_box )
{
    MP4_READBOX_ENTER( MP4_Box_data_tfxd_t );

    MP4_Box_data_tfrf_t *p_tfrf_data = p_box->data.p_tfrf;
    MP4_GETVERSIONFLAGS( p_tfrf_data );

    MP4_GET1BYTE( p_tfrf_data->i_fragment_count );

    p_tfrf_data->p_tfrf_data_fields = calloc( p_tfrf_data->i_fragment_count,
                                              sizeof( TfrfBoxDataFields_t ) );
    if( !p_tfrf_data->p_tfrf_data_fields )
        MP4_READBOX_EXIT( 0 );

    for( uint8_t i = 0; i < p_tfrf_data->i_fragment_count; i++ )
    {
        TfrfBoxDataFields_t *TfrfBoxDataField = &p_tfrf_data->p_tfrf_data_fields[i];
        if( p_tfrf_data->i_version == 0 )
        {
            MP4_GET4BYTES( TfrfBoxDataField->i_fragment_abs_time );
            MP4_GET4BYTES( TfrfBoxDataField->i_fragment_duration );
        }
        else
        {
            MP4_GET8BYTES( TfrfBoxDataField->i_fragment_abs_time );
            MP4_GET8BYTES( TfrfBoxDataField->i_fragment_duration );
        }
    }

#ifdef MP4_VERBOSE
    msg_Dbg( p_stream, "read box: \"tfrf\" version %d, flags 0x%x, "\
            "fragment count %"PRIu8, p_tfrf_data->i_version,
                p_tfrf_data->i_flags, p_tfrf_data->i_fragment_count );

    for( uint8_t i = 0; i < p_tfrf_data->i_fragment_count; i++ )
    {
        TfrfBoxDataFields_t *TfrfBoxDataField = &p_tfrf_data->p_tfrf_data_fields[i];
        msg_Dbg( p_stream, "\"tfrf\" fragment duration %"PRIu64", "\
                                    "fragment abs time %"PRIu64,
                    TfrfBoxDataField->i_fragment_duration,
                    TfrfBoxDataField->i_fragment_abs_time );
    }

#endif

    MP4_READBOX_EXIT( 1 );
}

static void MP4_FreeBox_tfrf( MP4_Box_t *p_box )
{
    FREENULL( p_box->data.p_tfrf->p_tfrf_data_fields );
}

553
554
555
556
557
558
static int MP4_ReadBox_stra( stream_t *p_stream, MP4_Box_t *p_box )
{
    MP4_READBOX_ENTER( MP4_Box_data_stra_t );
    MP4_Box_data_stra_t *p_stra = p_box->data.p_stra;

    uint8_t i_reserved;
559
    VLC_UNUSED(i_reserved);
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
    MP4_GET1BYTE( p_stra->i_es_cat );
    MP4_GET1BYTE( i_reserved );
    MP4_GET2BYTES( p_stra->i_track_ID );

    MP4_GET4BYTES( p_stra->i_timescale );
    MP4_GET8BYTES( p_stra->i_duration );

    MP4_GET4BYTES( p_stra->FourCC );
    MP4_GET4BYTES( p_stra->Bitrate );
    MP4_GET4BYTES( p_stra->MaxWidth );
    MP4_GET4BYTES( p_stra->MaxHeight );
    MP4_GET4BYTES( p_stra->SamplingRate );
    MP4_GET4BYTES( p_stra->Channels );
    MP4_GET4BYTES( p_stra->BitsPerSample );
    MP4_GET4BYTES( p_stra->AudioTag );
    MP4_GET2BYTES( p_stra->nBlockAlign );

    MP4_GET1BYTE( i_reserved );
    MP4_GET1BYTE( i_reserved );
    MP4_GET1BYTE( i_reserved );
580
581
582
583
    MP4_GET1BYTE( p_stra->cpd_len );
    if( p_stra->cpd_len > i_read )
        goto error;
    p_stra->CodecPrivateData = malloc( p_stra->cpd_len );
584
585
    if( unlikely( p_stra->CodecPrivateData == NULL ) )
        goto error;
586
    memcpy( p_stra->CodecPrivateData, p_peek, p_stra->cpd_len );
587
588

#ifdef MP4_VERBOSE
589
590
    msg_Dbg( p_stream, "es_cat is %"PRIu8", birate is %"PRIu32,
              p_stra->i_es_cat, p_stra->Bitrate );
591
592
593
594
595
596
597
598
599
600
601
602
#endif

    MP4_READBOX_EXIT( 1 );
error:
    MP4_READBOX_EXIT( 0 );
}

static void MP4_FreeBox_stra( MP4_Box_t *p_box )
{
    FREENULL( p_box->data.p_stra->CodecPrivateData );
}

603
604
605
606
607
608
static int MP4_ReadBox_uuid( stream_t *p_stream, MP4_Box_t *p_box )
{
    if( !CmpUUID( &p_box->i_uuid, &TfrfBoxUUID ) )
        return MP4_ReadBox_tfrf( p_stream, p_box );
    if( !CmpUUID( &p_box->i_uuid, &TfxdBoxUUID ) )
        return MP4_ReadBox_tfxd( p_stream, p_box );
609
610
611
612
    if( !CmpUUID( &p_box->i_uuid, &SmooBoxUUID ) )
        return MP4_ReadBoxContainer( p_stream, p_box );
    if( !CmpUUID( &p_box->i_uuid, &StraBoxUUID ) )
        return MP4_ReadBox_stra( p_stream, p_box );
613
614
615
616
617
618
619
620
621
622
623

    msg_Warn( p_stream, "Unknown uuid type box" );
    return 1;
}

static void MP4_FreeBox_uuid( MP4_Box_t *p_box )
{
    if( !CmpUUID( &p_box->i_uuid, &TfrfBoxUUID ) )
        return MP4_FreeBox_tfrf( p_box );
    if( !CmpUUID( &p_box->i_uuid, &TfxdBoxUUID ) )
        return MP4_FreeBox_Common( p_box );
624
625
626
627
    if( !CmpUUID( &p_box->i_uuid, &SmooBoxUUID ) )
        return MP4_FreeBox_Common( p_box );
    if( !CmpUUID( &p_box->i_uuid, &StraBoxUUID ) )
        return MP4_FreeBox_stra( p_box );
628
629
}

630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
static int MP4_ReadBox_sidx(  stream_t *p_stream, MP4_Box_t *p_box )
{
    MP4_READBOX_ENTER( MP4_Box_data_sidx_t );

    MP4_Box_data_sidx_t *p_sidx_data = p_box->data.p_sidx;
    MP4_GETVERSIONFLAGS( p_sidx_data );

    MP4_GET4BYTES( p_sidx_data->i_reference_ID );
    MP4_GET4BYTES( p_sidx_data->i_timescale );

    if( p_sidx_data->i_version == 0 )
    {
        MP4_GET4BYTES( p_sidx_data->i_earliest_presentation_time );
        MP4_GET4BYTES( p_sidx_data->i_first_offset );
    }
    else
    {
        MP4_GET8BYTES( p_sidx_data->i_earliest_presentation_time );
        MP4_GET8BYTES( p_sidx_data->i_first_offset );
    }

    uint16_t i_reserved;
652
    VLC_UNUSED(i_reserved);
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
    MP4_GET2BYTES( i_reserved );
    MP4_GET2BYTES( p_sidx_data->i_reference_count );
    uint16_t i_count = p_sidx_data->i_reference_count;

    p_sidx_data->p_items = calloc( i_count, sizeof( MP4_Box_sidx_item_t ) );
    uint32_t tmp;
    for( unsigned i = 0; i < i_count; i++ )
    {
        MP4_GET4BYTES( tmp );
        p_sidx_data->p_items[i].b_reference_type = (bool)((tmp & 0x80000000)>>24);
        p_sidx_data->p_items[i].i_referenced_size = tmp & 0x7fffffff;
        MP4_GET4BYTES( p_sidx_data->p_items[i].i_subsegment_duration );

        MP4_GET4BYTES( tmp );
        p_sidx_data->p_items[i].b_starts_with_SAP = (bool)((tmp & 0x80000000)>>24);
        p_sidx_data->p_items[i].i_SAP_type = (tmp & 0x70000000)>>24;
        p_sidx_data->p_items[i].i_SAP_delta_time = tmp & 0xfffffff;
    }

#ifdef MP4_VERBOSE
    msg_Dbg( p_stream, "read box: \"sidx\" version %d, flags 0x%x, "\
            "ref_ID %"PRIu32", timescale %"PRIu32", ref_count %"PRIu16", "\
            "first subsegmt duration %"PRIu32,
                p_sidx_data->i_version,
                p_sidx_data->i_flags,
                p_sidx_data->i_reference_ID,
                p_sidx_data->i_timescale,
                p_sidx_data->i_reference_count,
                p_sidx_data->p_items[0].i_subsegment_duration
           );
#endif

    MP4_READBOX_EXIT( 1 );
}

static void MP4_FreeBox_sidx( MP4_Box_t *p_box )
{
    FREENULL( p_box->data.p_sidx->p_items );
}

693
694
695
696
697
698
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 );

Frédéric Yhuel's avatar
Frédéric Yhuel committed
699
700
701
702
703
704
705
    if( p_box->data.p_tfhd->i_version != 0 )
    {
        msg_Warn( p_stream, "'tfhd' box with version != 0. "\
                " Don't know what to do with that, please patch" );
        MP4_READBOX_EXIT( 0 );
    }

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

Frédéric Yhuel's avatar
Frédéric Yhuel committed
708
    if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DURATION_IS_EMPTY )
709
    {
Frédéric Yhuel's avatar
Frédéric Yhuel committed
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
        msg_Dbg( p_stream, "'duration-is-empty' flag is present "\
                "=> no samples for this time interval." );
        p_box->data.p_tfhd->b_empty = true;
    }
    else
        p_box->data.p_tfhd->b_empty = false;

    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 );
727
728

#ifdef MP4_VERBOSE
Frédéric Yhuel's avatar
Frédéric Yhuel committed
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
    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 %"PRId64, 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 );
750
751
752
753
754
755
756
757
758
759
760
761
762
763
#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 )
764
        MP4_GET4BYTES( p_box->data.p_trun->i_data_offset );
765
766
767
768
769
770
    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 )
771
        MP4_READBOX_EXIT( 0 );
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786

    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
787
    msg_Dbg( p_stream, "read box: \"trun\" version %u flags 0x%x sample count %u",
788
789
790
791
792
793
794
                  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];
795
796
        msg_Dbg( p_stream, "read box: \"trun\" sample %4.4u flags 0x%x "\
            "duration %"PRIu32" size %"PRIu32" composition time offset %"PRIu32,
797
798
799
800
801
802
803
804
805
806
807
808
809
810
                        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
811
static int MP4_ReadBox_tkhd(  stream_t *p_stream, MP4_Box_t *p_box )
812
813
814
815
816
817
818
{
#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 );
819

820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
    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 );
    }
838

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
839
    for( unsigned i = 0; i < 2; i++ )
840
841
842
843
844
845
846
847
    {
        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 );

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
848
    for( unsigned i = 0; i < 9; i++ )
849
850
851
852
853
    {
        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 );
854

gnarula's avatar
gnarula committed
855
856
857
    double rotation;    //angle in degrees to be rotated clockwise
    double scale[2];    // scale factor; sx = scale[0] , sy = scale[1]
    double translate[2];// amount to translate; tx = translate[0] , ty = translate[1]
858

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
859
    int32_t *matrix = p_box->data.p_tkhd->i_matrix;
860

gnarula's avatar
gnarula committed
861
862
    translate[0] = conv_fx(matrix[6]);
    translate[1] = conv_fx(matrix[7]);
863

gnarula's avatar
gnarula committed
864
865
866
867
    scale[0] = sqrt(conv_fx(matrix[0]) * conv_fx(matrix[0]) +
                    conv_fx(matrix[3]) * conv_fx(matrix[3]));
    scale[1] = sqrt(conv_fx(matrix[1]) * conv_fx(matrix[1]) +
                    conv_fx(matrix[4]) * conv_fx(matrix[4]));
868

gnarula's avatar
gnarula committed
869
    rotation = atan2(conv_fx(matrix[1]) / scale[1], conv_fx(matrix[0]) / scale[0]) * 180 / M_PI;
870

gnarula's avatar
gnarula committed
871
872
873
    if (rotation < 0)
        rotation += 360.;

874
875
    p_box->data.p_tkhd->f_rotation = rotation;

876
#ifdef MP4_VERBOSE
877
878
879
    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time, false );
    MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mvhd->i_modification_time, false );
    MP4_ConvertDate2Str( s_duration, p_box->data.p_mvhd->i_duration, true );
880

gnarula's avatar
gnarula committed
881
    msg_Dbg( p_stream, "read box: \"tkhd\" creation %s modification %s duration %s track ID %d layer %d volume %f rotation %f scaleX %f scaleY %f translateX %f translateY %f width %f height %f. "
882
            "Matrix: %i %i %i %i %i %i %i %i %i",
883
884
885
886
887
888
                  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 ,
gnarula's avatar
gnarula committed
889
890
891
892
893
                  rotation,
                  scale[0],
                  scale[1],
                  translate[0],
                  translate[1],
894
895
                  (float)p_box->data.p_tkhd->i_width / BLOCK16x16,
                  (float)p_box->data.p_tkhd->i_height / BLOCK16x16,
896
897
898
899
900
901
902
903
904
                  p_box->data.p_tkhd->i_matrix[0],
                  p_box->data.p_tkhd->i_matrix[1],
                  p_box->data.p_tkhd->i_matrix[2],
                  p_box->data.p_tkhd->i_matrix[3],
                  p_box->data.p_tkhd->i_matrix[4],
                  p_box->data.p_tkhd->i_matrix[5],
                  p_box->data.p_tkhd->i_matrix[6],
                  p_box->data.p_tkhd->i_matrix[7],
                  p_box->data.p_tkhd->i_matrix[8] );
905
906
907
908
909
#endif
    MP4_READBOX_EXIT( 1 );
}


sigmunau's avatar
sigmunau committed
910
static int MP4_ReadBox_mdhd( stream_t *p_stream, MP4_Box_t *p_box )
911
{
912
    uint16_t i_language;
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
#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 );
    }
936
937

    MP4_GET2BYTES( i_language );
938
939
    decodeQtLanguageCode( i_language, p_box->data.p_mdhd->rgs_language,
                          &p_box->data.p_mdhd->b_mac_encoding );
940

941
    MP4_GET2BYTES( p_box->data.p_mdhd->i_quality );
942

943
#ifdef MP4_VERBOSE
944
945
946
    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mdhd->i_creation_time, false );
    MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mdhd->i_modification_time, false );
    MP4_ConvertDate2Str( s_duration, p_box->data.p_mdhd->i_duration, true );
947
    msg_Dbg( p_stream, "read box: \"mdhd\" creation %s modification %s time scale %d duration %s language %3.3s",
948
949
                  s_creation_time,
                  s_modification_time,
950
                  (uint32_t)p_box->data.p_mdhd->i_timescale,
951
                  s_duration,
952
                  (char*) &p_box->data.p_mdhd->rgs_language );
953
954
955
956
957
#endif
    MP4_READBOX_EXIT( 1 );
}


sigmunau's avatar
sigmunau committed
958
static int MP4_ReadBox_hdlr( stream_t *p_stream, MP4_Box_t *p_box )
959
{
960
    int32_t i_reserved;
961
    VLC_UNUSED(i_reserved);
962

963
    MP4_READBOX_ENTER( MP4_Box_data_hdlr_t );
964
965

    MP4_GETVERSIONFLAGS( p_box->data.p_hdlr );
966

967
    MP4_GETFOURCC( p_box->data.p_hdlr->i_predefined );
968
969
    MP4_GETFOURCC( p_box->data.p_hdlr->i_handler_type );

970
971
972
    MP4_GET4BYTES( i_reserved );
    MP4_GET4BYTES( i_reserved );
    MP4_GET4BYTES( i_reserved );
973
    p_box->data.p_hdlr->psz_name = NULL;
974

975
    if( i_read > 0 )
976
    {
977
        uint8_t *psz = p_box->data.p_hdlr->psz_name = malloc( i_read + 1 );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
978
        if( unlikely( psz == NULL ) )
979
            MP4_READBOX_EXIT( 0 );
980

981
982
983
984
985
        /* 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;
986

987
988
            MP4_GET1BYTE( i_len );
            i_copy = __MIN( i_read, i_len );
989

990
            memcpy( psz, p_peek, i_copy );
991
992
993
994
            p_box->data.p_hdlr->psz_name[i_copy] = '\0';
        }
        else
        {
995
            memcpy( psz, p_peek, i_read );
996
997
998
            p_box->data.p_hdlr->psz_name[i_read] = '\0';
        }
    }
999
1000

#ifdef MP4_VERBOSE
1001
        msg_Dbg( p_stream, "read box: \"hdlr\" handler type: \"%4.4s\" name: \"%s\"",
1002
1003
                   (char*)&p_box->data.p_hdlr->i_handler_type,
                   p_box->data.p_hdlr->psz_name );
1004
1005

#endif
1006
    MP4_READBOX_EXIT( 1 );
1007
1008
}

1009
static void MP4_FreeBox_hdlr( MP4_Box_t *p_box )
1010
{
zorglub's avatar
zorglub committed
1011
    FREENULL( p_box->data.p_hdlr->psz_name );
1012
1013
}

sigmunau's avatar
sigmunau committed
1014
static int MP4_ReadBox_vmhd( stream_t *p_stream, MP4_Box_t *p_box )
1015
{
1016
    MP4_READBOX_ENTER( MP4_Box_data_vmhd_t );
1017
1018

    MP4_GETVERSIONFLAGS( p_box->data.p_vmhd );
1019

1020
    MP4_GET2BYTES( p_box->data.p_vmhd->i_graphics_mode );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
1021
    for( unsigned i = 0; i < 3; i++ )
1022
1023
1024
    {
        MP4_GET2BYTES( p_box->data.p_vmhd->i_opcolor[i] );
    }
1025

1026
#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
1027
    msg_Dbg( p_stream, "read box: \"vmhd\" graphics-mode %d opcolor (%d, %d, %d)",
1028
1029
1030
1031
1032
1033
1034
1035
                      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
1036
static int MP4_ReadBox_smhd( stream_t *p_stream, MP4_Box_t *p_box )
1037
{
1038
    MP4_READBOX_ENTER( MP4_Box_data_smhd_t );
1039
1040
1041
1042
1043
1044
1045
1046

    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 );
1047

1048
#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
1049
    msg_Dbg( p_stream, "read box: \"smhd\" balance %f",
1050
1051
1052
1053
1054
1055
                      (float)p_box->data.p_smhd->i_balance / 256 );
#endif
    MP4_READBOX_EXIT( 1 );
}


sigmunau's avatar
sigmunau committed
1056
static int MP4_ReadBox_hmhd( stream_t *p_stream, MP4_Box_t *p_box )
1057
{
1058
    MP4_READBOX_ENTER( MP4_Box_data_hmhd_t );
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070

    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
1071
    msg_Dbg( p_stream, "read box: \"hmhd\" maxPDU-size %d avgPDU-size %d max-bitrate %d avg-bitrate %d",
1072
1073
1074
1075
1076
1077
1078
1079
                      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
1080
static int MP4_ReadBox_url( stream_t *p_stream, MP4_Box_t *p_box )
1081
{
1082
    MP4_READBOX_ENTER( MP4_Box_data_url_t );
1083
1084
1085
1086
1087

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

#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
1088
    msg_Dbg( p_stream, "read box: \"url\" url: %s",
1089
1090
1091
1092
1093
1094
1095
                       p_box->data.p_url->psz_location );

#endif
    MP4_READBOX_EXIT( 1 );
}


1096
static void MP4_FreeBox_url( MP4_Box_t *p_box )
1097
{
1098
    FREENULL( p_box->data.p_url->psz_location );
1099
1100
}

sigmunau's avatar
sigmunau committed
1101
static int MP4_ReadBox_urn( stream_t *p_stream, MP4_Box_t *p_box )
1102
1103
1104
1105
1106
1107
{
    MP4_READBOX_ENTER( MP4_Box_data_urn_t );

    MP4_GETVERSIONFLAGS( p_box->data.p_urn );

    MP4_GETSTRINGZ( p_box->data.p_urn->psz_name );
1108
1109
    MP4_GETSTRINGZ( p_box->data.p_urn->psz_location );

1110
#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
1111
    msg_Dbg( p_stream, "read box: \"urn\" name %s location %s",
1112
1113
1114
1115
1116
                      p_box->data.p_urn->psz_name,
                      p_box->data.p_urn->psz_location );
#endif
    MP4_READBOX_EXIT( 1 );
}
1117
static void MP4_FreeBox_urn( MP4_Box_t *p_box )
1118
{
zorglub's avatar
zorglub committed
1119
1120
    FREENULL( p_box->data.p_urn->psz_name );
    FREENULL( p_box->data.p_urn->psz_location );
1121
1122
1123
}


sigmunau's avatar
sigmunau committed
1124
static int MP4_ReadBox_dref( stream_t *p_stream, MP4_Box_t *p_box )
1125
1126
{
    MP4_READBOX_ENTER( MP4_Box_data_dref_t );
1127

1128
1129
1130
    MP4_GETVERSIONFLAGS( p_box->data.p_dref );

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

1132
    stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 8 );
1133
1134
1135
    MP4_ReadBoxContainerRaw( p_stream, p_box );

#ifdef MP4_VERBOSE
sigmunau's avatar
sigmunau committed
1136
    msg_Dbg( p_stream, "read box: \"dref\" entry-count %d",
1137
1138
1139
1140
1141
1142
                      p_box->data.p_dref->i_entry_count );

#endif
    MP4_READBOX_EXIT( 1 );
}

1143
1144
static void MP4_FreeBox_stts( MP4_Box_t *p_box )
{
1145
1146
    FREENULL( p_box->data.p_stts->pi_sample_count );
    FREENULL( p_box->data.p_stts->pi_sample_delta );
1147
}
1148

sigmunau's avatar
sigmunau committed
1149
static int MP4_ReadBox_stts( stream_t *p_stream, MP4_Box_t *p_box )
Sam Hocevar's avatar