Coverage Report

Created: 2025-08-29 06:30

/src/vlc/modules/demux/mp4/libmp4.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * libmp4.c : LibMP4 library for mp4 module for vlc
3
 *****************************************************************************
4
 * Copyright (C) 2001-2004, 2010 VLC authors and VideoLAN
5
 *
6
 * Author: Laurent Aimar <fenrir@via.ecp.fr>
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program; if not, write to the Free Software Foundation,
20
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21
 *****************************************************************************/
22
23
#ifdef HAVE_CONFIG_H
24
# include "config.h"
25
#endif
26
27
#include <vlc_common.h>
28
#include <vlc_stream.h>                               /* vlc_stream_Peek*/
29
#include <vlc_strings.h>                              /* vlc_ascii_tolower */
30
31
#ifdef HAVE_ZLIB_H
32
#   include <zlib.h>                                  /* for compressed moov */
33
#endif
34
35
#include "libmp4.h"
36
#include "languages.h"
37
#include <math.h>
38
#include <assert.h>
39
#include <limits.h>
40
#include <stdckdint.h>
41
42
/* Some assumptions:
43
 * The input method HAS to be seekable
44
 */
45
46
/* convert 16.16 fixed point to floating point */
47
0
static double conv_fx( int32_t fx ) {
48
0
    double fp = fx;
49
0
    fp /= 65536.;
50
0
    return fp;
51
0
}
52
53
/* some functions for mp4 encoding of variables */
54
#ifdef MP4_VERBOSE
55
static char * MP4_Time2Str( stime_t i_duration, uint32_t i_scale )
56
0
{
57
0
    uint64_t i_time = (i_scale) ? i_duration / i_scale : 0;
58
0
    unsigned h = ( i_time /( 60*60 ) ) % 60;
59
0
    unsigned m = ( i_time / 60 ) % 60;
60
0
    unsigned s = i_time % 60;
61
0
    uint64_t ms;
62
0
    if ( i_scale == 0 || ckd_mul( &ms, 1000, i_duration ) )
63
0
        ms = 0;
64
0
    ms = (ms / i_scale) % 1000;
65
66
0
    char *out;
67
0
    if( asprintf( &out, "%u:%.2u:%.2u:%.3" PRIu64, h, m, s, ms ) < 0 )
68
0
        return NULL;
69
0
    return out;
70
0
}
71
#endif
72
73
#define MP4_GETX_PRIVATE(dst, code, size) \
74
0
    do \
75
0
    { \
76
0
        if( (i_read) >= (size) ) \
77
0
        { \
78
0
            dst = (code); \
79
0
            p_peek += (size); \
80
0
            i_read -= (size); \
81
0
        } \
82
0
        else \
83
0
        { \
84
0
            dst = 0; \
85
0
            i_read = 0; \
86
0
        } \
87
0
    } while(0)
88
89
0
#define MP4_GET1BYTE( dst )  MP4_GETX_PRIVATE( dst, *p_peek, 1 )
90
0
#define MP4_GET2BYTES( dst ) MP4_GETX_PRIVATE( dst, GetWBE(p_peek), 2 )
91
0
#define MP4_GET3BYTES( dst ) MP4_GETX_PRIVATE( dst, Get24bBE(p_peek), 3 )
92
0
#define MP4_GET4BYTES( dst ) MP4_GETX_PRIVATE( dst, GetDWBE(p_peek), 4 )
93
0
#define MP4_GET8BYTES( dst ) MP4_GETX_PRIVATE( dst, GetQWBE(p_peek), 8 )
94
95
0
#define MP4_GET2BYTESLE( dst ) MP4_GETX_PRIVATE( dst, GetWLE(p_peek), 2 )
96
0
#define MP4_GET4BYTESLE( dst ) MP4_GETX_PRIVATE( dst, GetDWLE(p_peek), 4 )
97
#define MP4_GET8BYTESLE( dst ) MP4_GETX_PRIVATE( dst, GetQWLE(p_peek), 8 )
98
0
#define MP4_GETFOURCC( dst )   MP4_GET4BYTESLE( dst )
99
100
#define MP4_GETVERSIONFLAGS( p_void ) \
101
0
    MP4_GET1BYTE( p_void->i_version ); \
102
0
    MP4_GET3BYTES( p_void->i_flags )
103
104
static char *mp4_getstringz( uint8_t **restrict in, uint64_t *restrict size )
105
0
{
106
0
    assert( *size <= SSIZE_MAX );
107
108
0
    if( *size == 0 )
109
0
        return NULL;
110
111
0
    if( *in == 0 ) /* Null string stored */
112
0
    {
113
0
        *in += 1;
114
0
        *size -= 1;
115
0
        return NULL;
116
0
    }
117
118
0
    size_t len = strnlen( (const char *)*in, *size );
119
0
    if( len == 0 || len >= *size )
120
0
        return NULL;
121
122
0
    len++;
123
124
0
    char *ret = malloc( len );
125
0
    if( likely(ret != NULL) )
126
0
        memcpy( ret, *in, len );
127
0
    *in += len;
128
0
    *size -= len;
129
0
    return ret;
130
0
}
131
132
#define MP4_GETSTRINGZ( p_str ) \
133
0
    do \
134
0
        (p_str) = mp4_getstringz( &p_peek, &i_read ); \
135
0
    while(0)
136
137
/* This macro is used when we want to printf the box type
138
 * APPLE annotation box is :
139
 *  either 0xA9 + 24-bit ASCII text string (and 0xA9 isn't printable)
140
 *  either 32-bit ASCII text string
141
 */
142
0
#define MP4_BOX_TYPE_ASCII() ( ((unsigned char*)&p_box->i_type)[0] != 0xA9 )
143
144
static inline uint32_t Get24bBE( const uint8_t *p )
145
0
{
146
0
    return( ( p[0] <<16 ) + ( p[1] <<8 ) + p[2] );
147
0
}
148
149
static inline void GetUUID( UUID_t *p_uuid, const uint8_t *p_buff )
150
0
{
151
0
    memcpy( p_uuid, p_buff, 16 );
152
0
}
153
154
static video_palette_t * ReadQuicktimePalette( uint8_t **pp_peek, uint64_t *pi_read )
155
0
{
156
0
    uint8_t *p_peek = *pp_peek;
157
0
    uint64_t i_read = *pi_read;
158
0
    uint32_t v;
159
0
    MP4_GET4BYTES(v);
160
0
    if( v != 0 )
161
0
        return NULL;
162
0
    MP4_GET2BYTES(v); // should be == 0x8000, but does not in the wild
163
0
    uint16_t i_colors_count;
164
0
    MP4_GET2BYTES(i_colors_count);
165
0
    if( i_colors_count == UINT16_MAX ||
166
0
        ++i_colors_count > VIDEO_PALETTE_COLORS_MAX ||
167
0
        i_read < i_colors_count * 8U)
168
0
        return NULL;
169
0
    video_palette_t *p_palette = malloc( sizeof(video_palette_t) );
170
0
    if( p_palette == NULL )
171
0
        return NULL;
172
0
    for( uint16_t i=0; i<i_colors_count; i++ )
173
0
    {
174
0
        uint16_t dummy;
175
0
        MP4_GET2BYTES(dummy); VLC_UNUSED(dummy);
176
0
        MP4_GET2BYTES(p_palette->palette[i][0]);
177
0
        MP4_GET2BYTES(p_palette->palette[i][1]);
178
0
        MP4_GET2BYTES(p_palette->palette[i][2]);
179
0
        p_palette->palette[i][3] = 0xFF;
180
0
    }
181
0
    p_palette->i_entries = i_colors_count;
182
0
    *pp_peek = p_peek;
183
0
    *pi_read = i_read;
184
0
    return p_palette;
185
0
}
186
187
static uint8_t *mp4_readbox_enter_common( stream_t *s, MP4_Box_t *box,
188
                                          size_t typesize,
189
                                          void (*release)( MP4_Box_t * ),
190
                                          uint64_t readsize )
191
0
{
192
0
    const size_t headersize = mp4_box_headersize( box );
193
194
0
    if( unlikely(readsize < headersize) || unlikely(readsize > SSIZE_MAX) )
195
0
        return NULL;
196
197
0
    uint8_t *buf = malloc( readsize );
198
0
    if( unlikely(buf == NULL) )
199
0
        return NULL;
200
201
0
    ssize_t val = vlc_stream_Read( s, buf, readsize );
202
0
    if( (size_t)val != readsize )
203
0
    {
204
0
        msg_Warn( s, "mp4: wanted %"PRIu64" bytes, got %zd", readsize, val );
205
0
        goto error;
206
0
    }
207
208
0
    box->data.p_payload = calloc( 1, typesize );
209
0
    if( unlikely(box->data.p_payload == NULL) )
210
0
        goto error;
211
212
0
    box->pf_free = release;
213
0
    return buf;
214
0
error:
215
0
    free( buf );
216
0
    return NULL;
217
0
}
218
219
static uint8_t *mp4_readbox_enter_partial( stream_t *s, MP4_Box_t *box,
220
                                           size_t typesize,
221
                                           void (*release)( MP4_Box_t * ),
222
                                           uint64_t *restrict readsize )
223
0
{
224
0
    if( (uint64_t)*readsize > box->i_size )
225
0
        *readsize = box->i_size;
226
227
0
    return mp4_readbox_enter_common( s, box, typesize, release, *readsize );
228
0
}
229
230
static uint8_t *mp4_readbox_enter( stream_t *s, MP4_Box_t *box,
231
                                   size_t typesize,
232
                                   void (*release)( MP4_Box_t * ) )
233
0
{
234
0
    uint64_t readsize = box->i_size;
235
0
    return mp4_readbox_enter_common( s, box, typesize, release, readsize );
236
0
}
237
238
239
#define MP4_READBOX_ENTER_PARTIAL( MP4_Box_data_TYPE_t, maxread, release ) \
240
0
    uint64_t i_read = (maxread); \
241
0
    uint8_t *p_buff = mp4_readbox_enter_partial( p_stream, p_box, \
242
0
        sizeof( MP4_Box_data_TYPE_t ), release, &i_read ); \
243
0
    if( unlikely(p_buff == NULL) ) \
244
0
        return 0; \
245
0
    const size_t header_size = mp4_box_headersize( p_box ); \
246
0
    uint8_t *p_peek = p_buff + header_size; \
247
0
    i_read -= header_size
248
249
#define MP4_READBOX_ENTER( MP4_Box_data_TYPE_t, release ) \
250
0
    uint8_t *p_buff = mp4_readbox_enter( p_stream, p_box, \
251
0
        sizeof(MP4_Box_data_TYPE_t), release ); \
252
0
    if( unlikely(p_buff == NULL) ) \
253
0
        return 0; \
254
0
    uint64_t i_read = p_box->i_size; \
255
0
    const size_t header_size = mp4_box_headersize( p_box ); \
256
0
    uint8_t *p_peek = p_buff + header_size; \
257
0
    i_read -= header_size
258
259
#define MP4_READBOX_EXIT( i_code ) \
260
0
    do \
261
0
    { \
262
0
        free( p_buff ); \
263
0
        return( i_code ); \
264
0
    } while (0)
265
266
/*****************************************************************************
267
 * Some prototypes.
268
 *****************************************************************************/
269
static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father );
270
static MP4_Box_t *MP4_ReadBoxUsing( stream_t *p_stream, MP4_Box_t *p_father,
271
                                    int(*MP4_ReadBox_function)(stream_t *, MP4_Box_t *) );
272
static int MP4_Box_Read_Specific( stream_t *p_stream, MP4_Box_t *p_box, MP4_Box_t *p_father );
273
static int MP4_PeekBoxHeader( stream_t *p_stream, MP4_Box_t *p_box );
274
275
int MP4_Seek( stream_t *p_stream, uint64_t i_pos )
276
0
{
277
0
    bool b_canseek = false;
278
0
    if ( vlc_stream_Control( p_stream, STREAM_CAN_SEEK, &b_canseek ) != VLC_SUCCESS ||
279
0
         b_canseek )
280
0
    {
281
        /* can seek or don't know */
282
0
        return vlc_stream_Seek( p_stream, i_pos );
283
0
    }
284
    /* obviously can't seek then */
285
286
0
    int64_t i_current_pos = vlc_stream_Tell( p_stream );
287
0
    if ( i_current_pos < 0 || i_pos < (uint64_t)i_current_pos )
288
0
        return VLC_EGENERIC;
289
290
0
    uint64_t i_toread = i_pos - i_current_pos;
291
0
    if( i_toread == 0 )
292
0
        return VLC_SUCCESS;
293
0
    if( i_toread > SSIZE_MAX ) // we can't read more than that
294
0
        return VLC_EGENERIC;
295
296
0
    if( vlc_stream_Read( p_stream, NULL, i_toread ) != (ssize_t) i_toread )
297
0
        return VLC_EGENERIC;
298
0
    return VLC_SUCCESS;
299
0
}
300
301
static void MP4_BoxAddChild( MP4_Box_t *p_parent, MP4_Box_t *p_childbox )
302
0
{
303
0
    if( !p_parent->p_first )
304
0
            p_parent->p_first = p_childbox;
305
0
    else
306
0
            p_parent->p_last->p_next = p_childbox;
307
0
    p_parent->p_last = p_childbox;
308
0
    p_childbox->p_father = p_parent;
309
0
}
310
311
MP4_Box_t * MP4_BoxExtract( MP4_Box_t **pp_chain, uint32_t i_type )
312
0
{
313
0
    MP4_Box_t *p_box = *pp_chain;
314
0
    while( p_box )
315
0
    {
316
0
        if( p_box->i_type == i_type )
317
0
        {
318
0
            *pp_chain = p_box->p_next;
319
0
            p_box->p_next = NULL;
320
0
            p_box->p_father = NULL;
321
0
            return p_box;
322
0
        }
323
0
        pp_chain = &p_box->p_next;
324
0
        p_box = p_box->p_next;
325
0
    }
326
0
    return NULL;
327
0
}
328
329
/* Don't use vlc_stream_Seek directly */
330
#undef vlc_stream_Seek
331
#define vlc_stream_Seek(a,b) __NO__
332
333
/*****************************************************************************
334
 * MP4_PeekBoxHeader : Load only common parameters for all boxes
335
 *****************************************************************************
336
 * p_box need to be an already allocated MP4_Box_t, and all data
337
 *  will only be peek not read
338
 *
339
 * RETURN : 0 if it fail, 1 otherwise
340
 *****************************************************************************/
341
static int MP4_PeekBoxHeader( stream_t *p_stream, MP4_Box_t *p_box )
342
0
{
343
0
    ssize_t i_read;
344
0
    const uint8_t  *p_peek;
345
346
0
    if( ( ( i_read = vlc_stream_Peek( p_stream, &p_peek, 32 ) ) < 8 ) )
347
0
    {
348
0
        return 0;
349
0
    }
350
0
    p_box->i_pos = vlc_stream_Tell( p_stream );
351
352
0
    p_box->data.p_payload = NULL;
353
0
    p_box->p_father = NULL;
354
0
    p_box->p_first  = NULL;
355
0
    p_box->p_last  = NULL;
356
0
    p_box->p_next   = NULL;
357
358
0
    MP4_GET4BYTES( p_box->i_shortsize );
359
0
    MP4_GETFOURCC( p_box->i_type );
360
361
    /* Now special case */
362
363
0
    if( p_box->i_shortsize == 1 )
364
0
    {
365
0
        if( i_read < 8 )
366
0
            return 0;
367
        /* get the true size on 64 bits */
368
0
        MP4_GET8BYTES( p_box->i_size );
369
0
    }
370
0
    else
371
0
    {
372
0
        p_box->i_size = p_box->i_shortsize;
373
        /* XXX size of 0 means that the box extends to end of file */
374
0
    }
375
376
0
    if( UINT64_MAX - p_box->i_size < p_box->i_pos )
377
0
        return 0;
378
379
0
    if( p_box->i_type == ATOM_uuid )
380
0
    {
381
0
        if( i_read < 16 )
382
0
            return 0;
383
        /* get extended type on 16 bytes */
384
0
        GetUUID( &p_box->i_uuid, p_peek );
385
0
    }
386
387
#ifdef MP4_ULTRA_VERBOSE
388
    if( p_box->i_size )
389
    {
390
        if MP4_BOX_TYPE_ASCII()
391
            msg_Dbg( p_stream, "found Box: %4.4s size %"PRId64" %"PRId64,
392
                    (char*)&p_box->i_type, p_box->i_size, p_box->i_pos );
393
        else
394
            msg_Dbg( p_stream, "found Box: c%3.3s size %"PRId64,
395
                    (char*)&p_box->i_type+1, p_box->i_size );
396
    }
397
#endif
398
399
0
    return 1;
400
0
}
401
402
/*****************************************************************************
403
 * MP4_ReadBoxRestricted : Reads box from current position
404
 *****************************************************************************
405
 * if p_box == NULL, box is invalid or failed, position undefined
406
 * on success, position is past read box or EOF
407
 *****************************************************************************/
408
static MP4_Box_t *MP4_ReadBoxRestricted( stream_t *p_stream, MP4_Box_t *p_father,
409
                                         const uint32_t stopbefore[], bool *pb_restrictionhit )
410
0
{
411
0
    MP4_Box_t peekbox = { 0 };
412
0
    if ( !MP4_PeekBoxHeader( p_stream, &peekbox ) )
413
0
        return NULL;
414
415
0
    if( peekbox.i_size < 8 )
416
0
    {
417
0
        msg_Warn( p_stream, "found an invalid sized %"PRIu64" box %4.4s @%"PRIu64 ,
418
0
                  peekbox.i_size, (char *) &peekbox.i_type, vlc_stream_Tell(p_stream) );
419
0
        return NULL;
420
0
    }
421
422
0
    for( size_t i=0; stopbefore && stopbefore[i]; i++ )
423
0
    {
424
0
        if( stopbefore[i] == peekbox.i_type )
425
0
        {
426
0
            *pb_restrictionhit = true;
427
0
            return NULL;
428
0
        }
429
0
    }
430
431
    /* if father's size == 0, it means unknown or infinite size,
432
     * and we skip the followong check */
433
0
    if( p_father && p_father->i_size > 0 )
434
0
    {
435
0
        const uint64_t i_box_next = peekbox.i_size + peekbox.i_pos;
436
0
        const uint64_t i_father_next = p_father->i_size + p_father->i_pos;
437
        /* check if it's within p-father */
438
0
        if( i_box_next > i_father_next )
439
0
        {
440
0
            msg_Warn( p_stream, "out of bound child %4.4s", (char*) &peekbox.i_type );
441
0
            return NULL; /* out of bound */
442
0
        }
443
0
    }
444
445
    /* Everything seems OK */
446
0
    MP4_Box_t *p_box = (MP4_Box_t *) malloc( sizeof(MP4_Box_t) );
447
0
    if( !p_box )
448
0
        return NULL;
449
0
    *p_box = peekbox;
450
451
0
    const uint64_t i_next = p_box->i_pos + p_box->i_size;
452
0
    p_box->p_father = p_father;
453
0
    if( MP4_Box_Read_Specific( p_stream, p_box, p_father ) != VLC_SUCCESS )
454
0
    {
455
0
        msg_Warn( p_stream, "Failed reading box %4.4s", (char*) &peekbox.i_type );
456
0
        MP4_BoxFree( p_box );
457
0
        p_box = NULL;
458
0
    }
459
460
    /* Check is we consumed all data */
461
0
    if( vlc_stream_Tell( p_stream ) < i_next )
462
0
    {
463
0
        MP4_Seek( p_stream, i_next - 1 ); /*  since past seek can fail when hitting EOF */
464
0
        MP4_Seek( p_stream, i_next );
465
0
        if( vlc_stream_Tell( p_stream ) < i_next - 1 ) /* Truncated box */
466
0
        {
467
0
            msg_Warn( p_stream, "truncated box %4.4s discarded", (char*) &peekbox.i_type );
468
0
            MP4_BoxFree( p_box );
469
0
            p_box = NULL;
470
0
        }
471
0
    }
472
473
0
    if ( p_box )
474
0
        MP4_BoxAddChild( p_father, p_box );
475
476
0
    return p_box;
477
0
}
478
479
/*****************************************************************************
480
 * For all known box a loader is given,
481
 * you have to be already read container header
482
 * without container size, file position on exit is unknown
483
 *****************************************************************************/
484
static int MP4_ReadBoxContainerChildrenIndexed( stream_t *p_stream,
485
               MP4_Box_t *p_container, const uint32_t stoplist[],
486
               const uint32_t excludelist[], bool b_indexed )
487
0
{
488
    /* Size of root container is set to 0 when unknown, for example
489
     * with a DASH stream. In that case, we skip the following check */
490
0
    if( (p_container->i_size || p_container->p_father)
491
0
            && ( vlc_stream_Tell( p_stream ) + ((b_indexed)?16:8) >
492
0
        (uint64_t)(p_container->i_pos + p_container->i_size) )
493
0
      )
494
0
    {
495
        /* there is no box to load */
496
0
        return 0;
497
0
    }
498
499
0
    uint64_t i_last_pos = 0; /* used to detect read failure loops */
500
0
    const uint64_t i_end = p_container->i_pos + p_container->i_size;
501
0
    MP4_Box_t *p_box = NULL;
502
0
    bool b_onexclude = false;
503
0
    bool b_continue;
504
0
    do
505
0
    {
506
0
        b_continue = false;
507
0
        if ( p_container->i_size )
508
0
        {
509
0
            const uint64_t i_tell = vlc_stream_Tell( p_stream );
510
0
            if( i_tell + ((b_indexed)?16:8) >= i_end )
511
0
                break;
512
0
        }
513
514
0
        uint32_t i_index = 0;
515
0
        if ( b_indexed )
516
0
        {
517
0
            uint8_t read[8];
518
0
            if ( vlc_stream_Read( p_stream, read, 8 ) < 8 )
519
0
                break;
520
0
            i_index = GetDWBE(&read[4]);
521
0
        }
522
0
        b_onexclude = false; /* If stopped due exclude list */
523
0
        if( (p_box = MP4_ReadBoxRestricted( p_stream, p_container, excludelist, &b_onexclude )) )
524
0
        {
525
0
            b_continue = true;
526
0
            p_box->i_index = i_index;
527
0
            for(size_t i=0; stoplist && stoplist[i]; i++)
528
0
            {
529
0
                if( p_box->i_type == stoplist[i] )
530
0
                    return 1;
531
0
            }
532
0
        }
533
534
0
        const uint64_t i_tell = vlc_stream_Tell( p_stream );
535
0
        if ( p_container->i_size && i_tell >= i_end )
536
0
        {
537
0
            assert( i_tell == i_end );
538
0
            break;
539
0
        }
540
541
0
        if ( !p_box )
542
0
        {
543
            /* Continue with next if box fails to load */
544
0
            if( i_last_pos == i_tell )
545
0
                break;
546
0
            i_last_pos = i_tell;
547
0
            b_continue = true;
548
0
        }
549
550
0
    } while( b_continue );
551
552
    /* Always move to end of container */
553
0
    if ( !b_onexclude &&  p_container->i_size )
554
0
    {
555
0
        const uint64_t i_tell = vlc_stream_Tell( p_stream );
556
0
        if ( i_tell != i_end )
557
0
            MP4_Seek( p_stream, i_end );
558
0
    }
559
560
0
    return 1;
561
0
}
562
563
int MP4_ReadBoxContainerRestricted( stream_t *p_stream, MP4_Box_t *p_container,
564
                                    const uint32_t stoplist[], const uint32_t excludelist[] )
565
0
{
566
0
    return MP4_ReadBoxContainerChildrenIndexed( p_stream, p_container,
567
0
                                                stoplist, excludelist, false );
568
0
}
569
570
int MP4_ReadBoxContainerChildren( stream_t *p_stream, MP4_Box_t *p_container,
571
                                  const uint32_t stoplist[] )
572
0
{
573
0
    return MP4_ReadBoxContainerChildrenIndexed( p_stream, p_container,
574
0
                                                stoplist, NULL, false );
575
0
}
576
577
static void MP4_BoxOffsetUp( MP4_Box_t *p_box, uint64_t i_offset )
578
0
{
579
0
    while(p_box)
580
0
    {
581
0
        p_box->i_pos += i_offset;
582
0
        MP4_BoxOffsetUp( p_box->p_first, i_offset );
583
0
        p_box = p_box->p_next;
584
0
    }
585
0
}
586
587
/* Reads within an already read/in memory box (containers without having to seek) */
588
static int MP4_ReadBoxContainerRawInBox( stream_t *p_stream, MP4_Box_t *p_container,
589
                                         uint8_t *p_buffer, uint64_t i_size, uint64_t i_offset )
590
0
{
591
0
    if(!p_container)
592
0
        return 0;
593
0
    stream_t *p_substream = vlc_stream_MemoryNew( p_stream, p_buffer, i_size,
594
0
                                                  true );
595
0
    if( !p_substream )
596
0
        return 0;
597
0
    MP4_Box_t *p_last = p_container->p_last;
598
0
    MP4_ReadBoxContainerChildren( p_substream, p_container, NULL );
599
0
    vlc_stream_Delete( p_substream );
600
    /* do pos fixup */
601
0
    if( p_container )
602
0
    {
603
0
        MP4_Box_t *p_box = p_last ? p_last : p_container->p_first;
604
0
        MP4_BoxOffsetUp(p_box, i_offset);
605
0
    }
606
607
0
    return 1;
608
0
}
609
610
static int MP4_ReadBoxContainer( stream_t *p_stream, MP4_Box_t *p_container )
611
0
{
612
0
    if( p_container->i_size &&
613
0
        ( p_container->i_size <= (size_t)mp4_box_headersize(p_container ) + 8 ) )
614
0
    {
615
        /* container is empty, 8 stand for the first header in this box */
616
0
        return 1;
617
0
    }
618
619
    /* enter box */
620
0
    if ( MP4_Seek( p_stream, p_container->i_pos +
621
0
                      mp4_box_headersize( p_container ) ) )
622
0
        return 0;
623
0
    return MP4_ReadBoxContainerChildren( p_stream, p_container, NULL );
624
0
}
625
626
static int MP4_ReadBoxSkip( stream_t *p_stream, MP4_Box_t *p_box )
627
0
{
628
    /* XXX sometime moov is hidden in a free box */
629
0
    if( p_box->p_father &&
630
0
        p_box->p_father->i_type == ATOM_root &&
631
0
        p_box->i_type == ATOM_free )
632
0
    {
633
0
        const uint8_t *p_peek;
634
0
        size_t header_size = mp4_box_headersize( p_box ) + 4;
635
0
        vlc_fourcc_t i_fcc;
636
637
0
        ssize_t i_read = vlc_stream_Peek( p_stream, &p_peek, 44 );
638
0
        if( unlikely(i_read < (ssize_t)header_size) )
639
0
            return 0;
640
641
0
        p_peek += header_size;
642
0
        i_read -= header_size;
643
644
0
        if( i_read >= 8 )
645
0
        {
646
0
            i_fcc = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] );
647
648
0
            if( i_fcc == ATOM_cmov || i_fcc == ATOM_mvhd )
649
0
            {
650
0
                msg_Warn( p_stream, "detected moov hidden in a free box ..." );
651
652
0
                p_box->i_type = ATOM_foov;
653
0
                return MP4_ReadBoxContainer( p_stream, p_box );
654
0
            }
655
0
        }
656
0
    }
657
658
    /* Nothing to do */
659
#ifdef MP4_ULTRA_VERBOSE
660
    if MP4_BOX_TYPE_ASCII()
661
        msg_Dbg( p_stream, "skip box: \"%4.4s\"", (char*)&p_box->i_type );
662
    else
663
        msg_Dbg( p_stream, "skip box: \"c%3.3s\"", (char*)&p_box->i_type+1 );
664
#endif
665
0
    return 1;
666
0
}
667
668
static int MP4_ReadBox_mdia( stream_t *p_stream, MP4_Box_t *p_container )
669
0
{
670
0
    if( p_container->i_size &&
671
0
        ( p_container->i_size <= (size_t)mp4_box_headersize(p_container ) + 8 ) )
672
0
    {
673
        /* container is empty, 8 stand for the first header in this box */
674
0
        return 1;
675
0
    }
676
677
    /* enter box */
678
0
    if ( MP4_Seek( p_stream, p_container->i_pos +
679
0
                               mp4_box_headersize( p_container ) ) )
680
0
        return 0;
681
0
    int ret = MP4_ReadBoxContainerChildren( p_stream, p_container, NULL );
682
0
    MP4_Box_t *stsd = MP4_BoxGet( p_container, "minf/stbl/stsd" );
683
0
    if( stsd && stsd->i_handler == 0 )
684
0
    {
685
        /* Delayed parsing due to missing hdlr */
686
0
        if( MP4_Seek( p_stream, stsd->i_pos ) ||
687
0
            MP4_Box_Read_Specific( p_stream, stsd, stsd->p_father ) ||
688
0
            stsd->i_handler == 0 )
689
0
            msg_Warn( p_stream, "Failed to re-parse stsd" );
690
0
    }
691
692
0
    return ret;
693
0
}
694
695
static int MP4_ReadBox_ilst( stream_t *p_stream, MP4_Box_t *p_box )
696
0
{
697
0
    if( p_box->i_size < 8 || vlc_stream_Read( p_stream, NULL, 8 ) != 8 )
698
0
        return 0;
699
700
    /* Find our handler */
701
0
    if ( !p_box->i_handler && p_box->p_father )
702
0
    {
703
0
        const MP4_Box_t *p_sibling = p_box->p_father->p_first;
704
0
        while( p_sibling )
705
0
        {
706
0
            if ( p_sibling->i_type == ATOM_hdlr && p_sibling->data.p_hdlr )
707
0
            {
708
0
                p_box->i_handler = p_sibling->data.p_hdlr->i_handler_type;
709
0
                break;
710
0
            }
711
0
            p_sibling = p_sibling->p_next;
712
0
        }
713
0
    }
714
715
0
    switch( p_box->i_handler )
716
0
    {
717
0
    case 0:
718
0
        msg_Warn( p_stream, "no handler for ilst atom" );
719
0
        return 0;
720
0
    case HANDLER_mdta:
721
0
        return MP4_ReadBoxContainerChildrenIndexed( p_stream, p_box, NULL, NULL, true );
722
0
    case HANDLER_mdir:
723
0
        return MP4_ReadBoxContainerChildren( p_stream, p_box, NULL );
724
0
    default:
725
0
        msg_Warn( p_stream, "Unknown ilst handler type '%4.4s'", (char*)&p_box->i_handler );
726
0
        return 0;
727
0
    }
728
0
}
729
730
static void MP4_FreeBox_ftyp( MP4_Box_t *p_box )
731
0
{
732
0
    free( p_box->data.p_ftyp->i_compatible_brands );
733
0
}
734
735
static int MP4_ReadBox_ftyp( stream_t *p_stream, MP4_Box_t *p_box )
736
0
{
737
0
    MP4_READBOX_ENTER( MP4_Box_data_ftyp_t, MP4_FreeBox_ftyp );
738
739
0
    MP4_GETFOURCC( p_box->data.p_ftyp->i_major_brand );
740
0
    MP4_GET4BYTES( p_box->data.p_ftyp->i_minor_version );
741
742
0
    p_box->data.p_ftyp->i_compatible_brands_count = i_read / 4;
743
0
    if( p_box->data.p_ftyp->i_compatible_brands_count > 0 )
744
0
    {
745
0
        uint32_t *tab = p_box->data.p_ftyp->i_compatible_brands =
746
0
            vlc_alloc( p_box->data.p_ftyp->i_compatible_brands_count,
747
0
                       sizeof(uint32_t) );
748
749
0
        if( unlikely( tab == NULL ) )
750
0
            MP4_READBOX_EXIT( 0 );
751
752
0
        for( unsigned i = 0; i < p_box->data.p_ftyp->i_compatible_brands_count; i++ )
753
0
        {
754
0
            MP4_GETFOURCC( tab[i] );
755
0
        }
756
0
    }
757
0
    else
758
0
    {
759
0
        p_box->data.p_ftyp->i_compatible_brands = NULL;
760
0
    }
761
762
0
    MP4_READBOX_EXIT( 1 );
763
0
}
764
765
766
static int MP4_ReadBox_mvhd(  stream_t *p_stream, MP4_Box_t *p_box )
767
0
{
768
0
    MP4_READBOX_ENTER( MP4_Box_data_mvhd_t, NULL );
769
770
0
    MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );
771
772
0
    if( p_box->data.p_mvhd->i_version )
773
0
    {
774
0
        MP4_GET8BYTES( p_box->data.p_mvhd->i_creation_time );
775
0
        MP4_GET8BYTES( p_box->data.p_mvhd->i_modification_time );
776
0
        MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
777
0
        MP4_GET8BYTES( p_box->data.p_mvhd->i_duration );
778
0
    }
779
0
    else
780
0
    {
781
0
        MP4_GET4BYTES( p_box->data.p_mvhd->i_creation_time );
782
0
        MP4_GET4BYTES( p_box->data.p_mvhd->i_modification_time );
783
0
        MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
784
0
        MP4_GET4BYTES( p_box->data.p_mvhd->i_duration );
785
0
    }
786
0
    MP4_GET4BYTES( p_box->data.p_mvhd->i_rate );
787
0
    MP4_GET2BYTES( p_box->data.p_mvhd->i_volume );
788
0
    MP4_GET2BYTES( p_box->data.p_mvhd->i_reserved1 );
789
790
791
0
    for( unsigned i = 0; i < 2; i++ )
792
0
    {
793
0
        MP4_GET4BYTES( p_box->data.p_mvhd->i_reserved2[i] );
794
0
    }
795
0
    for( unsigned i = 0; i < 9; i++ )
796
0
    {
797
0
        MP4_GET4BYTES( p_box->data.p_mvhd->i_matrix[i] );
798
0
    }
799
0
    for( unsigned i = 0; i < 6; i++ )
800
0
    {
801
0
        MP4_GET4BYTES( p_box->data.p_mvhd->i_predefined[i] );
802
0
    }
803
804
0
    MP4_GET4BYTES( p_box->data.p_mvhd->i_next_track_id );
805
806
807
0
#ifdef MP4_VERBOSE
808
0
    char *psz_duration = MP4_Time2Str( p_box->data.p_mvhd->i_duration, p_box->data.p_mvhd->i_timescale );
809
0
    msg_Dbg( p_stream, "read box: \"mvhd\" timescale %"PRIu32" duration %"PRIu64" (%s) rate %.2f volume %.2f",
810
0
                  p_box->data.p_mvhd->i_timescale,
811
0
                  p_box->data.p_mvhd->i_duration,
812
0
                  psz_duration,
813
0
                  (float)p_box->data.p_mvhd->i_rate / (1<<16 ),
814
0
                  (float)p_box->data.p_mvhd->i_volume / 256 );
815
0
    free( psz_duration );
816
0
#endif
817
0
    MP4_READBOX_EXIT( 1 );
818
0
}
819
820
static int MP4_ReadBox_mfhd(  stream_t *p_stream, MP4_Box_t *p_box )
821
0
{
822
0
    MP4_READBOX_ENTER( MP4_Box_data_mfhd_t, NULL );
823
824
0
    MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );
825
826
0
    MP4_GET4BYTES( p_box->data.p_mfhd->i_sequence_number );
827
828
0
#ifdef MP4_VERBOSE
829
0
    msg_Dbg( p_stream, "read box: \"mfhd\" sequence number %d",
830
0
                  p_box->data.p_mfhd->i_sequence_number );
831
0
#endif
832
0
    MP4_READBOX_EXIT( 1 );
833
0
}
834
835
static int MP4_ReadBox_tfxd(  stream_t *p_stream, MP4_Box_t *p_box )
836
0
{
837
0
    MP4_READBOX_ENTER( MP4_Box_data_tfxd_t, NULL );
838
839
0
    MP4_Box_data_tfxd_t *p_tfxd_data = p_box->data.p_tfxd;
840
0
    MP4_GETVERSIONFLAGS( p_tfxd_data );
841
842
0
    if( p_tfxd_data->i_version == 0 )
843
0
    {
844
0
        MP4_GET4BYTES( p_tfxd_data->i_fragment_abs_time );
845
0
        MP4_GET4BYTES( p_tfxd_data->i_fragment_duration );
846
0
    }
847
0
    else
848
0
    {
849
0
        MP4_GET8BYTES( p_tfxd_data->i_fragment_abs_time );
850
0
        MP4_GET8BYTES( p_tfxd_data->i_fragment_duration );
851
0
    }
852
853
0
#ifdef MP4_VERBOSE
854
0
    msg_Dbg( p_stream, "read box: \"tfxd\" version %d, flags 0x%x, "\
855
0
            "fragment duration %"PRIu64", fragment abs time %"PRIu64,
856
0
                p_tfxd_data->i_version,
857
0
                p_tfxd_data->i_flags,
858
0
                p_tfxd_data->i_fragment_duration,
859
0
                p_tfxd_data->i_fragment_abs_time
860
0
           );
861
0
#endif
862
863
0
    MP4_READBOX_EXIT( 1 );
864
0
}
865
866
static void MP4_FreeBox_tfrf( MP4_Box_t *p_box )
867
0
{
868
0
    free( p_box->data.p_tfrf->p_tfrf_data_fields );
869
0
}
870
871
static int MP4_ReadBox_tfrf(  stream_t *p_stream, MP4_Box_t *p_box )
872
0
{
873
0
    MP4_READBOX_ENTER( MP4_Box_data_tfxd_t, MP4_FreeBox_tfrf );
874
875
0
    MP4_Box_data_tfrf_t *p_tfrf_data = p_box->data.p_tfrf;
876
0
    MP4_GETVERSIONFLAGS( p_tfrf_data );
877
878
0
    MP4_GET1BYTE( p_tfrf_data->i_fragment_count );
879
880
0
    p_tfrf_data->p_tfrf_data_fields = calloc( p_tfrf_data->i_fragment_count,
881
0
                                              sizeof( TfrfBoxDataFields_t ) );
882
0
    if( !p_tfrf_data->p_tfrf_data_fields )
883
0
        MP4_READBOX_EXIT( 0 );
884
885
0
    for( uint8_t i = 0; i < p_tfrf_data->i_fragment_count; i++ )
886
0
    {
887
0
        TfrfBoxDataFields_t *TfrfBoxDataField = &p_tfrf_data->p_tfrf_data_fields[i];
888
0
        if( p_tfrf_data->i_version == 0 )
889
0
        {
890
0
            MP4_GET4BYTES( TfrfBoxDataField->i_fragment_abs_time );
891
0
            MP4_GET4BYTES( TfrfBoxDataField->i_fragment_duration );
892
0
        }
893
0
        else
894
0
        {
895
0
            MP4_GET8BYTES( TfrfBoxDataField->i_fragment_abs_time );
896
0
            MP4_GET8BYTES( TfrfBoxDataField->i_fragment_duration );
897
0
        }
898
0
    }
899
900
0
#ifdef MP4_VERBOSE
901
0
    msg_Dbg( p_stream, "read box: \"tfrf\" version %d, flags 0x%x, "\
902
0
            "fragment count %"PRIu8, p_tfrf_data->i_version,
903
0
                p_tfrf_data->i_flags, p_tfrf_data->i_fragment_count );
904
905
0
    for( uint8_t i = 0; i < p_tfrf_data->i_fragment_count; i++ )
906
0
    {
907
0
        TfrfBoxDataFields_t *TfrfBoxDataField = &p_tfrf_data->p_tfrf_data_fields[i];
908
0
        msg_Dbg( p_stream, "\"tfrf\" fragment duration %"PRIu64", "\
909
0
                                    "fragment abs time %"PRIu64,
910
0
                    TfrfBoxDataField->i_fragment_duration,
911
0
                    TfrfBoxDataField->i_fragment_abs_time );
912
0
    }
913
914
0
#endif
915
916
0
    MP4_READBOX_EXIT( 1 );
917
0
}
918
919
static int MP4_ReadBox_XML360( stream_t *p_stream, MP4_Box_t *p_box )
920
0
{
921
0
    MP4_READBOX_ENTER( MP4_Box_data_360_t, NULL );
922
923
0
    MP4_Box_data_360_t *p_360_data = p_box->data.p_360;
924
925
    /* Copy the string for pattern matching as it does not end
926
    with a '\0' in the stream. */
927
0
    char *psz_rdf = strndup((char *)p_peek, i_read);
928
929
0
    if ( unlikely( !psz_rdf ) )
930
0
        MP4_READBOX_EXIT( 0 );
931
932
    /* Try to find the string "GSpherical:Spherical" because the v1
933
    spherical video spec says the tag must be there. */
934
935
0
    if ( strcasestr( psz_rdf, "Gspherical:Spherical" ) )
936
0
        p_360_data->i_projection_mode = PROJECTION_MODE_EQUIRECTANGULAR;
937
938
    /* Try to find the stero mode. */
939
0
    if ( strcasestr( psz_rdf, "left-right" ) )
940
0
    {
941
0
        msg_Dbg( p_stream, "Left-right stereo mode" );
942
0
        p_360_data->e_stereo_mode = XML360_STEREOSCOPIC_LEFT_RIGHT;
943
0
    }
944
945
0
    if ( strcasestr( psz_rdf, "top-bottom" ) )
946
0
    {
947
0
        msg_Dbg( p_stream, "Top-bottom stereo mode" );
948
0
        p_360_data->e_stereo_mode = XML360_STEREOSCOPIC_TOP_BOTTOM;
949
0
    }
950
951
0
    free( psz_rdf );
952
953
0
    MP4_READBOX_EXIT( 1 );
954
0
}
955
956
static int MP4_ReadBox_st3d( stream_t *p_stream, MP4_Box_t *p_box )
957
0
{
958
0
    MP4_READBOX_ENTER( MP4_Box_data_st3d_t, NULL );
959
960
0
    uint8_t i_version;
961
0
    MP4_GET1BYTE( i_version );
962
0
    if ( i_version != 0 )
963
0
        MP4_READBOX_EXIT( 0 );
964
965
0
    uint32_t i_flags;
966
0
    VLC_UNUSED( i_flags );
967
0
    MP4_GET3BYTES( i_flags );
968
969
0
    MP4_Box_data_st3d_t *p_data = p_box->data.p_st3d;
970
0
    MP4_GET1BYTE( p_data->i_stereo_mode );
971
972
0
    MP4_READBOX_EXIT( 1 );
973
0
}
974
975
static int MP4_ReadBox_prhd( stream_t *p_stream, MP4_Box_t *p_box )
976
0
{
977
0
    MP4_READBOX_ENTER( MP4_Box_data_prhd_t, NULL );
978
979
0
    uint8_t i_version;
980
0
    MP4_GET1BYTE( i_version );
981
0
    if (i_version != 0)
982
0
        MP4_READBOX_EXIT( 0 );
983
984
0
    uint32_t i_flags;
985
0
    VLC_UNUSED( i_flags );
986
0
    MP4_GET3BYTES( i_flags );
987
988
0
    MP4_Box_data_prhd_t *p_data = p_box->data.p_prhd;
989
0
    int32_t fixed16_16;
990
0
    MP4_GET4BYTES( fixed16_16 );
991
0
    p_data->f_pose_yaw_degrees   = (float) fixed16_16 / 65536.0f;
992
993
0
    MP4_GET4BYTES( fixed16_16 );
994
0
    p_data->f_pose_pitch_degrees = (float) fixed16_16 / 65536.0f;
995
996
0
    MP4_GET4BYTES( fixed16_16 );
997
0
    p_data->f_pose_roll_degrees  = (float) fixed16_16 / 65536.0f;
998
999
0
    MP4_READBOX_EXIT( 1 );
1000
0
}
1001
1002
static int MP4_ReadBox_equi( stream_t *p_stream, MP4_Box_t *p_box )
1003
0
{
1004
0
    MP4_READBOX_ENTER( MP4_Box_data_equi_t, NULL );
1005
1006
0
    uint8_t i_version;
1007
0
    MP4_GET1BYTE( i_version );
1008
0
    if (i_version != 0)
1009
0
        MP4_READBOX_EXIT( 0 );
1010
1011
0
    uint32_t i_flags;
1012
0
    VLC_UNUSED( i_flags );
1013
0
    MP4_GET3BYTES( i_flags );
1014
1015
0
    MP4_Box_data_equi_t *p_data = p_box->data.p_equi;
1016
0
    MP4_GET4BYTES( p_data->i_projection_bounds_top );
1017
0
    MP4_GET4BYTES( p_data->i_projection_bounds_bottom );
1018
0
    MP4_GET4BYTES( p_data->i_projection_bounds_left );
1019
0
    MP4_GET4BYTES( p_data->i_projection_bounds_right );
1020
1021
0
    MP4_READBOX_EXIT( 1 );
1022
0
}
1023
1024
static int MP4_ReadBox_cbmp( stream_t *p_stream, MP4_Box_t *p_box )
1025
0
{
1026
0
    MP4_READBOX_ENTER( MP4_Box_data_cbmp_t, NULL );
1027
1028
0
    uint8_t i_version;
1029
0
    MP4_GET1BYTE( i_version );
1030
0
    if (i_version != 0)
1031
0
        MP4_READBOX_EXIT( 0 );
1032
1033
0
    uint32_t i_flags;
1034
0
    VLC_UNUSED( i_flags );
1035
0
    MP4_GET3BYTES( i_flags );
1036
1037
0
    MP4_Box_data_cbmp_t *p_data = p_box->data.p_cbmp;
1038
0
    MP4_GET4BYTES( p_data->i_layout );
1039
0
    MP4_GET4BYTES( p_data->i_padding );
1040
1041
0
    MP4_READBOX_EXIT( 1 );
1042
0
}
1043
1044
static void MP4_FreeBox_sidx( MP4_Box_t *p_box )
1045
0
{
1046
0
    free( p_box->data.p_sidx->p_items );
1047
0
}
1048
1049
static int MP4_ReadBox_sidx(  stream_t *p_stream, MP4_Box_t *p_box )
1050
0
{
1051
0
    MP4_READBOX_ENTER( MP4_Box_data_sidx_t, MP4_FreeBox_sidx );
1052
1053
0
    MP4_Box_data_sidx_t *p_sidx_data = p_box->data.p_sidx;
1054
0
    MP4_GETVERSIONFLAGS( p_sidx_data );
1055
1056
0
    MP4_GET4BYTES( p_sidx_data->i_reference_ID );
1057
0
    MP4_GET4BYTES( p_sidx_data->i_timescale );
1058
1059
0
    if( p_sidx_data->i_version == 0 )
1060
0
    {
1061
0
        MP4_GET4BYTES( p_sidx_data->i_earliest_presentation_time );
1062
0
        MP4_GET4BYTES( p_sidx_data->i_first_offset );
1063
0
    }
1064
0
    else
1065
0
    {
1066
0
        MP4_GET8BYTES( p_sidx_data->i_earliest_presentation_time );
1067
0
        MP4_GET8BYTES( p_sidx_data->i_first_offset );
1068
0
    }
1069
1070
0
    uint16_t i_reserved, i_count;
1071
1072
0
    VLC_UNUSED(i_reserved);
1073
0
    MP4_GET2BYTES( i_reserved );
1074
0
    MP4_GET2BYTES( i_count );
1075
0
    if( i_count == 0 )
1076
0
        MP4_READBOX_EXIT( 1 );
1077
1078
0
    p_sidx_data->i_reference_count = i_count;
1079
0
    p_sidx_data->p_items = vlc_alloc( i_count, sizeof( MP4_Box_sidx_item_t ) );
1080
0
    if( unlikely(p_sidx_data->p_items == NULL) )
1081
0
        MP4_READBOX_EXIT( 0 );
1082
1083
0
    for( unsigned i = 0; i < i_count; i++ )
1084
0
    {
1085
0
        MP4_Box_sidx_item_t *item = p_sidx_data->p_items + i;
1086
0
        uint32_t tmp;
1087
1088
0
        MP4_GET4BYTES( tmp );
1089
0
        item->b_reference_type = tmp >> 31;
1090
0
        item->i_referenced_size = tmp & 0x7fffffff;
1091
0
        MP4_GET4BYTES( item->i_subsegment_duration );
1092
1093
0
        MP4_GET4BYTES( tmp );
1094
0
        item->b_starts_with_SAP = tmp >> 31;
1095
0
        item->i_SAP_type = (tmp >> 24) & 0x70;
1096
0
        item->i_SAP_delta_time = tmp & 0xfffffff;
1097
0
    }
1098
1099
0
#ifdef MP4_VERBOSE
1100
0
    msg_Dbg( p_stream, "read box: \"sidx\" version %d, flags 0x%x, "\
1101
0
            "ref_ID %"PRIu32", timescale %"PRIu32", ref_count %"PRIu16", "\
1102
0
            "first subsegmt duration %"PRIu32,
1103
0
                p_sidx_data->i_version,
1104
0
                p_sidx_data->i_flags,
1105
0
                p_sidx_data->i_reference_ID,
1106
0
                p_sidx_data->i_timescale,
1107
0
                p_sidx_data->i_reference_count,
1108
0
                p_sidx_data->p_items[0].i_subsegment_duration
1109
0
           );
1110
0
#endif
1111
1112
0
    MP4_READBOX_EXIT( 1 );
1113
0
}
1114
1115
static int MP4_ReadBox_tfhd(  stream_t *p_stream, MP4_Box_t *p_box )
1116
0
{
1117
0
    MP4_READBOX_ENTER( MP4_Box_data_tfhd_t, NULL );
1118
1119
0
    MP4_GETVERSIONFLAGS( p_box->data.p_tfhd );
1120
1121
0
    if( p_box->data.p_tfhd->i_version != 0 )
1122
0
    {
1123
0
        msg_Warn( p_stream, "'tfhd' box with version != 0. "\
1124
0
                " Don't know what to do with that, please patch" );
1125
0
        MP4_READBOX_EXIT( 0 );
1126
0
    }
1127
1128
0
    MP4_GET4BYTES( p_box->data.p_tfhd->i_track_ID );
1129
1130
0
    if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DURATION_IS_EMPTY )
1131
0
    {
1132
0
        msg_Dbg( p_stream, "'duration-is-empty' flag is present "\
1133
0
                "=> no samples for this time interval." );
1134
0
        p_box->data.p_tfhd->b_empty = true;
1135
0
    }
1136
0
    else
1137
0
        p_box->data.p_tfhd->b_empty = false;
1138
1139
0
    if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
1140
0
        MP4_GET8BYTES( p_box->data.p_tfhd->i_base_data_offset );
1141
0
    if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
1142
0
        MP4_GET4BYTES( p_box->data.p_tfhd->i_sample_description_index );
1143
0
    if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
1144
0
        MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_duration );
1145
0
    if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
1146
0
        MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_size );
1147
0
    if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
1148
0
        MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_flags );
1149
1150
0
#ifdef MP4_VERBOSE
1151
0
    char psz_base[128] = "\0";
1152
0
    char psz_desc[128] = "\0";
1153
0
    char psz_dura[128] = "\0";
1154
0
    char psz_size[128] = "\0";
1155
0
    char psz_flag[128] = "\0";
1156
0
    if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
1157
0
        snprintf(psz_base, sizeof(psz_base), "base offset %"PRId64, p_box->data.p_tfhd->i_base_data_offset);
1158
0
    if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
1159
0
        snprintf(psz_desc, sizeof(psz_desc), "sample description index %d", p_box->data.p_tfhd->i_sample_description_index);
1160
0
    if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
1161
0
        snprintf(psz_dura, sizeof(psz_dura), "sample duration %d", p_box->data.p_tfhd->i_default_sample_duration);
1162
0
    if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
1163
0
        snprintf(psz_size, sizeof(psz_size), "sample size %d", p_box->data.p_tfhd->i_default_sample_size);
1164
0
    if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
1165
0
        snprintf(psz_flag, sizeof(psz_flag), "sample flags 0x%x", p_box->data.p_tfhd->i_default_sample_flags);
1166
1167
0
    msg_Dbg( p_stream, "read box: \"tfhd\" version %d flags 0x%x track ID %d %s %s %s %s %s",
1168
0
                p_box->data.p_tfhd->i_version,
1169
0
                p_box->data.p_tfhd->i_flags,
1170
0
                p_box->data.p_tfhd->i_track_ID,
1171
0
                psz_base, psz_desc, psz_dura, psz_size, psz_flag );
1172
0
#endif
1173
1174
0
    MP4_READBOX_EXIT( 1 );
1175
0
}
1176
1177
static void MP4_FreeBox_trun( MP4_Box_t *p_box )
1178
0
{
1179
0
    free( p_box->data.p_trun->p_samples );
1180
0
}
1181
1182
static int MP4_ReadBox_trun(  stream_t *p_stream, MP4_Box_t *p_box )
1183
0
{
1184
0
    uint32_t count;
1185
1186
0
    MP4_READBOX_ENTER( MP4_Box_data_trun_t, MP4_FreeBox_trun );
1187
0
    MP4_Box_data_trun_t *p_trun = p_box->data.p_trun;
1188
0
    MP4_GETVERSIONFLAGS( p_trun );
1189
0
    MP4_GET4BYTES( count );
1190
1191
0
    if( p_trun->i_flags & MP4_TRUN_DATA_OFFSET )
1192
0
        MP4_GET4BYTES( p_trun->i_data_offset );
1193
0
    if( p_trun->i_flags & MP4_TRUN_FIRST_FLAGS )
1194
0
        MP4_GET4BYTES( p_trun->i_first_sample_flags );
1195
1196
0
    uint64_t i_entry_size =
1197
0
        !!(p_trun->i_flags & MP4_TRUN_SAMPLE_DURATION) +
1198
0
        !!(p_trun->i_flags & MP4_TRUN_SAMPLE_SIZE) +
1199
0
        !!(p_trun->i_flags & MP4_TRUN_SAMPLE_FLAGS) +
1200
0
        !!(p_trun->i_flags & MP4_TRUN_SAMPLE_TIME_OFFSET);
1201
1202
0
    if( i_entry_size * 4 * count > i_read )
1203
0
        MP4_READBOX_EXIT( 0 );
1204
1205
0
    p_trun->p_samples = vlc_alloc( count, sizeof(MP4_descriptor_trun_sample_t) );
1206
0
    if ( p_trun->p_samples == NULL )
1207
0
        MP4_READBOX_EXIT( 0 );
1208
0
    p_trun->i_sample_count = count;
1209
1210
0
    for( unsigned int i = 0; i < count; i++ )
1211
0
    {
1212
0
        MP4_descriptor_trun_sample_t *p_sample = &p_trun->p_samples[i];
1213
0
        if( p_trun->i_flags & MP4_TRUN_SAMPLE_DURATION )
1214
0
            MP4_GET4BYTES( p_sample->i_duration );
1215
0
        if( p_trun->i_flags & MP4_TRUN_SAMPLE_SIZE )
1216
0
            MP4_GET4BYTES( p_sample->i_size );
1217
0
        if( p_trun->i_flags & MP4_TRUN_SAMPLE_FLAGS )
1218
0
            MP4_GET4BYTES( p_sample->i_flags );
1219
0
        if( p_trun->i_flags & MP4_TRUN_SAMPLE_TIME_OFFSET )
1220
0
            MP4_GET4BYTES( p_sample->i_composition_time_offset.v0 );
1221
0
    }
1222
1223
#ifdef MP4_ULTRA_VERBOSE
1224
    msg_Dbg( p_stream, "read box: \"trun\" version %u flags 0x%x sample count %"PRIu32,
1225
                  p_trun->i_version,
1226
                  p_trun->i_flags,
1227
                  p_trun->i_sample_count );
1228
1229
    for( unsigned int i = 0; i < count; i++ )
1230
    {
1231
        MP4_descriptor_trun_sample_t *p_sample = &p_trun->p_samples[i];
1232
        msg_Dbg( p_stream, "read box: \"trun\" sample %4.4u flags 0x%x "\
1233
            "duration %"PRIu32" size %"PRIu32" composition time offset %"PRIu32,
1234
                        i, p_sample->i_flags, p_sample->i_duration,
1235
                        p_sample->i_size, p_sample->i_composition_time_offset );
1236
    }
1237
#endif
1238
1239
0
    MP4_READBOX_EXIT( 1 );
1240
0
}
1241
1242
static int MP4_ReadBox_tfdt( stream_t *p_stream, MP4_Box_t *p_box )
1243
0
{
1244
0
    MP4_READBOX_ENTER( MP4_Box_data_tfdt_t, NULL );
1245
0
    if( i_read < 8 )
1246
0
        MP4_READBOX_EXIT( 0 );
1247
1248
0
    MP4_GETVERSIONFLAGS( p_box->data.p_tfdt );
1249
1250
0
    if( p_box->data.p_tfdt->i_version == 0 )
1251
0
        MP4_GET4BYTES( p_box->data.p_tfdt->i_base_media_decode_time );
1252
0
    else if( p_box->data.p_tfdt->i_version == 1 )
1253
0
        MP4_GET8BYTES( p_box->data.p_tfdt->i_base_media_decode_time );
1254
0
    else
1255
0
        MP4_READBOX_EXIT( 0 );
1256
1257
0
    MP4_READBOX_EXIT( 1 );
1258
0
}
1259
1260
static int MP4_ReadBox_tkhd(  stream_t *p_stream, MP4_Box_t *p_box )
1261
0
{
1262
0
    MP4_READBOX_ENTER( MP4_Box_data_tkhd_t, NULL );
1263
1264
0
    MP4_GETVERSIONFLAGS( p_box->data.p_tkhd );
1265
1266
0
    if( p_box->data.p_tkhd->i_version )
1267
0
    {
1268
0
        MP4_GET8BYTES( p_box->data.p_tkhd->i_creation_time );
1269
0
        MP4_GET8BYTES( p_box->data.p_tkhd->i_modification_time );
1270
0
        MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
1271
0
        MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
1272
0
        MP4_GET8BYTES( p_box->data.p_tkhd->i_duration );
1273
0
    }
1274
0
    else
1275
0
    {
1276
0
        MP4_GET4BYTES( p_box->data.p_tkhd->i_creation_time );
1277
0
        MP4_GET4BYTES( p_box->data.p_tkhd->i_modification_time );
1278
0
        MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
1279
0
        MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
1280
0
        MP4_GET4BYTES( p_box->data.p_tkhd->i_duration );
1281
0
    }
1282
1283
0
    for( unsigned i = 0; i < 2; i++ )
1284
0
    {
1285
0
        MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved2[i] );
1286
0
    }
1287
0
    MP4_GET2BYTES( p_box->data.p_tkhd->i_layer );
1288
0
    MP4_GET2BYTES( p_box->data.p_tkhd->i_predefined );
1289
0
    MP4_GET2BYTES( p_box->data.p_tkhd->i_volume );
1290
0
    MP4_GET2BYTES( p_box->data.p_tkhd->i_reserved3 );
1291
1292
0
    for( unsigned i = 0; i < 9; i++ )
1293
0
    {
1294
0
        MP4_GET4BYTES( p_box->data.p_tkhd->i_matrix[i] );
1295
0
    }
1296
0
    MP4_GET4BYTES( p_box->data.p_tkhd->i_width );
1297
0
    MP4_GET4BYTES( p_box->data.p_tkhd->i_height );
1298
1299
0
    double rotation = 0;//angle in degrees to be rotated clockwise
1300
0
    double scale[2];    // scale factor; sx = scale[0] , sy = scale[1]
1301
0
    int32_t *matrix = p_box->data.p_tkhd->i_matrix;
1302
1303
0
    int64_t det = (int64_t)matrix[0] * matrix[4] - (int64_t)matrix[1] * matrix[3];
1304
0
    if (det < 0) {
1305
        /* If determinant is negative copy the matrix and flip it horizontally. */
1306
0
        const int flip[] = { -1, 1, 1 };
1307
0
        for (int j = 0; j < 9; j++)
1308
0
            matrix[j] *= flip[j % 3];
1309
0
        p_box->data.p_tkhd->i_flip = 1;
1310
0
    }
1311
1312
0
    scale[0] = sqrt(conv_fx(matrix[0]) * conv_fx(matrix[0]) +
1313
0
                    conv_fx(matrix[3]) * conv_fx(matrix[3]));
1314
0
    scale[1] = sqrt(conv_fx(matrix[1]) * conv_fx(matrix[1]) +
1315
0
                    conv_fx(matrix[4]) * conv_fx(matrix[4]));
1316
1317
0
    if( likely(scale[0] > 0 && scale[1] > 0) )
1318
0
    {
1319
0
        rotation = atan2(conv_fx(matrix[1]) / scale[1],
1320
0
                         conv_fx(matrix[0]) / scale[0]) * 180 / M_PI;
1321
0
        if (rotation < 0)
1322
0
            rotation += 360.;
1323
0
    }
1324
1325
0
    p_box->data.p_tkhd->f_rotation = rotation;
1326
1327
0
#ifdef MP4_VERBOSE
1328
0
    double translate[2];// amount to translate; tx = translate[0] , ty = translate[1]
1329
1330
0
    translate[0] = conv_fx(matrix[6]);
1331
0
    translate[1] = conv_fx(matrix[7]);
1332
1333
0
    msg_Dbg( p_stream, "read box: \"tkhd\" track #%"PRIu32" duration %"PRIu64" layer %d "
1334
0
                       "volume %3.1f rotation %3.1f scale %.2fx%.2f translate +%.2f+%.2f size %ux%u. "
1335
0
                       "Matrix: %i %i %i %i %i %i %i %i %i",
1336
0
                  p_box->data.p_tkhd->i_track_ID,
1337
0
                  p_box->data.p_tkhd->i_duration,
1338
0
                  p_box->data.p_tkhd->i_layer,
1339
0
                  (float)p_box->data.p_tkhd->i_volume / 256 ,
1340
0
                  rotation,
1341
0
                  scale[0],
1342
0
                  scale[1],
1343
0
                  translate[0],
1344
0
                  translate[1],
1345
0
                  (unsigned)p_box->data.p_tkhd->i_width / BLOCK16x16,
1346
0
                  (unsigned)p_box->data.p_tkhd->i_height / BLOCK16x16,
1347
0
                  p_box->data.p_tkhd->i_matrix[0],
1348
0
                  p_box->data.p_tkhd->i_matrix[1],
1349
0
                  p_box->data.p_tkhd->i_matrix[2],
1350
0
                  p_box->data.p_tkhd->i_matrix[3],
1351
0
                  p_box->data.p_tkhd->i_matrix[4],
1352
0
                  p_box->data.p_tkhd->i_matrix[5],
1353
0
                  p_box->data.p_tkhd->i_matrix[6],
1354
0
                  p_box->data.p_tkhd->i_matrix[7],
1355
0
                  p_box->data.p_tkhd->i_matrix[8] );
1356
0
#endif
1357
0
    MP4_READBOX_EXIT( 1 );
1358
0
}
1359
1360
static int MP4_ReadBox_load( stream_t *p_stream, MP4_Box_t *p_box )
1361
0
{
1362
0
    if ( p_box->i_size != 24 )
1363
0
        return 0;
1364
0
    MP4_READBOX_ENTER( MP4_Box_data_load_t, NULL );
1365
0
    MP4_GET4BYTES( p_box->data.p_load->i_start_time );
1366
0
    MP4_GET4BYTES( p_box->data.p_load->i_duration );
1367
0
    MP4_GET4BYTES( p_box->data.p_load->i_flags );
1368
0
    MP4_GET4BYTES( p_box->data.p_load->i_hints );
1369
0
    MP4_READBOX_EXIT( 1 );
1370
0
}
1371
1372
static int MP4_ReadBox_mdhd( stream_t *p_stream, MP4_Box_t *p_box )
1373
0
{
1374
0
    uint16_t i_language;
1375
0
    MP4_READBOX_ENTER( MP4_Box_data_mdhd_t, NULL );
1376
1377
0
    MP4_GETVERSIONFLAGS( p_box->data.p_mdhd );
1378
1379
0
    if( p_box->data.p_mdhd->i_version )
1380
0
    {
1381
0
        MP4_GET8BYTES( p_box->data.p_mdhd->i_creation_time );
1382
0
        MP4_GET8BYTES( p_box->data.p_mdhd->i_modification_time );
1383
0
        MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
1384
0
        MP4_GET8BYTES( p_box->data.p_mdhd->i_duration );
1385
0
    }
1386
0
    else
1387
0
    {
1388
0
        MP4_GET4BYTES( p_box->data.p_mdhd->i_creation_time );
1389
0
        MP4_GET4BYTES( p_box->data.p_mdhd->i_modification_time );
1390
0
        MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
1391
0
        MP4_GET4BYTES( p_box->data.p_mdhd->i_duration );
1392
0
    }
1393
1394
0
    MP4_GET2BYTES( i_language );
1395
0
    decodeQtLanguageCode( i_language, p_box->data.p_mdhd->rgs_language,
1396
0
                          &p_box->data.p_mdhd->b_mac_encoding );
1397
1398
0
    MP4_GET2BYTES( p_box->data.p_mdhd->i_quality );
1399
1400
0
#ifdef MP4_VERBOSE
1401
0
    char *psz_duration = MP4_Time2Str( p_box->data.p_mdhd->i_duration, p_box->data.p_mdhd->i_timescale );
1402
0
    msg_Dbg( p_stream, "read box: \"mdhd\" timescale %"PRIu32" duration %"PRIu64" (%s) language %3.3s",
1403
0
                  p_box->data.p_mdhd->i_timescale,
1404
0
                  p_box->data.p_mdhd->i_duration,
1405
0
                  psz_duration,
1406
0
                  (char*) &p_box->data.p_mdhd->rgs_language );
1407
0
    free( psz_duration );
1408
0
#endif
1409
0
    MP4_READBOX_EXIT( 1 );
1410
0
}
1411
1412
static void MP4_FreeBox_hdlr( MP4_Box_t *p_box )
1413
0
{
1414
0
    free( p_box->data.p_hdlr->psz_name );
1415
0
}
1416
1417
static int MP4_ReadBox_hdlr( stream_t *p_stream, MP4_Box_t *p_box )
1418
0
{
1419
0
    int32_t i_reserved;
1420
0
    VLC_UNUSED(i_reserved);
1421
1422
0
    MP4_READBOX_ENTER( MP4_Box_data_hdlr_t, MP4_FreeBox_hdlr );
1423
1424
0
    MP4_GETVERSIONFLAGS( p_box->data.p_hdlr );
1425
1426
0
    MP4_GETFOURCC( p_box->data.p_hdlr->i_predefined );
1427
0
    MP4_GETFOURCC( p_box->data.p_hdlr->i_handler_type );
1428
1429
0
    MP4_GET4BYTES( i_reserved );
1430
0
    MP4_GET4BYTES( i_reserved );
1431
0
    MP4_GET4BYTES( i_reserved );
1432
0
    p_box->data.p_hdlr->psz_name = NULL;
1433
1434
0
    if( i_read >= SSIZE_MAX )
1435
0
        MP4_READBOX_EXIT( 0 );
1436
1437
0
    if( i_read > 0 )
1438
0
    {
1439
0
        size_t i_copy;
1440
1441
        /* Yes, I love .mp4 :( */
1442
0
        if( p_box->data.p_hdlr->i_predefined == VLC_FOURCC( 'm', 'h', 'l', 'r' ) )
1443
0
        {
1444
0
            uint8_t i_len;
1445
1446
0
            MP4_GET1BYTE( i_len );
1447
0
            i_copy = (i_len <= i_read) ? i_len : i_read;
1448
0
        }
1449
0
        else
1450
0
            i_copy = i_read;
1451
1452
0
        uint8_t *psz = p_box->data.p_hdlr->psz_name = malloc( i_copy + 1 );
1453
0
        if( unlikely( psz == NULL ) )
1454
0
            MP4_READBOX_EXIT( 0 );
1455
1456
0
        memcpy( psz, p_peek, i_copy );
1457
0
        p_box->data.p_hdlr->psz_name[i_copy] = '\0';
1458
0
    }
1459
1460
0
#ifdef MP4_VERBOSE
1461
0
        msg_Dbg( p_stream, "read box: \"hdlr\" handler type: \"%4.4s\" name: \"%s\"",
1462
0
                   (char*)&p_box->data.p_hdlr->i_handler_type,
1463
0
                   p_box->data.p_hdlr->psz_name );
1464
1465
0
#endif
1466
0
    MP4_READBOX_EXIT( 1 );
1467
0
}
1468
1469
static int MP4_ReadBox_vmhd( stream_t *p_stream, MP4_Box_t *p_box )
1470
0
{
1471
0
    MP4_READBOX_ENTER( MP4_Box_data_vmhd_t, NULL );
1472
1473
0
    MP4_GETVERSIONFLAGS( p_box->data.p_vmhd );
1474
1475
0
    MP4_GET2BYTES( p_box->data.p_vmhd->i_graphics_mode );
1476
0
    for( unsigned i = 0; i < 3; i++ )
1477
0
    {
1478
0
        MP4_GET2BYTES( p_box->data.p_vmhd->i_opcolor[i] );
1479
0
    }
1480
1481
0
#ifdef MP4_VERBOSE
1482
0
    msg_Dbg( p_stream, "read box: \"vmhd\" graphics-mode %d opcolor (%d, %d, %d)",
1483
0
                      p_box->data.p_vmhd->i_graphics_mode,
1484
0
                      p_box->data.p_vmhd->i_opcolor[0],
1485
0
                      p_box->data.p_vmhd->i_opcolor[1],
1486
0
                      p_box->data.p_vmhd->i_opcolor[2] );
1487
0
#endif
1488
0
    MP4_READBOX_EXIT( 1 );
1489
0
}
1490
1491
static int MP4_ReadBox_smhd( stream_t *p_stream, MP4_Box_t *p_box )
1492
0
{
1493
0
    MP4_READBOX_ENTER( MP4_Box_data_smhd_t, NULL );
1494
1495
0
    MP4_GETVERSIONFLAGS( p_box->data.p_smhd );
1496
1497
1498
1499
0
    MP4_GET2BYTES( p_box->data.p_smhd->i_balance );
1500
1501
0
    MP4_GET2BYTES( p_box->data.p_smhd->i_reserved );
1502
1503
0
#ifdef MP4_VERBOSE
1504
0
    msg_Dbg( p_stream, "read box: \"smhd\" balance %f",
1505
0
                      (float)p_box->data.p_smhd->i_balance / 256 );
1506
0
#endif
1507
0
    MP4_READBOX_EXIT( 1 );
1508
0
}
1509
1510
1511
static int MP4_ReadBox_hmhd( stream_t *p_stream, MP4_Box_t *p_box )
1512
0
{
1513
0
    MP4_READBOX_ENTER( MP4_Box_data_hmhd_t, NULL );
1514
1515
0
    MP4_GETVERSIONFLAGS( p_box->data.p_hmhd );
1516
1517
0
    MP4_GET2BYTES( p_box->data.p_hmhd->i_max_PDU_size );
1518
0
    MP4_GET2BYTES( p_box->data.p_hmhd->i_avg_PDU_size );
1519
1520
0
    MP4_GET4BYTES( p_box->data.p_hmhd->i_max_bitrate );
1521
0
    MP4_GET4BYTES( p_box->data.p_hmhd->i_avg_bitrate );
1522
1523
0
    MP4_GET4BYTES( p_box->data.p_hmhd->i_reserved );
1524
1525
0
#ifdef MP4_VERBOSE
1526
0
    msg_Dbg( p_stream, "read box: \"hmhd\" maxPDU-size %d avgPDU-size %d max-bitrate %d avg-bitrate %d",
1527
0
                      p_box->data.p_hmhd->i_max_PDU_size,
1528
0
                      p_box->data.p_hmhd->i_avg_PDU_size,
1529
0
                      p_box->data.p_hmhd->i_max_bitrate,
1530
0
                      p_box->data.p_hmhd->i_avg_bitrate );
1531
0
#endif
1532
0
    MP4_READBOX_EXIT( 1 );
1533
0
}
1534
1535
static void MP4_FreeBox_url( MP4_Box_t *p_box )
1536
0
{
1537
0
    free( p_box->data.p_url->psz_location );
1538
0
}
1539
1540
static int MP4_ReadBox_url( stream_t *p_stream, MP4_Box_t *p_box )
1541
0
{
1542
0
    MP4_READBOX_ENTER( MP4_Box_data_url_t, MP4_FreeBox_url );
1543
1544
0
    MP4_GETVERSIONFLAGS( p_box->data.p_url );
1545
0
    MP4_GETSTRINGZ( p_box->data.p_url->psz_location );
1546
1547
0
#ifdef MP4_VERBOSE
1548
0
    msg_Dbg( p_stream, "read box: \"url\" url: %s",
1549
0
                       p_box->data.p_url->psz_location );
1550
1551
0
#endif
1552
0
    MP4_READBOX_EXIT( 1 );
1553
0
}
1554
1555
static void MP4_FreeBox_urn( MP4_Box_t *p_box )
1556
0
{
1557
0
    free( p_box->data.p_urn->psz_name );
1558
0
    free( p_box->data.p_urn->psz_location );
1559
0
}
1560
1561
static int MP4_ReadBox_urn( stream_t *p_stream, MP4_Box_t *p_box )
1562
0
{
1563
0
    MP4_READBOX_ENTER( MP4_Box_data_urn_t, MP4_FreeBox_urn );
1564
1565
0
    MP4_GETVERSIONFLAGS( p_box->data.p_urn );
1566
1567
0
    MP4_GETSTRINGZ( p_box->data.p_urn->psz_name );
1568
0
    MP4_GETSTRINGZ( p_box->data.p_urn->psz_location );
1569
1570
0
#ifdef MP4_VERBOSE
1571
0
    msg_Dbg( p_stream, "read box: \"urn\" name %s location %s",
1572
0
                      p_box->data.p_urn->psz_name,
1573
0
                      p_box->data.p_urn->psz_location );
1574
0
#endif
1575
0
    MP4_READBOX_EXIT( 1 );
1576
0
}
1577
1578
static int MP4_ReadBox_LtdContainer( stream_t *p_stream, MP4_Box_t *p_box )
1579
0
{
1580
0
    MP4_READBOX_ENTER_PARTIAL( MP4_Box_data_lcont_t, 16, NULL );
1581
0
    if( i_read < 8 )
1582
0
        MP4_READBOX_EXIT( 0 );
1583
1584
0
    MP4_GETVERSIONFLAGS( p_box->data.p_lcont );
1585
0
    if( p_box->data.p_lcont->i_version != 0 )
1586
0
        MP4_READBOX_EXIT( 0 );
1587
0
    MP4_GET4BYTES( p_box->data.p_lcont->i_entry_count );
1588
1589
0
    uint32_t i_entry = 0;
1590
0
    i_read = p_box->i_size - 16;
1591
0
    while (i_read > 8 && i_entry < p_box->data.p_lcont->i_entry_count )
1592
0
    {
1593
0
        MP4_Box_t *p_childbox = MP4_ReadBox( p_stream, p_box );
1594
0
        if( !p_childbox )
1595
0
            break;
1596
0
        MP4_BoxAddChild( p_box, p_childbox );
1597
0
        i_entry++;
1598
1599
0
        if( i_read < p_childbox->i_size )
1600
0
            MP4_READBOX_EXIT( 0 );
1601
1602
0
        i_read -= p_childbox->i_size;
1603
0
    }
1604
1605
0
    if (i_entry != p_box->data.p_lcont->i_entry_count)
1606
0
        p_box->data.p_lcont->i_entry_count = i_entry;
1607
1608
0
#ifdef MP4_VERBOSE
1609
0
    msg_Dbg( p_stream, "read box: \"%4.4s\" entry-count %d", (char *)&p_box->i_type,
1610
0
                        p_box->data.p_lcont->i_entry_count );
1611
1612
0
#endif
1613
1614
0
    if ( MP4_Seek( p_stream, p_box->i_pos + p_box->i_size ) )
1615
0
        MP4_READBOX_EXIT( 0 );
1616
1617
0
    MP4_READBOX_EXIT( 1 );
1618
0
}
1619
1620
static void MP4_FreeBox_stts( MP4_Box_t *p_box )
1621
0
{
1622
0
    free( p_box->data.p_stts->pi_sample_count );
1623
0
    free( p_box->data.p_stts->pi_sample_delta );
1624
0
}
1625
1626
static int MP4_ReadBox_stts( stream_t *p_stream, MP4_Box_t *p_box )
1627
0
{
1628
0
    uint32_t count;
1629
1630
0
    MP4_READBOX_ENTER( MP4_Box_data_stts_t, MP4_FreeBox_stts );
1631
1632
0
    MP4_GETVERSIONFLAGS( p_box->data.p_stts );
1633
0
    MP4_GET4BYTES( count );
1634
1635
0
    if( UINT64_C(8) * count > i_read )
1636
0
    {
1637
        /*count = i_read / 8;*/
1638
0
        MP4_READBOX_EXIT( 0 );
1639
0
    }
1640
1641
0
    p_box->data.p_stts->pi_sample_count = vlc_alloc( count, sizeof(uint32_t) );
1642
0
    p_box->data.p_stts->pi_sample_delta = vlc_alloc( count, sizeof(uint32_t) );
1643
0
    p_box->data.p_stts->i_entry_count = count;
1644
1645
0
    if( p_box->data.p_stts->pi_sample_count == NULL
1646
0
     || p_box->data.p_stts->pi_sample_delta == NULL )
1647
0
    {
1648
0
        MP4_FreeBox_stts( p_box );
1649
0
        MP4_READBOX_EXIT( 0 );
1650
0
    }
1651
1652
0
    for( uint32_t i = 0; i < count; i++ )
1653
0
    {
1654
0
        MP4_GET4BYTES( p_box->data.p_stts->pi_sample_count[i] );
1655
0
        MP4_GET4BYTES( p_box->data.p_stts->pi_sample_delta[i] );
1656
        /* Patch bogus durations, including negative stored values */
1657
0
        if( p_box->data.p_stts->pi_sample_delta[i] == 0 ||
1658
0
            p_box->data.p_stts->pi_sample_delta[i] >= 0xF0000000 )
1659
0
            p_box->data.p_stts->pi_sample_delta[i] = 1;
1660
0
    }
1661
1662
0
#ifdef MP4_VERBOSE
1663
0
    msg_Dbg( p_stream, "read box: \"stts\" entry-count %d",
1664
0
                      p_box->data.p_stts->i_entry_count );
1665
1666
0
#endif
1667
0
    MP4_READBOX_EXIT( 1 );
1668
0
}
1669
1670
1671
static void MP4_FreeBox_ctts( MP4_Box_t *p_box )
1672
0
{
1673
0
    free( p_box->data.p_ctts->pi_sample_count );
1674
0
    free( p_box->data.p_ctts->pi_sample_offset );
1675
0
}
1676
1677
static int MP4_ReadBox_ctts( stream_t *p_stream, MP4_Box_t *p_box )
1678
0
{
1679
0
    uint32_t count;
1680
1681
0
    MP4_READBOX_ENTER( MP4_Box_data_ctts_t, MP4_FreeBox_ctts );
1682
1683
0
    MP4_GETVERSIONFLAGS( p_box->data.p_ctts );
1684
0
    MP4_GET4BYTES( count );
1685
1686
0
    if( UINT64_C(8) * count > i_read )
1687
0
        MP4_READBOX_EXIT( 0 );
1688
1689
0
    p_box->data.p_ctts->pi_sample_count = vlc_alloc( count, sizeof(uint32_t) );
1690
0
    p_box->data.p_ctts->pi_sample_offset = vlc_alloc( count, sizeof(int32_t) );
1691
0
    if( unlikely(p_box->data.p_ctts->pi_sample_count == NULL
1692
0
              || p_box->data.p_ctts->pi_sample_offset == NULL) )
1693
0
    {
1694
0
        MP4_FreeBox_ctts( p_box );
1695
0
        MP4_READBOX_EXIT( 0 );
1696
0
    }
1697
0
    p_box->data.p_ctts->i_entry_count = count;
1698
1699
0
    for( uint32_t i = 0; i < count; i++ )
1700
0
    {
1701
0
        MP4_GET4BYTES( p_box->data.p_ctts->pi_sample_count[i] );
1702
0
        MP4_GET4BYTES( p_box->data.p_ctts->pi_sample_offset[i] );
1703
0
    }
1704
1705
0
#ifdef MP4_VERBOSE
1706
0
    msg_Dbg( p_stream, "read box: \"ctts\" entry-count %"PRIu32, count );
1707
1708
0
#endif
1709
0
    MP4_READBOX_EXIT( 1 );
1710
0
}
1711
1712
static int MP4_ReadBox_cslg( stream_t *p_stream, MP4_Box_t *p_box )
1713
0
{
1714
0
    MP4_READBOX_ENTER( MP4_Box_data_cslg_t, NULL );
1715
1716
0
    unsigned i_version, i_flags;
1717
0
    MP4_GET1BYTE( i_version );
1718
0
    MP4_GET3BYTES( i_flags );
1719
0
    VLC_UNUSED(i_flags);
1720
1721
0
    if( i_version > 1 )
1722
0
        MP4_READBOX_EXIT( 0 );
1723
1724
0
    union { int32_t s; uint32_t u; } u32;
1725
0
    union { int64_t s; uint64_t u; } u64;
1726
0
#define DOREAD_CSLG( readbytes, temp, member ) \
1727
0
        { readbytes( temp.u ); member = temp.s; }
1728
1729
0
#define READ_CSLG( readbytes, temp ) {\
1730
0
    DOREAD_CSLG( readbytes, temp, p_box->data.p_cslg->ct_to_dts_shift );\
1731
0
    DOREAD_CSLG( readbytes, temp, p_box->data.p_cslg->i_least_delta );\
1732
0
    DOREAD_CSLG( readbytes, temp, p_box->data.p_cslg->i_max_delta );\
1733
0
    DOREAD_CSLG( readbytes, temp, p_box->data.p_cslg->i_composition_starttime );\
1734
0
    DOREAD_CSLG( readbytes, temp, p_box->data.p_cslg->i_composition_endtime ); }
1735
1736
0
    if( i_version == 0 )
1737
0
        READ_CSLG( MP4_GET4BYTES, u32 )
1738
0
    else
1739
0
        READ_CSLG( MP4_GET8BYTES, u64 )
1740
1741
0
    MP4_READBOX_EXIT( 1 );
1742
0
}
1743
1744
static uint64_t MP4_ReadLengthDescriptor( uint8_t **restrict bufp,
1745
                                          uint64_t *restrict lenp )
1746
0
{
1747
0
    unsigned char *buf = *bufp;
1748
0
    uint64_t len = *lenp;
1749
0
    unsigned char b;
1750
0
    uint64_t value = 0;
1751
1752
0
    do
1753
0
    {
1754
0
        if (unlikely(len == 0))
1755
0
            return UINT64_C(-1); /* end of bit stream */
1756
0
        if (unlikely(value > (UINT64_MAX >> 7)))
1757
0
            return UINT64_C(-1); /* integer overflow */
1758
1759
0
        b = *(buf++);
1760
0
        len--;
1761
0
        value = (value << 7) + (b & 0x7f);
1762
0
    }
1763
0
    while (b & 0x80);
1764
1765
0
    *bufp = buf;
1766
0
    *lenp = len;
1767
0
    return value;
1768
0
}
1769
1770
1771
static void MP4_FreeBox_esds( MP4_Box_t *p_box )
1772
0
{
1773
0
    free( p_box->data.p_esds->es_descriptor.psz_URL );
1774
0
    if( p_box->data.p_esds->es_descriptor.p_decConfigDescr )
1775
0
    {
1776
0
        free( p_box->data.p_esds->es_descriptor.p_decConfigDescr->p_decoder_specific_info );
1777
0
        free( p_box->data.p_esds->es_descriptor.p_decConfigDescr );
1778
0
    }
1779
0
}
1780
1781
static int MP4_ReadBox_esds( stream_t *p_stream, MP4_Box_t *p_box )
1782
0
{
1783
0
#define es_descriptor p_box->data.p_esds->es_descriptor
1784
0
    uint64_t i_len;
1785
0
    unsigned int i_flags;
1786
0
    unsigned int i_type;
1787
1788
0
    MP4_READBOX_ENTER( MP4_Box_data_esds_t, MP4_FreeBox_esds );
1789
1790
0
    MP4_GETVERSIONFLAGS( p_box->data.p_esds );
1791
1792
1793
0
    MP4_GET1BYTE( i_type );
1794
0
    if( i_type == 0x03 ) /* MP4ESDescrTag ISO/IEC 14496-1 */
1795
0
    {
1796
0
        i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1797
0
        if( unlikely(i_len == UINT64_C(-1)) )
1798
0
            MP4_READBOX_EXIT( 0 );
1799
1800
0
#ifdef MP4_VERBOSE
1801
0
        msg_Dbg( p_stream, "found esds MPEG4ESDescr (%"PRIu64" bytes)",
1802
0
                 i_len );
1803
0
#endif
1804
1805
0
        MP4_GET2BYTES( es_descriptor.i_ES_ID );
1806
0
        MP4_GET1BYTE( i_flags );
1807
0
        es_descriptor.b_stream_dependence = ( (i_flags&0x80) != 0);
1808
0
        es_descriptor.b_url = ( (i_flags&0x40) != 0);
1809
0
        es_descriptor.b_OCRstream = ( (i_flags&0x20) != 0);
1810
1811
0
        es_descriptor.i_stream_priority = i_flags&0x1f;
1812
0
        if( es_descriptor.b_stream_dependence )
1813
0
        {
1814
0
            MP4_GET2BYTES( es_descriptor.i_depend_on_ES_ID );
1815
0
        }
1816
0
        if( es_descriptor.b_url && i_read > 0 )
1817
0
        {
1818
0
            uint8_t i_url;
1819
1820
0
            MP4_GET1BYTE( i_url );
1821
0
            if( i_url > i_read )
1822
0
                MP4_READBOX_EXIT( 1 );
1823
0
            es_descriptor.psz_URL = malloc( (unsigned) i_url + 1 );
1824
0
            if( es_descriptor.psz_URL )
1825
0
            {
1826
0
                memcpy( es_descriptor.psz_URL, p_peek, i_url );
1827
0
                es_descriptor.psz_URL[i_url] = 0;
1828
0
            }
1829
0
            p_peek += i_url;
1830
0
            i_read -= i_url;
1831
0
        }
1832
0
        else
1833
0
        {
1834
0
            es_descriptor.psz_URL = NULL;
1835
0
        }
1836
0
        if( es_descriptor.b_OCRstream )
1837
0
        {
1838
0
            MP4_GET2BYTES( es_descriptor.i_OCR_ES_ID );
1839
0
        }
1840
0
        MP4_GET1BYTE( i_type ); /* get next type */
1841
0
    }
1842
1843
0
    if( i_type != 0x04)/* MP4DecConfigDescrTag ISO/IEC 14496-1 8.3.4 */
1844
0
    {
1845
0
         es_descriptor.p_decConfigDescr = NULL;
1846
0
         MP4_READBOX_EXIT( 1 ); /* rest isn't interesting up to now */
1847
0
    }
1848
1849
0
    i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1850
0
    if( unlikely(i_len == UINT64_C(-1)) )
1851
0
        MP4_READBOX_EXIT( 0 );
1852
0
#ifdef MP4_VERBOSE
1853
0
    msg_Dbg( p_stream, "found esds MP4DecConfigDescr (%"PRIu64" bytes)",
1854
0
             i_len );
1855
0
#endif
1856
1857
0
    es_descriptor.p_decConfigDescr =
1858
0
            calloc( 1, sizeof( MP4_descriptor_decoder_config_t ));
1859
0
    if( unlikely( es_descriptor.p_decConfigDescr == NULL ) )
1860
0
        MP4_READBOX_EXIT( 0 );
1861
1862
0
    MP4_GET1BYTE( es_descriptor.p_decConfigDescr->i_objectProfileIndication );
1863
0
    MP4_GET1BYTE( i_flags );
1864
0
    es_descriptor.p_decConfigDescr->i_streamType = i_flags >> 2;
1865
0
    es_descriptor.p_decConfigDescr->b_upStream = ( i_flags >> 1 )&0x01;
1866
0
    MP4_GET3BYTES( es_descriptor.p_decConfigDescr->i_buffer_sizeDB );
1867
0
    MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_max_bitrate );
1868
0
    MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_avg_bitrate );
1869
0
    MP4_GET1BYTE( i_type );
1870
0
    if( i_type !=  0x05 )/* MP4DecSpecificDescrTag ISO/IEC 14496-1 8.3.5 */
1871
0
    {
1872
0
        es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = 0;
1873
0
        es_descriptor.p_decConfigDescr->p_decoder_specific_info  = NULL;
1874
0
        MP4_READBOX_EXIT( 1 );
1875
0
    }
1876
1877
0
    i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1878
0
    if( unlikely(i_len == UINT64_C(-1)) )
1879
0
        MP4_READBOX_EXIT( 0 );
1880
0
#ifdef MP4_VERBOSE
1881
0
    msg_Dbg( p_stream, "found esds MP4DecSpecificDescr (%"PRIu64" bytes)",
1882
0
             i_len );
1883
0
#endif
1884
0
    if( i_len > i_read )
1885
0
        MP4_READBOX_EXIT( 0 );
1886
1887
0
    es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = i_len;
1888
0
    es_descriptor.p_decConfigDescr->p_decoder_specific_info = malloc( i_len );
1889
0
    if( unlikely( es_descriptor.p_decConfigDescr->p_decoder_specific_info == NULL ) )
1890
0
        MP4_READBOX_EXIT( 0 );
1891
1892
0
    memcpy( es_descriptor.p_decConfigDescr->p_decoder_specific_info,
1893
0
            p_peek, i_len );
1894
1895
0
    MP4_READBOX_EXIT( 1 );
1896
0
#undef es_descriptor
1897
0
}
1898
1899
static void MP4_FreeBox_av1C( MP4_Box_t *p_box )
1900
0
{
1901
0
    MP4_Box_data_av1C_t *p_av1C = p_box->data.p_av1C;
1902
0
    free( p_av1C->p_av1C );
1903
0
}
1904
1905
static int MP4_ReadBox_av1C( stream_t *p_stream, MP4_Box_t *p_box )
1906
0
{
1907
0
    MP4_Box_data_av1C_t *p_av1C;
1908
1909
0
    MP4_READBOX_ENTER( MP4_Box_data_av1C_t, MP4_FreeBox_av1C );
1910
0
    p_av1C = p_box->data.p_av1C;
1911
1912
0
    if( i_read < 4 ||
1913
0
       p_peek[0] != 0x81 ) /* marker / version */
1914
0
        MP4_READBOX_EXIT( 0 );
1915
1916
0
    p_av1C->p_av1C = malloc( i_read );
1917
0
    if( p_av1C->p_av1C )
1918
0
    {
1919
0
        memcpy( p_av1C->p_av1C, p_peek, i_read );
1920
0
        p_av1C->i_av1C = i_read;
1921
0
    }
1922
1923
0
    uint8_t i_8b;
1924
0
    MP4_GET1BYTE( i_8b ); /* marker / version */
1925
1926
0
    MP4_GET1BYTE( i_8b );
1927
0
    p_av1C->i_profile = i_8b >> 5;
1928
0
    p_av1C->i_level = i_8b & 0x1F;
1929
1930
0
    MP4_GET1BYTE( i_8b );
1931
0
    MP4_GET1BYTE( i_8b );
1932
1933
0
    if( i_8b & 0x10 ) /* delay flag */
1934
0
        p_av1C->i_presentation_delay = 1 + (i_8b & 0x0F);
1935
0
    else
1936
0
        p_av1C->i_presentation_delay = 0;
1937
1938
0
    MP4_READBOX_EXIT( 1 );
1939
0
}
1940
1941
static void MP4_FreeBox_avcC( MP4_Box_t *p_box )
1942
0
{
1943
0
    MP4_Box_data_avcC_t *p_avcC = p_box->data.p_avcC;
1944
0
    free( p_avcC->p_avcC );
1945
0
}
1946
1947
static int MP4_ReadBox_avcC( stream_t *p_stream, MP4_Box_t *p_box )
1948
0
{
1949
0
    MP4_Box_data_avcC_t *p_avcC;
1950
1951
0
    MP4_READBOX_ENTER( MP4_Box_data_avcC_t, MP4_FreeBox_avcC );
1952
0
    p_avcC = p_box->data.p_avcC;
1953
1954
0
    if( i_read > 0 )
1955
0
    {
1956
0
        p_avcC->p_avcC = malloc( i_read );
1957
0
        if( p_avcC->p_avcC )
1958
0
        {
1959
0
            memcpy( p_avcC->p_avcC, p_peek, i_read );
1960
0
            p_avcC->i_avcC = i_read;
1961
0
        }
1962
0
    }
1963
1964
0
    MP4_GET1BYTE( p_avcC->i_version );
1965
0
    MP4_GET1BYTE( p_avcC->i_profile );
1966
0
    MP4_GET1BYTE( p_avcC->i_profile_compatibility );
1967
0
    MP4_GET1BYTE( p_avcC->i_level );
1968
0
#ifdef MP4_VERBOSE
1969
0
    msg_Dbg( p_stream,
1970
0
             "read box: \"avcC\" version=%d profile=0x%x level=0x%x",
1971
0
             p_avcC->i_version, p_avcC->i_profile, p_avcC->i_level );
1972
0
#endif
1973
0
    MP4_READBOX_EXIT( 1 );
1974
0
}
1975
1976
static void MP4_FreeBox_vpcC( MP4_Box_t *p_box )
1977
0
{
1978
0
    free( p_box->data.p_vpcC->p_codec_init_data );
1979
0
}
1980
1981
static int MP4_ReadBox_vpcC( stream_t *p_stream, MP4_Box_t *p_box )
1982
0
{
1983
0
    MP4_READBOX_ENTER( MP4_Box_data_vpcC_t, MP4_FreeBox_vpcC );
1984
0
    MP4_Box_data_vpcC_t *p_vpcC = p_box->data.p_vpcC;
1985
1986
0
    if( p_box->i_size < 9 )
1987
0
        MP4_READBOX_EXIT( 0 );
1988
1989
0
    MP4_GET1BYTE( p_vpcC->i_version );
1990
0
    if( p_vpcC->i_version > 1 )
1991
0
        MP4_READBOX_EXIT( 0 );
1992
1993
    /* Skip flags */
1994
0
    uint32_t i_flags;
1995
0
    MP4_GET3BYTES( i_flags );
1996
0
    VLC_UNUSED( i_flags );
1997
1998
0
    MP4_GET1BYTE( p_vpcC->i_profile );
1999
0
    MP4_GET1BYTE( p_vpcC->i_level );
2000
0
    MP4_GET1BYTE( p_vpcC->i_bit_depth );
2001
2002
    /* Deprecated one
2003
       https://github.com/webmproject/vp9-dash/blob/master/archive/VPCodecISOMediaFileFormatBinding-v0.docx */
2004
0
    if( p_vpcC->i_version == 0 )
2005
0
    {
2006
0
        p_vpcC->i_color_primaries = p_vpcC->i_bit_depth & 0x0F;
2007
0
        p_vpcC->i_bit_depth >>= 4;
2008
0
        MP4_GET1BYTE( p_vpcC->i_chroma_subsampling );
2009
0
        p_vpcC->i_xfer_function = ( p_vpcC->i_chroma_subsampling & 0x0F ) >> 1;
2010
0
        p_vpcC->i_fullrange = p_vpcC->i_chroma_subsampling & 0x01;
2011
0
        p_vpcC->i_chroma_subsampling >>= 4;
2012
0
    }
2013
0
    else
2014
0
    {
2015
0
        p_vpcC->i_chroma_subsampling = ( p_vpcC->i_bit_depth & 0x0F ) >> 1;
2016
0
        p_vpcC->i_fullrange = p_vpcC->i_bit_depth & 0x01;
2017
0
        p_vpcC->i_bit_depth >>= 4;
2018
0
        MP4_GET1BYTE( p_vpcC->i_color_primaries );
2019
0
        MP4_GET1BYTE( p_vpcC->i_xfer_function );
2020
0
        MP4_GET1BYTE( p_vpcC->i_matrix_coeffs );
2021
0
    }
2022
2023
0
    MP4_GET2BYTES( p_vpcC->i_codec_init_datasize );
2024
0
    if( p_vpcC->i_codec_init_datasize > i_read )
2025
0
        p_vpcC->i_codec_init_datasize = i_read;
2026
2027
0
    if( p_vpcC->i_codec_init_datasize )
2028
0
    {
2029
0
        p_vpcC->p_codec_init_data = malloc( i_read );
2030
0
        if( !p_vpcC->p_codec_init_data )
2031
0
            MP4_READBOX_EXIT( 0 );
2032
0
        memcpy( p_vpcC->p_codec_init_data, p_peek, i_read );
2033
0
    }
2034
2035
0
    MP4_READBOX_EXIT( 1 );
2036
0
}
2037
2038
static int MP4_ReadBox_SmDm( stream_t *p_stream, MP4_Box_t *p_box )
2039
0
{
2040
0
    MP4_READBOX_ENTER( MP4_Box_data_SmDm_t, NULL );
2041
0
    MP4_Box_data_SmDm_t *p_SmDm = p_box->data.p_SmDm;
2042
2043
    /* SmDm: version/flags RGB */
2044
    /* mdcv: version/flags GBR or not */
2045
0
    if( p_box->i_type != ATOM_mdcv )
2046
0
    {
2047
0
        uint8_t i_version;
2048
0
        uint32_t i_flags;
2049
0
        MP4_GET1BYTE( i_version );
2050
0
        MP4_GET3BYTES( i_flags );
2051
0
        VLC_UNUSED(i_flags);
2052
0
        if( i_version != 0 )
2053
0
            MP4_READBOX_EXIT( 0 );
2054
0
    }
2055
2056
0
    const uint8_t RGB2GBR[3] = {2,0,1};
2057
0
    for(int i=0; i<6; i++)
2058
0
    {
2059
0
        int index = (p_box->i_type != ATOM_mdcv) ? RGB2GBR[i/2] + i%2 : i;
2060
0
        MP4_GET2BYTES( p_SmDm->primaries[index] );
2061
2062
        /* convert from fixed point to 0.00002 resolution */
2063
0
        if(p_box->i_type != ATOM_mdcv)
2064
0
            p_SmDm->primaries[index] = 50000 *
2065
0
                    (double)p_SmDm->primaries[index] / (double)(1<<16);
2066
0
    }
2067
0
    for(int i=0; i<2; i++)
2068
0
    {
2069
0
        MP4_GET2BYTES( p_SmDm->white_point[i] );
2070
0
        if(p_box->i_type != ATOM_mdcv)
2071
0
            p_SmDm->white_point[i] = 50000 *
2072
0
                    (double)p_SmDm->white_point[i] / (double)(1<<16);
2073
0
    }
2074
2075
0
    MP4_GET4BYTES( p_SmDm->i_luminanceMax );
2076
0
    MP4_GET4BYTES( p_SmDm->i_luminanceMin );
2077
0
    if(p_box->i_type != ATOM_mdcv)
2078
0
    {
2079
0
        p_SmDm->i_luminanceMax = 10000 *
2080
0
                (double)p_SmDm->i_luminanceMax / (double) (1<<8);
2081
0
        p_SmDm->i_luminanceMin = 10000 *
2082
0
                (double)p_SmDm->i_luminanceMin / (double) (1<<14);
2083
0
    }
2084
2085
0
    MP4_READBOX_EXIT( 1 );
2086
0
}
2087
2088
static int MP4_ReadBox_CoLL( stream_t *p_stream, MP4_Box_t *p_box )
2089
0
{
2090
0
    MP4_READBOX_ENTER( MP4_Box_data_CoLL_t, NULL );
2091
0
    MP4_Box_data_CoLL_t *p_CoLL = p_box->data.p_CoLL;
2092
2093
0
    if( p_box->i_type != ATOM_clli )
2094
0
    {
2095
0
        uint8_t i_version;
2096
0
        uint32_t i_flags;
2097
0
        MP4_GET1BYTE( i_version );
2098
0
        MP4_GET3BYTES( i_flags );
2099
0
        VLC_UNUSED(i_flags);
2100
0
        if( i_version != 0 )
2101
0
            MP4_READBOX_EXIT( 0 );
2102
0
    }
2103
2104
0
    MP4_GET2BYTES( p_CoLL->i_maxCLL );
2105
0
    MP4_GET2BYTES( p_CoLL->i_maxFALL );
2106
0
    MP4_READBOX_EXIT( 1 );
2107
0
}
2108
2109
static void MP4_FreeBox_WMA2( MP4_Box_t *p_box )
2110
0
{
2111
0
    free( p_box->data.p_WMA2->p_extra );
2112
0
}
2113
2114
static int MP4_ReadBox_WMA2( stream_t *p_stream, MP4_Box_t *p_box )
2115
0
{
2116
0
    MP4_READBOX_ENTER( MP4_Box_data_WMA2_t, MP4_FreeBox_WMA2 );
2117
2118
0
    MP4_Box_data_WMA2_t *p_WMA2 = p_box->data.p_WMA2;
2119
2120
0
    MP4_GET2BYTESLE( p_WMA2->Format.wFormatTag );
2121
0
    MP4_GET2BYTESLE( p_WMA2->Format.nChannels );
2122
0
    MP4_GET4BYTESLE( p_WMA2->Format.nSamplesPerSec );
2123
0
    MP4_GET4BYTESLE( p_WMA2->Format.nAvgBytesPerSec );
2124
0
    MP4_GET2BYTESLE( p_WMA2->Format.nBlockAlign );
2125
0
    MP4_GET2BYTESLE( p_WMA2->Format.wBitsPerSample );
2126
2127
0
    uint16_t i_cbSize;
2128
0
    MP4_GET2BYTESLE( i_cbSize );
2129
2130
0
    if( i_cbSize > i_read )
2131
0
        goto error;
2132
2133
0
    p_WMA2->i_extra = i_cbSize;
2134
0
    if ( p_WMA2->i_extra )
2135
0
    {
2136
0
        p_WMA2->p_extra = malloc( p_WMA2->i_extra );
2137
0
        if ( ! p_WMA2->p_extra )
2138
0
            goto error;
2139
0
        memcpy( p_WMA2->p_extra, p_peek, p_WMA2->i_extra );
2140
0
    }
2141
2142
0
    MP4_READBOX_EXIT( 1 );
2143
2144
0
error:
2145
0
    MP4_READBOX_EXIT( 0 );
2146
0
}
2147
2148
static void MP4_FreeBox_strf( MP4_Box_t *p_box )
2149
0
{
2150
0
    free( p_box->data.p_strf->p_extra );
2151
0
}
2152
2153
static int MP4_ReadBox_strf( stream_t *p_stream, MP4_Box_t *p_box )
2154
0
{
2155
0
    MP4_READBOX_ENTER( MP4_Box_data_strf_t, MP4_FreeBox_strf );
2156
2157
0
    MP4_Box_data_strf_t *p_strf = p_box->data.p_strf;
2158
2159
0
    if( i_read < 40 )
2160
0
        goto error;
2161
2162
0
    MP4_GET4BYTESLE( p_strf->bmiHeader.biSize );
2163
0
    MP4_GET4BYTESLE( p_strf->bmiHeader.biWidth );
2164
0
    MP4_GET4BYTESLE( p_strf->bmiHeader.biHeight );
2165
0
    MP4_GET2BYTESLE( p_strf->bmiHeader.biPlanes );
2166
0
    MP4_GET2BYTESLE( p_strf->bmiHeader.biBitCount );
2167
0
    MP4_GETFOURCC( p_strf->bmiHeader.biCompression );
2168
0
    MP4_GET4BYTESLE( p_strf->bmiHeader.biSizeImage );
2169
0
    MP4_GET4BYTESLE( p_strf->bmiHeader.biXPelsPerMeter );
2170
0
    MP4_GET4BYTESLE( p_strf->bmiHeader.biYPelsPerMeter );
2171
0
    MP4_GET4BYTESLE( p_strf->bmiHeader.biClrUsed );
2172
0
    MP4_GET4BYTESLE( p_strf->bmiHeader.biClrImportant );
2173
2174
0
    p_strf->i_extra = i_read;
2175
0
    if ( p_strf->i_extra )
2176
0
    {
2177
0
        p_strf->p_extra = malloc( p_strf->i_extra );
2178
0
        if ( ! p_strf->p_extra )
2179
0
            goto error;
2180
0
        memcpy( p_strf->p_extra, p_peek, i_read );
2181
0
    }
2182
2183
0
    MP4_READBOX_EXIT( 1 );
2184
2185
0
error:
2186
0
    MP4_READBOX_EXIT( 0 );
2187
0
}
2188
2189
static int MP4_ReadBox_ASF( stream_t *p_stream, MP4_Box_t *p_box )
2190
0
{
2191
0
    MP4_READBOX_ENTER( MP4_Box_data_ASF_t, NULL );
2192
2193
0
    MP4_Box_data_ASF_t *p_asf = p_box->data.p_asf;
2194
2195
0
    if (i_read != 8)
2196
0
        MP4_READBOX_EXIT( 0 );
2197
2198
0
    MP4_GET1BYTE( p_asf->i_stream_number );
2199
    /* remaining is unknown */
2200
2201
0
    MP4_READBOX_EXIT( 1 );
2202
0
}
2203
2204
static void MP4_FreeBox_sbgp( MP4_Box_t *p_box )
2205
0
{
2206
0
    MP4_Box_data_sbgp_t *p_sbgp = p_box->data.p_sbgp;
2207
0
    free( p_sbgp->p_entries );
2208
0
}
2209
2210
static int MP4_ReadBox_sbgp( stream_t *p_stream, MP4_Box_t *p_box )
2211
0
{
2212
0
    MP4_READBOX_ENTER( MP4_Box_data_sbgp_t, MP4_FreeBox_sbgp );
2213
0
    MP4_Box_data_sbgp_t *p_sbgp = p_box->data.p_sbgp;
2214
0
    uint32_t i_flags;
2215
2216
0
    if ( i_read < 12 )
2217
0
        MP4_READBOX_EXIT( 0 );
2218
2219
0
    MP4_GET1BYTE( p_sbgp->i_version );
2220
0
    MP4_GET3BYTES( i_flags );
2221
0
    if( i_flags != 0 )
2222
0
        MP4_READBOX_EXIT( 0 );
2223
2224
0
    MP4_GETFOURCC( p_sbgp->i_grouping_type );
2225
2226
0
    if( p_sbgp->i_version == 1 )
2227
0
    {
2228
0
        if( i_read < 8 )
2229
0
            MP4_READBOX_EXIT( 0 );
2230
0
        MP4_GET4BYTES( p_sbgp->i_grouping_type_parameter );
2231
0
    }
2232
2233
0
    MP4_GET4BYTES( p_sbgp->i_entry_count );
2234
0
    if( p_sbgp->i_entry_count > i_read / (4 + 4) )
2235
0
        p_sbgp->i_entry_count = i_read / (4 + 4);
2236
2237
0
    p_sbgp->p_entries = vlc_alloc( p_sbgp->i_entry_count, sizeof(*p_sbgp->p_entries) );
2238
0
    if( !p_sbgp->p_entries )
2239
0
    {
2240
0
        MP4_FreeBox_sbgp( p_box );
2241
0
        MP4_READBOX_EXIT( 0 );
2242
0
    }
2243
2244
0
    for( uint32_t i=0; i<p_sbgp->i_entry_count; i++ )
2245
0
    {
2246
0
        MP4_GET4BYTES( p_sbgp->p_entries[i].i_sample_count );
2247
0
        MP4_GET4BYTES( p_sbgp->p_entries[i].i_group_description_index );
2248
0
    }
2249
2250
0
#ifdef MP4_VERBOSE
2251
0
    msg_Dbg( p_stream,
2252
0
        "read box: \"sbgp\" grouping type %4.4s", (char*) &p_sbgp->i_grouping_type );
2253
 #ifdef MP4_ULTRA_VERBOSE
2254
    for (uint32_t i = 0; i < p_sbgp->i_entry_count; i++)
2255
        msg_Dbg( p_stream, "\t samples %" PRIu32 " group %" PRIu32,
2256
                 p_sbgp->entries[i].i_sample_count,
2257
                 p_sbgp->entries[i].i_group_description_index );
2258
 #endif
2259
0
#endif
2260
2261
0
    MP4_READBOX_EXIT( 1 );
2262
0
}
2263
2264
static void MP4_FreeBox_sgpd( MP4_Box_t *p_box )
2265
0
{
2266
0
    MP4_Box_data_sgpd_t *p_sgpd = p_box->data.p_sgpd;
2267
0
    free( p_sgpd->p_entries );
2268
0
}
2269
2270
static int MP4_ReadBox_sgpd( stream_t *p_stream, MP4_Box_t *p_box )
2271
0
{
2272
0
    MP4_READBOX_ENTER( MP4_Box_data_sgpd_t, MP4_FreeBox_sgpd );
2273
0
    MP4_Box_data_sgpd_t *p_sgpd = p_box->data.p_sgpd;
2274
0
    uint32_t i_flags;
2275
0
    uint32_t i_default_length = 0;
2276
2277
0
    if ( i_read < 8 )
2278
0
        MP4_READBOX_EXIT( 0 );
2279
2280
0
    MP4_GET1BYTE( p_sgpd->i_version );
2281
0
    MP4_GET3BYTES( i_flags );
2282
0
    if( i_flags != 0 )
2283
0
        MP4_READBOX_EXIT( 0 );
2284
2285
0
    MP4_GETFOURCC( p_sgpd->i_grouping_type );
2286
2287
0
    switch( p_sgpd->i_grouping_type )
2288
0
    {
2289
0
        case SAMPLEGROUP_rap:
2290
0
        case SAMPLEGROUP_roll:
2291
0
            break;
2292
2293
0
        default:
2294
0
#ifdef MP4_VERBOSE
2295
0
    msg_Dbg( p_stream,
2296
0
        "read box: \"sgpd\" grouping type %4.4s (unimplemented)", (char*) &p_sgpd->i_grouping_type );
2297
0
#endif
2298
0
            MP4_READBOX_EXIT( 1 );
2299
0
    }
2300
2301
0
    if( p_sgpd->i_version == 1 )
2302
0
    {
2303
0
        if( i_read < 8 )
2304
0
            MP4_READBOX_EXIT( 0 );
2305
0
        MP4_GET4BYTES( i_default_length );
2306
0
    }
2307
0
    else if( p_sgpd->i_version >= 2 )
2308
0
    {
2309
0
        if( i_read < 8 )
2310
0
            MP4_READBOX_EXIT( 0 );
2311
0
        MP4_GET4BYTES( p_sgpd->i_default_sample_description_index );
2312
0
    }
2313
2314
0
    MP4_GET4BYTES( p_sgpd->i_entry_count );
2315
2316
0
    p_sgpd->p_entries = vlc_alloc( p_sgpd->i_entry_count, sizeof(*p_sgpd->p_entries) );
2317
0
    if( !p_sgpd->p_entries )
2318
0
        MP4_READBOX_EXIT( 0 );
2319
2320
0
    uint32_t i = 0;
2321
0
    for( ; i<p_sgpd->i_entry_count; i++ )
2322
0
    {
2323
0
        uint32_t i_description_length = i_default_length;
2324
0
        if( p_sgpd->i_version == 1 && i_default_length == 0 )
2325
0
        {
2326
0
            if( i_read < 4 )
2327
0
                break;
2328
0
            MP4_GET4BYTES( i_description_length );
2329
0
        }
2330
2331
0
        if( p_sgpd->i_version == 1 && i_read < i_description_length )
2332
0
            break;
2333
2334
0
        switch( p_sgpd->i_grouping_type )
2335
0
        {
2336
0
            case SAMPLEGROUP_rap:
2337
0
                {
2338
0
                    if( i_read < 1 )
2339
0
                    {
2340
0
                        free( p_sgpd->p_entries );
2341
0
                        MP4_READBOX_EXIT( 0 );
2342
0
                    }
2343
0
                    uint8_t i_data;
2344
0
                    MP4_GET1BYTE( i_data );
2345
0
                    p_sgpd->p_entries[i].rap.i_num_leading_samples_known = i_data & 0x80;
2346
0
                    p_sgpd->p_entries[i].rap.i_num_leading_samples = i_data & 0x7F;
2347
0
                }
2348
0
                break;
2349
2350
0
            case SAMPLEGROUP_roll:
2351
0
                {
2352
0
                    if( i_read < 2 )
2353
0
                    {
2354
0
                        free( p_sgpd->p_entries );
2355
0
                        MP4_READBOX_EXIT( 0 );
2356
0
                    }
2357
0
                    union
2358
0
                    {
2359
0
                        uint16_t u;
2360
0
                        int16_t  s;
2361
0
                    } readsigned;
2362
0
                    MP4_GET2BYTES( readsigned.u );
2363
0
                    p_sgpd->p_entries[i].roll.i_roll_distance = readsigned.s;
2364
0
                }
2365
0
                break;
2366
2367
0
            default:
2368
0
                vlc_assert_unreachable();
2369
0
                free( p_sgpd->p_entries );
2370
0
                MP4_READBOX_EXIT( 0 );
2371
0
        }
2372
0
    }
2373
2374
0
    if( i != p_sgpd->i_entry_count )
2375
0
        p_sgpd->i_entry_count = i;
2376
2377
0
#ifdef MP4_VERBOSE
2378
0
    msg_Dbg( p_stream,
2379
0
        "read box: \"sgpd\" grouping type %4.4s", (char*) &p_sgpd->i_grouping_type );
2380
0
#endif
2381
2382
0
    MP4_READBOX_EXIT( 1 );
2383
0
}
2384
2385
static void MP4_FreeBox_stsdext_chan( MP4_Box_t *p_box )
2386
0
{
2387
0
    MP4_Box_data_chan_t *p_chan = p_box->data.p_chan;
2388
0
    CoreAudio_Layout_Clean( &p_chan->layout );
2389
0
}
2390
2391
static int MP4_ReadBox_stsdext_chan( stream_t *p_stream, MP4_Box_t *p_box )
2392
0
{
2393
0
    MP4_READBOX_ENTER( MP4_Box_data_chan_t, MP4_FreeBox_stsdext_chan );
2394
0
    MP4_Box_data_chan_t *p_chan = p_box->data.p_chan;
2395
2396
0
    if ( i_read < 16 )
2397
0
        MP4_READBOX_EXIT( 0 );
2398
2399
0
    MP4_GET1BYTE( p_chan->i_version );
2400
0
    MP4_GET3BYTES( p_chan->i_channels_flags );
2401
0
    MP4_GET4BYTES( p_chan->layout.i_channels_layout_tag );
2402
0
    MP4_GET4BYTES( p_chan->layout.i_channels_bitmap );
2403
0
    MP4_GET4BYTES( p_chan->layout.i_channels_description_count );
2404
2405
0
    size_t i_descsize = 8 + 3 * sizeof(float);
2406
0
    if ( i_read < p_chan->layout.i_channels_description_count * i_descsize )
2407
0
        MP4_READBOX_EXIT( 0 );
2408
2409
0
    p_chan->layout.p_descriptions =
2410
0
        vlc_alloc( p_chan->layout.i_channels_description_count, i_descsize );
2411
2412
0
    if ( !p_chan->layout.p_descriptions )
2413
0
        MP4_READBOX_EXIT( 0 );
2414
2415
0
    uint32_t i;
2416
0
    for( i=0; i<p_chan->layout.i_channels_description_count; i++ )
2417
0
    {
2418
0
        if ( i_read < 20 )
2419
0
            break;
2420
0
        MP4_GET4BYTES( p_chan->layout.p_descriptions[i].i_channel_label );
2421
0
        MP4_GET4BYTES( p_chan->layout.p_descriptions[i].i_channel_flags );
2422
0
        MP4_GET4BYTES( p_chan->layout.p_descriptions[i].f_coordinates[0] );
2423
0
        MP4_GET4BYTES( p_chan->layout.p_descriptions[i].f_coordinates[1] );
2424
0
        MP4_GET4BYTES( p_chan->layout.p_descriptions[i].f_coordinates[2] );
2425
0
    }
2426
0
    if ( i<p_chan->layout.i_channels_description_count )
2427
0
        p_chan->layout.i_channels_description_count = i;
2428
2429
0
#ifdef MP4_VERBOSE
2430
0
    msg_Dbg( p_stream,
2431
0
             "read box: \"chan\" flags=0x%x tag=0x%x bitmap=0x%x descriptions=%u",
2432
0
             p_chan->i_channels_flags, p_chan->layout.i_channels_layout_tag,
2433
0
             p_chan->layout.i_channels_bitmap, p_chan->layout.i_channels_description_count );
2434
0
#endif
2435
0
    MP4_READBOX_EXIT( 1 );
2436
0
}
2437
2438
static int MP4_ReadBox_stsdext_srat( stream_t *p_stream, MP4_Box_t *p_box )
2439
0
{
2440
0
    MP4_READBOX_ENTER( MP4_Box_data_srat_t, NULL );
2441
0
    MP4_Box_data_srat_t *p_srat = p_box->data.p_srat;
2442
0
    if ( i_read != 8 )
2443
0
        MP4_READBOX_EXIT( 0 );
2444
2445
0
    uint32_t i_dummy;
2446
0
    VLC_UNUSED( i_dummy );
2447
0
    MP4_GET4BYTES( i_dummy ); /* version flags */
2448
0
    MP4_GET4BYTES( p_srat->i_sample_rate );
2449
2450
0
    MP4_READBOX_EXIT( 1 );
2451
0
}
2452
2453
static int MP4_ReadBox_dec3( stream_t *p_stream, MP4_Box_t *p_box )
2454
0
{
2455
0
    MP4_READBOX_ENTER( MP4_Box_data_dec3_t, NULL );
2456
2457
0
    MP4_Box_data_dec3_t *p_dec3 = p_box->data.p_dec3;
2458
2459
0
    unsigned i_header;
2460
0
    MP4_GET2BYTES( i_header );
2461
2462
0
    p_dec3->i_data_rate = i_header >> 3;
2463
0
    p_dec3->i_num_ind_sub = (i_header & 0x7) + 1;
2464
0
    for (uint8_t i = 0; i < p_dec3->i_num_ind_sub; i++) {
2465
0
        MP4_GET3BYTES( i_header );
2466
0
        p_dec3->stream[i].i_fscod = ( i_header >> 22 ) & 0x03;
2467
0
        p_dec3->stream[i].i_bsid  = ( i_header >> 17 ) & 0x01f;
2468
0
        p_dec3->stream[i].i_bsmod = ( i_header >> 12 ) & 0x01f;
2469
0
        p_dec3->stream[i].i_acmod = ( i_header >> 9 ) & 0x07;
2470
0
        p_dec3->stream[i].i_lfeon = ( i_header >> 8 ) & 0x01;
2471
0
        p_dec3->stream[i].i_num_dep_sub = (i_header >> 1) & 0x0f;
2472
0
        if (p_dec3->stream[i].i_num_dep_sub) {
2473
0
            MP4_GET1BYTE( p_dec3->stream[i].i_chan_loc );
2474
0
            p_dec3->stream[i].i_chan_loc |= (i_header & 1) << 8;
2475
0
        } else
2476
0
            p_dec3->stream[i].i_chan_loc = 0;
2477
0
    }
2478
2479
0
#ifdef MP4_VERBOSE
2480
0
    msg_Dbg( p_stream,
2481
0
        "read box: \"dec3\" bitrate %dkbps %d independent substreams",
2482
0
            p_dec3->i_data_rate, p_dec3->i_num_ind_sub);
2483
2484
0
    for (uint8_t i = 0; i < p_dec3->i_num_ind_sub; i++)
2485
0
        msg_Dbg( p_stream,
2486
0
                "\tstream %d: bsid=0x%x bsmod=0x%x acmod=0x%x lfeon=0x%x "
2487
0
                "num dependent subs=%d chan_loc=0x%x",
2488
0
                i, p_dec3->stream[i].i_bsid, p_dec3->stream[i].i_bsmod, p_dec3->stream[i].i_acmod,
2489
0
                p_dec3->stream[i].i_lfeon, p_dec3->stream[i].i_num_dep_sub, p_dec3->stream[i].i_chan_loc );
2490
0
#endif
2491
0
    MP4_READBOX_EXIT( 1 );
2492
0
}
2493
2494
static int MP4_ReadBox_dac3( stream_t *p_stream, MP4_Box_t *p_box )
2495
0
{
2496
0
    MP4_Box_data_dac3_t *p_dac3;
2497
0
    MP4_READBOX_ENTER( MP4_Box_data_dac3_t, NULL );
2498
2499
0
    p_dac3 = p_box->data.p_dac3;
2500
2501
0
    unsigned i_header;
2502
0
    MP4_GET3BYTES( i_header );
2503
2504
0
    p_dac3->i_fscod = ( i_header >> 22 ) & 0x03;
2505
0
    p_dac3->i_bsid  = ( i_header >> 17 ) & 0x01f;
2506
0
    p_dac3->i_bsmod = ( i_header >> 14 ) & 0x07;
2507
0
    p_dac3->i_acmod = ( i_header >> 11 ) & 0x07;
2508
0
    p_dac3->i_lfeon = ( i_header >> 10 ) & 0x01;
2509
0
    p_dac3->i_bitrate_code = ( i_header >> 5) & 0x1f;
2510
2511
0
#ifdef MP4_VERBOSE
2512
0
    msg_Dbg( p_stream,
2513
0
             "read box: \"dac3\" fscod=0x%x bsid=0x%x bsmod=0x%x acmod=0x%x lfeon=0x%x bitrate_code=0x%x",
2514
0
             p_dac3->i_fscod, p_dac3->i_bsid, p_dac3->i_bsmod, p_dac3->i_acmod, p_dac3->i_lfeon, p_dac3->i_bitrate_code );
2515
0
#endif
2516
0
    MP4_READBOX_EXIT( 1 );
2517
0
}
2518
2519
static void MP4_FreeBox_dvc1( MP4_Box_t *p_box )
2520
0
{
2521
0
    free( p_box->data.p_dvc1->p_vc1 );
2522
0
}
2523
2524
static int MP4_ReadBox_dvc1( stream_t *p_stream, MP4_Box_t *p_box )
2525
0
{
2526
0
    MP4_READBOX_ENTER( MP4_Box_data_dvc1_t, MP4_FreeBox_dvc1 );
2527
0
    if( i_read < 7 )
2528
0
        MP4_READBOX_EXIT( 0 );
2529
2530
0
    MP4_Box_data_dvc1_t *p_dvc1 = p_box->data.p_dvc1;
2531
0
    MP4_GET1BYTE( p_dvc1->i_profile_level );
2532
0
    p_dvc1->i_vc1 = i_read; /* Header + profile_level */
2533
0
    if( p_dvc1->i_vc1 > 0 && (p_dvc1->p_vc1 = malloc( p_dvc1->i_vc1 )) )
2534
0
        memcpy( p_dvc1->p_vc1, p_peek, i_read );
2535
2536
0
#ifdef MP4_VERBOSE
2537
0
    uint8_t i_profile = (p_dvc1->i_profile_level & 0xf0) >> 4;
2538
0
    msg_Dbg( p_stream, "read box: \"dvc1\" profile=%"PRIu8, i_profile );
2539
0
#endif
2540
2541
0
    MP4_READBOX_EXIT( 1 );
2542
0
}
2543
2544
static int MP4_ReadBox_fiel( stream_t *p_stream, MP4_Box_t *p_box )
2545
0
{
2546
0
    MP4_Box_data_fiel_t *p_fiel;
2547
0
    MP4_READBOX_ENTER( MP4_Box_data_fiel_t, NULL );
2548
0
    p_fiel = p_box->data.p_fiel;
2549
0
    if(i_read < 2)
2550
0
        MP4_READBOX_EXIT( 0 );
2551
0
    if(p_peek[0] == 2) /* Interlaced */
2552
0
    {
2553
        /*
2554
         * 0 – There is only one field.
2555
         * 1 – T is displayed earliest, T is stored first in the file.
2556
         * 6 – B is displayed earliest, B is stored first in the file.
2557
         * 9 – B is displayed earliest, T is stored first in the file.
2558
         * 14 – T is displayed earliest, B is stored first in the file.
2559
        */
2560
0
        if(p_peek[1] == 0)
2561
0
            p_fiel->i_flags = BLOCK_FLAG_SINGLE_FIELD;
2562
0
        else if(p_peek[1] == 1 || p_peek[1] == 9)
2563
0
            p_fiel->i_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
2564
0
        else if(p_peek[1] == 6 || p_peek[1] == 14)
2565
0
            p_fiel->i_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
2566
0
    }
2567
0
    MP4_READBOX_EXIT( 1 );
2568
0
}
2569
2570
static int MP4_ReadBox_enda( stream_t *p_stream, MP4_Box_t *p_box )
2571
0
{
2572
0
    MP4_Box_data_enda_t *p_enda;
2573
0
    MP4_READBOX_ENTER( MP4_Box_data_enda_t, NULL );
2574
2575
0
    p_enda = p_box->data.p_enda;
2576
2577
0
    MP4_GET2BYTES( p_enda->i_little_endian );
2578
2579
0
#ifdef MP4_VERBOSE
2580
0
    msg_Dbg( p_stream,
2581
0
             "read box: \"enda\" little_endian=%d", p_enda->i_little_endian );
2582
0
#endif
2583
0
    MP4_READBOX_EXIT( 1 );
2584
0
}
2585
2586
static int MP4_ReadBox_pcmC( stream_t *p_stream, MP4_Box_t *p_box )
2587
0
{
2588
0
    MP4_READBOX_ENTER( MP4_Box_data_pcmC_t, NULL );
2589
0
    if(i_read != 6)
2590
0
        MP4_READBOX_EXIT( 0 );
2591
0
    uint32_t temp;
2592
0
    MP4_GET4BYTES(temp);
2593
0
    if(temp != 0) /* support only v0 */
2594
0
        MP4_READBOX_EXIT( 0 );
2595
0
    MP4_GET1BYTE(p_box->data.p_pcmC->i_format_flags);
2596
0
    MP4_GET1BYTE(p_box->data.p_pcmC->i_sample_size);
2597
0
    MP4_READBOX_EXIT( 1 );
2598
0
}
2599
2600
static void MP4_FreeBox_sample_soun( MP4_Box_t *p_box )
2601
0
{
2602
0
    free( p_box->data.p_sample_soun->p_qt_description );
2603
0
}
2604
2605
static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box )
2606
0
{
2607
0
    p_box->i_handler = ATOM_soun;
2608
0
    MP4_READBOX_ENTER( MP4_Box_data_sample_soun_t, MP4_FreeBox_sample_soun );
2609
0
    p_box->data.p_sample_soun->p_qt_description = NULL;
2610
2611
0
    size_t i_actually_read = i_read + header_size;
2612
2613
    /* Sanity check needed because the "wave" box does also contain an
2614
     * "mp4a" box that we don't understand. */
2615
0
    if( i_read < 28 )
2616
0
    {
2617
0
        MP4_READBOX_EXIT( 1 );
2618
0
    }
2619
2620
0
    READ_SAMPLE_DESC_COMMON_8BYTES_HEADER;
2621
2622
    /*
2623
     * XXX hack -> produce a copy of the nearly complete chunk
2624
     */
2625
0
    p_box->data.p_sample_soun->i_qt_description = 0;
2626
0
    p_box->data.p_sample_soun->p_qt_description = NULL;
2627
0
    if( i_read > 0 )
2628
0
    {
2629
0
        p_box->data.p_sample_soun->p_qt_description = malloc( i_read );
2630
0
        if( p_box->data.p_sample_soun->p_qt_description )
2631
0
        {
2632
0
            p_box->data.p_sample_soun->i_qt_description = i_read;
2633
0
            memcpy( p_box->data.p_sample_soun->p_qt_description, p_peek, i_read );
2634
0
        }
2635
0
    }
2636
2637
0
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_version );
2638
0
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_revision_level );
2639
0
    MP4_GET4BYTES( p_box->data.p_sample_soun->i_qt_vendor );
2640
2641
0
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_channelcount );
2642
0
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_samplesize );
2643
0
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_compressionid );
2644
0
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_reserved3 );
2645
0
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratehi );
2646
0
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratelo );
2647
2648
0
#ifdef MP4_VERBOSE
2649
0
    msg_Dbg( p_stream,
2650
0
             "read box: \"soun\" stsd qt_version %"PRIu16" compid=%"PRIx16,
2651
0
             p_box->data.p_sample_soun->i_qt_version,
2652
0
             p_box->data.p_sample_soun->i_compressionid );
2653
0
#endif
2654
    /* @36 bytes */
2655
0
    if( p_box->data.p_sample_soun->i_qt_version == 1 && i_read >= 16 )
2656
0
    {
2657
        /* SoundDescriptionV1 */
2658
0
        MP4_GET4BYTES( p_box->data.p_sample_soun->i_sample_per_packet );
2659
0
        MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_packet );
2660
0
        MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_frame );
2661
0
        MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_sample );
2662
2663
0
#ifdef MP4_VERBOSE
2664
0
        msg_Dbg( p_stream,
2665
0
                 "read box: \"soun\" V1 sample/packet=%d bytes/packet=%d "
2666
0
                 "bytes/frame=%d bytes/sample=%d",
2667
0
                 p_box->data.p_sample_soun->i_sample_per_packet,
2668
0
                 p_box->data.p_sample_soun->i_bytes_per_packet,
2669
0
                 p_box->data.p_sample_soun->i_bytes_per_frame,
2670
0
                 p_box->data.p_sample_soun->i_bytes_per_sample );
2671
0
#endif
2672
        /* @52 bytes */
2673
0
    }
2674
0
    else if( p_box->data.p_sample_soun->i_qt_version == 2 && i_read >= 36 )
2675
0
    {
2676
        /* SoundDescriptionV2 */
2677
0
        double f_sample_rate;
2678
0
        int64_t i_dummy64;
2679
0
        uint32_t i_channel, i_extoffset, i_dummy32;
2680
2681
        /* Checks */
2682
0
        if ( p_box->data.p_sample_soun->i_channelcount != 0x3  ||
2683
0
             p_box->data.p_sample_soun->i_samplesize != 0x0010 ||
2684
0
             p_box->data.p_sample_soun->i_compressionid != 0xFFFE ||
2685
0
             p_box->data.p_sample_soun->i_reserved3 != 0x0     ||
2686
0
             p_box->data.p_sample_soun->i_sampleratehi != 0x1  ||//65536
2687
0
             p_box->data.p_sample_soun->i_sampleratelo != 0x0 )  //remainder
2688
0
        {
2689
0
            msg_Err( p_stream, "invalid stsd V2 box defaults" );
2690
0
            MP4_READBOX_EXIT( 0 );
2691
0
        }
2692
        /* !Checks */
2693
2694
0
        MP4_GET4BYTES( i_extoffset ); /* offset to stsd extensions */
2695
0
        MP4_GET8BYTES( i_dummy64 );
2696
0
        memcpy( &f_sample_rate, &i_dummy64, 8 );
2697
0
        msg_Dbg( p_stream, "read box: %f Hz", f_sample_rate );
2698
        /* Rounding error with lo, but we don't care since we do not support fractional audio rate */
2699
0
        p_box->data.p_sample_soun->i_sampleratehi = (uint32_t)f_sample_rate;
2700
0
        p_box->data.p_sample_soun->i_sampleratelo = (f_sample_rate - p_box->data.p_sample_soun->i_sampleratehi);
2701
2702
0
        MP4_GET4BYTES( i_channel );
2703
0
        p_box->data.p_sample_soun->i_channelcount = i_channel;
2704
2705
0
        MP4_GET4BYTES( i_dummy32 );
2706
0
        if ( i_dummy32 != 0x7F000000 )
2707
0
        {
2708
0
            msg_Err( p_stream, "invalid stsd V2 box" );
2709
0
            MP4_READBOX_EXIT( 0 );
2710
0
        }
2711
2712
0
        MP4_GET4BYTES( p_box->data.p_sample_soun->i_constbitsperchannel );
2713
0
        MP4_GET4BYTES( p_box->data.p_sample_soun->i_formatflags );
2714
0
        MP4_GET4BYTES( p_box->data.p_sample_soun->i_constbytesperaudiopacket );
2715
0
        MP4_GET4BYTES( p_box->data.p_sample_soun->i_constLPCMframesperaudiopacket );
2716
2717
0
#ifdef MP4_VERBOSE
2718
0
        msg_Dbg( p_stream, "read box: \"soun\" V2 rate=%f bitsperchannel=%u "
2719
0
                           "flags=%u bytesperpacket=%u lpcmframesperpacket=%u",
2720
0
                 f_sample_rate,
2721
0
                 p_box->data.p_sample_soun->i_constbitsperchannel,
2722
0
                 p_box->data.p_sample_soun->i_formatflags,
2723
0
                 p_box->data.p_sample_soun->i_constbytesperaudiopacket,
2724
0
                 p_box->data.p_sample_soun->i_constLPCMframesperaudiopacket );
2725
0
#endif
2726
        /* @72 bytes + */
2727
0
        if( i_extoffset > i_actually_read )
2728
0
            i_extoffset = i_actually_read;
2729
0
        p_peek = &p_buff[i_extoffset];
2730
0
        i_read = i_actually_read - i_extoffset;
2731
0
    }
2732
0
    else
2733
0
    {
2734
0
        p_box->data.p_sample_soun->i_sample_per_packet = 0;
2735
0
        p_box->data.p_sample_soun->i_bytes_per_packet = 0;
2736
0
        p_box->data.p_sample_soun->i_bytes_per_frame = 0;
2737
0
        p_box->data.p_sample_soun->i_bytes_per_sample = 0;
2738
2739
0
#ifdef MP4_VERBOSE
2740
0
        msg_Dbg( p_stream, "read box: \"soun\" V0 or qt1/2 (rest=%"PRIu64")",
2741
0
                 i_read );
2742
0
#endif
2743
        /* @36 bytes */
2744
0
    }
2745
2746
0
    if( p_box->i_type == ATOM_drms )
2747
0
    {
2748
0
        msg_Warn( p_stream, "DRM protected streams are not supported." );
2749
0
        MP4_READBOX_EXIT( 0 );
2750
0
    }
2751
2752
0
    if( p_box->i_type == ATOM_samr || p_box->i_type == ATOM_sawb )
2753
0
    {
2754
        /* Ignore channelcount for AMR (3gpp AMRSpecificBox) */
2755
0
        p_box->data.p_sample_soun->i_channelcount = 1;
2756
0
    }
2757
2758
    /* Loads extensions */
2759
0
    MP4_ReadBoxContainerRawInBox( p_stream, p_box, p_peek, i_read,
2760
0
                                  p_box->i_pos + p_peek - p_buff ); /* esds/wave/... */
2761
2762
0
#ifdef MP4_VERBOSE
2763
0
    msg_Dbg( p_stream, "read box: \"soun\" in stsd channel %d "
2764
0
             "sample size %d sample rate %f",
2765
0
             p_box->data.p_sample_soun->i_channelcount,
2766
0
             p_box->data.p_sample_soun->i_samplesize,
2767
0
             (float)p_box->data.p_sample_soun->i_sampleratehi +
2768
0
             (float)p_box->data.p_sample_soun->i_sampleratelo / BLOCK16x16 );
2769
2770
0
#endif
2771
0
    MP4_READBOX_EXIT( 1 );
2772
0
}
2773
2774
static void MP4_FreeBox_sample_vide( MP4_Box_t *p_box )
2775
0
{
2776
0
    free( p_box->data.p_sample_vide->p_qt_image_description );
2777
0
    free( p_box->data.p_sample_vide->p_palette );
2778
0
}
2779
2780
int MP4_ReadBox_sample_vide( stream_t *p_stream, MP4_Box_t *p_box )
2781
0
{
2782
0
    p_box->i_handler = ATOM_vide;
2783
0
    MP4_READBOX_ENTER( MP4_Box_data_sample_vide_t, MP4_FreeBox_sample_vide );
2784
2785
0
    size_t i_actually_read = i_read + header_size;
2786
2787
0
    READ_SAMPLE_DESC_COMMON_8BYTES_HEADER;
2788
2789
    /*
2790
     * XXX hack -> produce a copy of the nearly complete chunk
2791
     */
2792
0
    if( i_read > 0 )
2793
0
    {
2794
0
        p_box->data.p_sample_vide->p_qt_image_description = malloc( i_read );
2795
0
        if( unlikely( p_box->data.p_sample_vide->p_qt_image_description == NULL ) )
2796
0
            MP4_READBOX_EXIT( 0 );
2797
0
        p_box->data.p_sample_vide->i_qt_image_description = i_read;
2798
0
        memcpy( p_box->data.p_sample_vide->p_qt_image_description,
2799
0
                p_peek, i_read );
2800
0
    }
2801
0
    else
2802
0
    {
2803
0
        p_box->data.p_sample_vide->i_qt_image_description = 0;
2804
0
        p_box->data.p_sample_vide->p_qt_image_description = NULL;
2805
0
    }
2806
2807
0
    MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_version );
2808
0
    MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_revision_level );
2809
0
    MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_vendor );
2810
2811
0
    MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_temporal_quality );
2812
0
    MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_spatial_quality );
2813
2814
0
    MP4_GET2BYTES( p_box->data.p_sample_vide->i_width );
2815
0
    MP4_GET2BYTES( p_box->data.p_sample_vide->i_height );
2816
2817
0
    MP4_GET4BYTES( p_box->data.p_sample_vide->i_horizresolution );
2818
0
    MP4_GET4BYTES( p_box->data.p_sample_vide->i_vertresolution );
2819
2820
0
    MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_data_size );
2821
0
    MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_frame_count );
2822
2823
0
    if ( i_read < 32 )
2824
0
        MP4_READBOX_EXIT( 0 );
2825
0
    if( p_peek[0] <= 31 ) // Must be Pascal String
2826
0
    {
2827
0
        memcpy( &p_box->data.p_sample_vide->sz_compressorname, &p_peek[1], p_peek[0] );
2828
0
        p_box->data.p_sample_vide->sz_compressorname[p_peek[0]] = 0;
2829
0
    }
2830
0
    p_peek += 32; i_read -= 32;
2831
2832
0
    MP4_GET2BYTES( p_box->data.p_sample_vide->i_depth );
2833
0
    MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_color_table );
2834
2835
0
    if( p_box->data.p_sample_vide->i_depth == 8 &&
2836
0
        p_box->data.p_sample_vide->i_qt_color_table == 0 )
2837
0
    {
2838
0
        p_box->data.p_sample_vide->p_palette = ReadQuicktimePalette( &p_peek, &i_read );
2839
0
        if( p_box->data.p_sample_vide->p_palette == NULL )
2840
0
            MP4_READBOX_EXIT( 0 );
2841
0
    }
2842
2843
0
    if( p_box->i_type == ATOM_drmi )
2844
0
    {
2845
0
        msg_Warn( p_stream, "DRM protected streams are not supported." );
2846
0
        MP4_READBOX_EXIT( 0 );
2847
0
    }
2848
2849
0
    if( i_actually_read > 78 && p_peek - p_buff > 78 )
2850
0
    {
2851
0
        MP4_ReadBoxContainerRawInBox( p_stream, p_box, p_peek, i_read,
2852
0
                                      p_box->i_pos + p_peek - p_buff );
2853
0
    }
2854
2855
0
#ifdef MP4_VERBOSE
2856
0
    msg_Dbg( p_stream, "read box: \"vide\" in stsd %dx%d depth %d (%s)",
2857
0
                      p_box->data.p_sample_vide->i_width,
2858
0
                      p_box->data.p_sample_vide->i_height,
2859
0
                      p_box->data.p_sample_vide->i_depth,
2860
0
                      p_box->data.p_sample_vide->sz_compressorname );
2861
2862
0
#endif
2863
0
    MP4_READBOX_EXIT( 1 );
2864
0
}
2865
2866
static void MP4_FreeBox_sample_generic( MP4_Box_t *p_box )
2867
0
{
2868
0
    free( p_box->data.p_sample_gen->p_data );
2869
0
}
2870
2871
static int MP4_ReadBox_sample_generic( stream_t *p_stream, MP4_Box_t *p_box )
2872
0
{
2873
0
    MP4_READBOX_ENTER_PARTIAL( MP4_Box_data_sample_generic_t, 16, NULL );
2874
2875
0
    READ_SAMPLE_DESC_COMMON_8BYTES_HEADER;
2876
2877
0
    switch( p_box->i_type )
2878
0
    {
2879
0
        case ATOM_mp4s:
2880
0
            p_box->i_handler = ATOM_text;
2881
0
            break;
2882
0
        default:
2883
0
            msg_Warn( p_stream, "Unknown mapping for %4.4s with generic handler",
2884
0
                      (const char *)&p_box->i_type );
2885
0
            break;
2886
0
    }
2887
2888
0
    MP4_ReadBoxContainerChildren( p_stream, p_box, NULL );
2889
2890
0
    if ( MP4_Seek( p_stream, p_box->i_pos + p_box->i_size ) )
2891
0
        MP4_READBOX_EXIT( 0 );
2892
2893
0
    MP4_READBOX_EXIT( 1 );
2894
0
}
2895
2896
static int MP4_ReadBox_sample_hint8( stream_t *p_stream, MP4_Box_t *p_box )
2897
0
{
2898
0
    MP4_READBOX_ENTER_PARTIAL( MP4_Box_data_sample_generic_t, 24, MP4_FreeBox_sample_generic );
2899
2900
0
    READ_SAMPLE_DESC_COMMON_8BYTES_HEADER;
2901
2902
0
    if( !(p_box->data.p_sample_gen->p_data = malloc(8)) )
2903
0
        MP4_READBOX_EXIT( 0 );
2904
2905
0
    MP4_GET8BYTES( *(p_box->data.p_sample_gen->p_data) );
2906
0
    p_box->data.p_sample_gen->i_data = 8;
2907
2908
0
    MP4_ReadBoxContainerChildren(p_stream, p_box, NULL);
2909
2910
0
    if ( MP4_Seek( p_stream, p_box->i_pos + p_box->i_size ) )
2911
0
        MP4_READBOX_EXIT( 0 );
2912
2913
0
    MP4_READBOX_EXIT( 1 );
2914
0
}
2915
2916
static int MP4_ReadBox_sample_text( stream_t *p_stream, MP4_Box_t *p_box )
2917
0
{
2918
0
    p_box->i_handler = ATOM_text;
2919
0
    MP4_READBOX_ENTER( MP4_Box_data_sample_generic_t, MP4_FreeBox_sample_generic );
2920
2921
0
    READ_SAMPLE_DESC_COMMON_8BYTES_HEADER;
2922
2923
0
    if( i_read )
2924
0
    {
2925
0
        p_box->data.p_sample_gen->p_data = malloc( i_read );
2926
0
        if( !p_box->data.p_sample_gen->p_data )
2927
0
            MP4_READBOX_EXIT( 0 );
2928
0
        memcpy( p_box->data.p_sample_gen->p_data, p_peek, i_read );
2929
0
    }
2930
0
    p_box->data.p_sample_gen->i_data = i_read;
2931
2932
0
#ifdef MP4_VERBOSE
2933
0
    msg_Dbg( p_stream, "read box: \"%4.4s\" in stsd", (const char*) &p_box->i_type );
2934
0
#endif
2935
0
    MP4_READBOX_EXIT( 1 );
2936
0
}
2937
2938
static int MP4_ReadBox_stsd( stream_t *p_stream, MP4_Box_t *p_box )
2939
0
{
2940
0
    MP4_READBOX_ENTER_PARTIAL( MP4_Box_data_lcont_t, 16, NULL );
2941
0
    if( i_read < 8 )
2942
0
        MP4_READBOX_EXIT( 0 );
2943
2944
0
    MP4_GETVERSIONFLAGS( p_box->data.p_lcont );
2945
0
    if( p_box->data.p_lcont->i_version > 1 )
2946
0
        MP4_READBOX_EXIT( 0 );
2947
0
    MP4_GET4BYTES( p_box->data.p_lcont->i_entry_count );
2948
2949
0
    const MP4_Box_t *p_mdia = MP4_BoxGet( p_box, "../../../" );
2950
0
    const MP4_Box_t *p_hdlr;
2951
0
    if( p_mdia == NULL || p_mdia->i_type != ATOM_mdia ||
2952
0
        (p_hdlr = MP4_BoxGet( p_mdia, "hdlr" )) == NULL )
2953
0
    {
2954
0
        if ( MP4_Seek( p_stream, p_box->i_pos + p_box->i_size ) == VLC_SUCCESS )
2955
0
        {
2956
0
            msg_Warn( p_stream, "missing hdlr for stsd, delaying" );
2957
0
            MP4_READBOX_EXIT( 1 );
2958
0
        }
2959
0
        MP4_READBOX_EXIT( 0 );
2960
0
    }
2961
2962
    /* Tag stsd with handler type that children can just read from */
2963
0
    p_box->i_handler = BOXDATA(p_hdlr)->i_handler_type;
2964
2965
0
    uint32_t i_entry = 0;
2966
0
    i_read = p_box->i_size - 16;
2967
0
    while (i_read > 8 && i_entry < p_box->data.p_lcont->i_entry_count )
2968
0
    {
2969
0
        int(*pf_read)(stream_t *, MP4_Box_t *);
2970
0
        switch( BOXDATA(p_hdlr)->i_handler_type )
2971
0
        {
2972
0
            case ATOM_soun:
2973
0
                pf_read = MP4_ReadBox_sample_soun;
2974
0
                break;
2975
0
            case ATOM_vide:
2976
0
            case ATOM_pict: /* heif */
2977
0
                pf_read = MP4_ReadBox_sample_vide;
2978
0
                break;
2979
0
            case ATOM_hint:
2980
0
                pf_read = MP4_ReadBox_sample_hint8;
2981
0
                break;
2982
0
            case ATOM_clcp:
2983
0
            case ATOM_text:
2984
0
            case ATOM_subt:
2985
0
            case ATOM_tx3g:
2986
0
            case ATOM_sbtl:
2987
0
                pf_read = MP4_ReadBox_sample_text;
2988
0
                break;
2989
0
            case ATOM_subp: /* see #13464 */
2990
0
                pf_read = MP4_ReadBox_sample_generic;
2991
0
                break;
2992
0
            default:
2993
0
                pf_read = NULL;
2994
0
                msg_Warn( p_stream, "unknown handler type %4.4s in stsd",
2995
0
                          (const char *)& BOXDATA(p_hdlr)->i_handler_type );
2996
0
                break;
2997
0
        }
2998
2999
0
        if( !pf_read )
3000
0
            break;
3001
3002
0
        MP4_Box_t *p_sample = MP4_ReadBoxUsing( p_stream, p_box, pf_read );
3003
0
        if( !p_sample )
3004
0
            break;
3005
3006
        /* write back stsd handler in case of final handler set by child */
3007
0
        p_box->i_handler = p_sample->i_handler;
3008
3009
0
        MP4_BoxAddChild( p_box, p_sample );
3010
0
        i_entry++;
3011
3012
0
        if( i_read < p_sample->i_size )
3013
0
            MP4_READBOX_EXIT( 0 );
3014
3015
0
        i_read -= p_sample->i_size;
3016
0
    }
3017
3018
0
    if (i_entry != p_box->data.p_lcont->i_entry_count)
3019
0
        p_box->data.p_lcont->i_entry_count = i_entry;
3020
3021
0
#ifdef MP4_VERBOSE
3022
0
    msg_Dbg( p_stream, "read box: \"%4.4s\" entry-count %d", (char *)&p_box->i_type,
3023
0
                        p_box->data.p_lcont->i_entry_count );
3024
3025
0
#endif
3026
3027
0
    if ( MP4_Seek( p_stream, p_box->i_pos + p_box->i_size ) )
3028
0
        MP4_READBOX_EXIT( 0 );
3029
3030
0
    MP4_READBOX_EXIT( 1 );
3031
0
}
3032
3033
static void MP4_FreeBox_stsz( MP4_Box_t *p_box )
3034
0
{
3035
0
    free( p_box->data.p_stsz->i_entry_size );
3036
0
}
3037
3038
static int MP4_ReadBox_stsz( stream_t *p_stream, MP4_Box_t *p_box )
3039
0
{
3040
0
    uint32_t count;
3041
3042
0
    MP4_READBOX_ENTER( MP4_Box_data_stsz_t, MP4_FreeBox_stsz );
3043
3044
0
    MP4_GETVERSIONFLAGS( p_box->data.p_stsz );
3045
3046
0
    MP4_GET4BYTES( p_box->data.p_stsz->i_sample_size );
3047
0
    MP4_GET4BYTES( count );
3048
0
    p_box->data.p_stsz->i_sample_count = count;
3049
3050
0
    if( p_box->data.p_stsz->i_sample_size == 0 )
3051
0
    {
3052
0
        if( UINT64_C(4) * count > i_read )
3053
0
            MP4_READBOX_EXIT( 0 );
3054
3055
0
        p_box->data.p_stsz->i_entry_size =
3056
0
            vlc_alloc( count, sizeof(uint32_t) );
3057
0
        if( unlikely( !p_box->data.p_stsz->i_entry_size ) )
3058
0
            MP4_READBOX_EXIT( 0 );
3059
3060
0
        for( uint32_t i = 0; i < count; i++ )
3061
0
        {
3062
0
            MP4_GET4BYTES( p_box->data.p_stsz->i_entry_size[i] );
3063
0
        }
3064
0
    }
3065
0
    else
3066
0
        p_box->data.p_stsz->i_entry_size = NULL;
3067
3068
0
#ifdef MP4_VERBOSE
3069
0
    msg_Dbg( p_stream, "read box: \"stsz\" sample-size %d sample-count %d",
3070
0
                      p_box->data.p_stsz->i_sample_size,
3071
0
                      p_box->data.p_stsz->i_sample_count );
3072
3073
0
#endif
3074
0
    MP4_READBOX_EXIT( 1 );
3075
0
}
3076
3077
static int MP4_ReadBox_stz2( stream_t *p_stream, MP4_Box_t *p_box )
3078
0
{
3079
0
    uint32_t count;
3080
0
    uint8_t field_size;
3081
3082
0
    MP4_READBOX_ENTER( MP4_Box_data_stsz_t, MP4_FreeBox_stsz );
3083
3084
0
    MP4_GETVERSIONFLAGS( p_box->data.p_stsz );
3085
3086
0
    uint32_t reserved;
3087
0
    MP4_GET3BYTES( reserved );
3088
0
    (void) reserved;
3089
3090
0
    MP4_GET1BYTE(field_size);
3091
3092
0
    MP4_GET4BYTES( count );
3093
0
    p_box->data.p_stsz->i_sample_count = count;
3094
3095
0
    if( field_size != 4 && field_size != 8 && field_size != 16 )
3096
0
        MP4_READBOX_EXIT( 0 );
3097
0
    if( ( (uint64_t)field_size * count + 7 ) / 8 > i_read )
3098
0
        MP4_READBOX_EXIT( 0 );
3099
3100
0
    p_box->data.p_stsz->i_entry_size =
3101
0
            vlc_alloc( count, sizeof(uint32_t) );
3102
0
    if( unlikely( p_box->data.p_stsz->i_entry_size == NULL ) )
3103
0
        MP4_READBOX_EXIT( 0 );
3104
3105
0
    if( field_size == 16 )
3106
0
    {
3107
0
        for( uint32_t i = 0; i < count; i++ )
3108
0
            MP4_GET2BYTES( p_box->data.p_stsz->i_entry_size[i] );
3109
0
    }
3110
0
    else if( field_size == 8 )
3111
0
    {
3112
0
        for( uint32_t i = 0; i < count; i++ )
3113
0
            MP4_GET1BYTE( p_box->data.p_stsz->i_entry_size[i] );
3114
0
    }
3115
0
    else
3116
0
    {
3117
0
        vlc_assert( field_size == 4 );
3118
0
        count &= ~1;
3119
0
        for( uint32_t i = 0; i < count; i += 2 )
3120
0
        {
3121
0
            uint8_t entry;
3122
0
            MP4_GET1BYTE( entry );
3123
0
            p_box->data.p_stsz->i_entry_size[i] = entry >> 4;
3124
0
            p_box->data.p_stsz->i_entry_size[i + 1] = entry & 0x0F;
3125
0
        }
3126
0
        if( count < p_box->data.p_stsz->i_sample_count )
3127
0
        {
3128
0
            uint8_t entry;
3129
            /* ISO-14496-12: if the sizes do not fill an integral number of
3130
             * bytes, the last byte is padded with zeros.
3131
             */
3132
0
            MP4_GET1BYTE( entry );
3133
0
            p_box->data.p_stsz->i_entry_size[count] = entry >> 4;
3134
0
        }
3135
0
    }
3136
3137
0
#ifdef MP4_VERBOSE
3138
0
    msg_Dbg( p_stream, "read box: \"stz2\" field-size %d sample-count %d",
3139
0
             field_size,
3140
0
             p_box->data.p_stsz->i_sample_count );
3141
3142
0
#endif
3143
0
    MP4_READBOX_EXIT( 1 );
3144
0
}
3145
3146
static void MP4_FreeBox_stsc( MP4_Box_t *p_box )
3147
0
{
3148
0
    free( p_box->data.p_stsc->i_first_chunk );
3149
0
    free( p_box->data.p_stsc->i_samples_per_chunk );
3150
0
    free( p_box->data.p_stsc->i_sample_description_index );
3151
0
}
3152
3153
static int MP4_ReadBox_stsc( stream_t *p_stream, MP4_Box_t *p_box )
3154
0
{
3155
0
    uint32_t count;
3156
3157
0
    MP4_READBOX_ENTER( MP4_Box_data_stsc_t, MP4_FreeBox_stsc );
3158
3159
0
    MP4_GETVERSIONFLAGS( p_box->data.p_stsc );
3160
0
    MP4_GET4BYTES( count );
3161
3162
0
    if( UINT64_C(12) * count > i_read )
3163
0
        MP4_READBOX_EXIT( 0 );
3164
3165
0
    p_box->data.p_stsc->i_first_chunk = vlc_alloc( count, sizeof(uint32_t) );
3166
0
    p_box->data.p_stsc->i_samples_per_chunk = vlc_alloc( count,
3167
0
                                                         sizeof(uint32_t) );
3168
0
    p_box->data.p_stsc->i_sample_description_index = vlc_alloc( count,
3169
0
                                                            sizeof(uint32_t) );
3170
0
    if( unlikely( p_box->data.p_stsc->i_first_chunk == NULL
3171
0
     || p_box->data.p_stsc->i_samples_per_chunk == NULL
3172
0
     || p_box->data.p_stsc->i_sample_description_index == NULL ) )
3173
0
    {
3174
0
        MP4_READBOX_EXIT( 0 );
3175
0
    }
3176
0
    p_box->data.p_stsc->i_entry_count = count;
3177
3178
0
    for( uint32_t i = 0; i < count;i++ )
3179
0
    {
3180
0
        MP4_GET4BYTES( p_box->data.p_stsc->i_first_chunk[i] );
3181
0
        MP4_GET4BYTES( p_box->data.p_stsc->i_samples_per_chunk[i] );
3182
0
        MP4_GET4BYTES( p_box->data.p_stsc->i_sample_description_index[i] );
3183
0
    }
3184
3185
0
#ifdef MP4_VERBOSE
3186
0
    msg_Dbg( p_stream, "read box: \"stsc\" entry-count %d",
3187
0
                      p_box->data.p_stsc->i_entry_count );
3188
3189
0
#endif
3190
0
    MP4_READBOX_EXIT( 1 );
3191
0
}
3192
3193
static void MP4_FreeBox_sdp( MP4_Box_t *p_box )
3194
0
{
3195
0
    free( p_box->data.p_sdp->psz_text );
3196
0
}
3197
3198
static int MP4_ReadBox_sdp( stream_t *p_stream, MP4_Box_t *p_box )
3199
0
{
3200
0
   MP4_READBOX_ENTER( MP4_Box_data_sdp_t, MP4_FreeBox_sdp );
3201
3202
0
   MP4_GETSTRINGZ( p_box->data.p_sdp->psz_text );
3203
3204
0
   MP4_READBOX_EXIT( 1 );
3205
0
}
3206
3207
static void MP4_FreeBox_rtp( MP4_Box_t *p_box )
3208
0
{
3209
0
    free( p_box->data.p_moviehintinformation_rtp->psz_text );
3210
0
}
3211
3212
static int MP4_ReadBox_rtp( stream_t *p_stream, MP4_Box_t *p_box )
3213
0
{
3214
0
    MP4_READBOX_ENTER( MP4_Box_data_moviehintinformation_rtp_t, MP4_FreeBox_rtp );
3215
3216
0
    MP4_GET4BYTES( p_box->data.p_moviehintinformation_rtp->i_description_format );
3217
3218
0
    MP4_GETSTRINGZ( p_box->data.p_moviehintinformation_rtp->psz_text );
3219
3220
0
    MP4_READBOX_EXIT( 1 );
3221
0
}
3222
3223
static int MP4_ReadBox_tims( stream_t *p_stream, MP4_Box_t *p_box )
3224
0
{
3225
0
    MP4_READBOX_ENTER( MP4_Box_data_tims_t, NULL );
3226
3227
0
    MP4_GET4BYTES( p_box->data.p_tims->i_timescale );
3228
3229
0
    MP4_READBOX_EXIT( 1 );
3230
0
}
3231
3232
static int MP4_ReadBox_tsro( stream_t *p_stream, MP4_Box_t *p_box )
3233
0
{
3234
0
    MP4_READBOX_ENTER( MP4_Box_data_tsro_t, NULL );
3235
3236
0
    MP4_GET4BYTES( p_box->data.p_tsro->i_offset );
3237
3238
0
    MP4_READBOX_EXIT( 1 );
3239
0
}
3240
3241
static int MP4_ReadBox_tssy( stream_t *p_stream, MP4_Box_t *p_box )
3242
0
{
3243
0
    MP4_READBOX_ENTER( MP4_Box_data_tssy_t,  NULL );
3244
3245
0
    MP4_GET1BYTE( p_box->data.p_tssy->i_reserved_timestamp_sync );
3246
3247
0
    MP4_READBOX_EXIT( 1 );
3248
0
}
3249
3250
static void MP4_FreeBox_stco_co64( MP4_Box_t *p_box )
3251
0
{
3252
0
    free( p_box->data.p_co64->i_chunk_offset );
3253
0
}
3254
3255
static int MP4_ReadBox_stco_co64( stream_t *p_stream, MP4_Box_t *p_box )
3256
0
{
3257
0
    const bool sixtyfour = p_box->i_type != ATOM_stco;
3258
0
    uint32_t count;
3259
3260
0
    MP4_READBOX_ENTER( MP4_Box_data_co64_t, MP4_FreeBox_stco_co64 );
3261
3262
0
    MP4_GETVERSIONFLAGS( p_box->data.p_co64 );
3263
0
    MP4_GET4BYTES( count );
3264
3265
0
    if( (sixtyfour ? UINT64_C(8) : UINT64_C(4)) * count > i_read )
3266
0
        MP4_READBOX_EXIT( 0 );
3267
3268
0
    p_box->data.p_co64->i_chunk_offset = vlc_alloc( count, sizeof(uint64_t) );
3269
0
    if( unlikely(p_box->data.p_co64->i_chunk_offset == NULL) )
3270
0
        MP4_READBOX_EXIT( 0 );
3271
0
    p_box->data.p_co64->i_entry_count = count;
3272
3273
0
    for( uint32_t i = 0; i < count; i++ )
3274
0
    {
3275
0
        if( sixtyfour )
3276
0
            MP4_GET8BYTES( p_box->data.p_co64->i_chunk_offset[i] );
3277
0
        else
3278
0
            MP4_GET4BYTES( p_box->data.p_co64->i_chunk_offset[i] );
3279
0
    }
3280
3281
0
#ifdef MP4_VERBOSE
3282
0
    msg_Dbg( p_stream, "read box: \"co64\" entry-count %d",
3283
0
                      p_box->data.p_co64->i_entry_count );
3284
3285
0
#endif
3286
0
    MP4_READBOX_EXIT( 1 );
3287
0
}
3288
3289
static void MP4_FreeBox_stss( MP4_Box_t *p_box )
3290
0
{
3291
0
    free( p_box->data.p_stss->i_sample_number );
3292
0
}
3293
3294
static int MP4_ReadBox_stss( stream_t *p_stream, MP4_Box_t *p_box )
3295
0
{
3296
0
    uint32_t count;
3297
3298
0
    MP4_READBOX_ENTER( MP4_Box_data_stss_t, MP4_FreeBox_stss );
3299
3300
0
    MP4_GETVERSIONFLAGS( p_box->data.p_stss );
3301
0
    MP4_GET4BYTES( count );
3302
3303
0
    if( UINT64_C(4) * count > i_read )
3304
0
        MP4_READBOX_EXIT( 0 );
3305
3306
0
    p_box->data.p_stss->i_sample_number = vlc_alloc( count, sizeof(uint32_t) );
3307
0
    if( unlikely( p_box->data.p_stss->i_sample_number == NULL ) )
3308
0
        MP4_READBOX_EXIT( 0 );
3309
0
    p_box->data.p_stss->i_entry_count = count;
3310
3311
0
    for( uint32_t i = 0; i < count; i++ )
3312
0
    {
3313
0
        MP4_GET4BYTES( p_box->data.p_stss->i_sample_number[i] );
3314
        /* XXX in libmp4 sample begin at 0 */
3315
0
        p_box->data.p_stss->i_sample_number[i]--;
3316
0
    }
3317
3318
0
#ifdef MP4_VERBOSE
3319
0
    msg_Dbg( p_stream, "read box: \"stss\" entry-count %d",
3320
0
                      p_box->data.p_stss->i_entry_count );
3321
3322
0
#endif
3323
0
    MP4_READBOX_EXIT( 1 );
3324
0
}
3325
3326
static void MP4_FreeBox_stsh( MP4_Box_t *p_box )
3327
0
{
3328
0
    free( p_box->data.p_stsh->i_shadowed_sample_number );
3329
0
    free( p_box->data.p_stsh->i_sync_sample_number );
3330
0
}
3331
3332
static int MP4_ReadBox_stsh( stream_t *p_stream, MP4_Box_t *p_box )
3333
0
{
3334
0
    uint32_t count;
3335
3336
0
    MP4_READBOX_ENTER( MP4_Box_data_stsh_t, MP4_FreeBox_stsh );
3337
3338
0
    MP4_GETVERSIONFLAGS( p_box->data.p_stsh );
3339
0
    MP4_GET4BYTES( count );
3340
3341
0
    if( UINT64_C(8) * count > i_read )
3342
0
        MP4_READBOX_EXIT( 0 );
3343
3344
0
    p_box->data.p_stsh->i_shadowed_sample_number = vlc_alloc( count,
3345
0
                                                            sizeof(uint32_t) );
3346
0
    p_box->data.p_stsh->i_sync_sample_number = vlc_alloc( count,
3347
0
                                                          sizeof(uint32_t) );
3348
0
    if( p_box->data.p_stsh->i_shadowed_sample_number == NULL
3349
0
     || p_box->data.p_stsh->i_sync_sample_number == NULL )
3350
0
        MP4_READBOX_EXIT( 0 );
3351
0
    p_box->data.p_stsh->i_entry_count = count;
3352
3353
0
    for( uint32_t i = 0; i < p_box->data.p_stss->i_entry_count; i++ )
3354
0
    {
3355
0
        MP4_GET4BYTES( p_box->data.p_stsh->i_shadowed_sample_number[i] );
3356
0
        MP4_GET4BYTES( p_box->data.p_stsh->i_sync_sample_number[i] );
3357
0
    }
3358
3359
0
#ifdef MP4_VERBOSE
3360
0
    msg_Dbg( p_stream, "read box: \"stsh\" entry-count %d",
3361
0
                      p_box->data.p_stsh->i_entry_count );
3362
0
#endif
3363
0
    MP4_READBOX_EXIT( 1 );
3364
0
}
3365
3366
static void MP4_FreeBox_stdp( MP4_Box_t *p_box )
3367
0
{
3368
0
    free( p_box->data.p_stdp->i_priority );
3369
0
}
3370
3371
static int MP4_ReadBox_stdp( stream_t *p_stream, MP4_Box_t *p_box )
3372
0
{
3373
0
    MP4_READBOX_ENTER( MP4_Box_data_stdp_t, MP4_FreeBox_stdp );
3374
3375
0
    MP4_GETVERSIONFLAGS( p_box->data.p_stdp );
3376
3377
0
    p_box->data.p_stdp->i_priority =
3378
0
        calloc( i_read / 2, sizeof(*p_box->data.p_stdp->i_priority) );
3379
3380
0
    if( unlikely( !p_box->data.p_stdp->i_priority ) )
3381
0
        MP4_READBOX_EXIT( 0 );
3382
3383
0
    for( unsigned i = 0; i < i_read / 2 ; i++ )
3384
0
    {
3385
0
        MP4_GET2BYTES( p_box->data.p_stdp->i_priority[i] );
3386
0
    }
3387
3388
0
#ifdef MP4_VERBOSE
3389
0
    msg_Dbg( p_stream, "read box: \"stdp\" entry-count %"PRId64,
3390
0
                      i_read / 2 );
3391
3392
0
#endif
3393
0
    MP4_READBOX_EXIT( 1 );
3394
0
}
3395
3396
static void MP4_FreeBox_elst( MP4_Box_t *p_box )
3397
0
{
3398
0
    free( p_box->data.p_elst->entries );
3399
0
}
3400
3401
static int MP4_ReadBox_elst( stream_t *p_stream, MP4_Box_t *p_box )
3402
0
{
3403
0
    uint32_t count;
3404
3405
0
    MP4_READBOX_ENTER( MP4_Box_data_elst_t, MP4_FreeBox_elst );
3406
0
    MP4_Box_data_elst_t *p_elst = p_box->data.p_elst;
3407
3408
0
    uint8_t i_version;
3409
0
    uint32_t dummy;
3410
0
    MP4_GET1BYTE( i_version );
3411
0
    MP4_GET3BYTES( dummy ); VLC_UNUSED(dummy);
3412
3413
0
    if( i_version > 1 )
3414
0
        MP4_READBOX_EXIT( 0 );
3415
3416
0
    MP4_GET4BYTES( count );
3417
0
    if( count == 0 )
3418
0
        MP4_READBOX_EXIT( 1 );
3419
3420
0
    uint32_t i_entries_max = i_read / ((i_version == 1) ? 20 : 12);
3421
0
    if( count > i_entries_max )
3422
0
        count = i_entries_max;
3423
3424
0
    p_elst->entries = vlc_alloc( count, sizeof(*p_elst->entries) );
3425
0
    if( !p_elst->entries )
3426
0
        MP4_READBOX_EXIT( 0 );
3427
3428
0
    p_elst->i_entry_count = count;
3429
3430
0
    for( uint32_t i = 0; i < count; i++ )
3431
0
    {
3432
0
        uint64_t segment_duration;
3433
0
        int64_t media_time;
3434
3435
0
        if( i_version == 1 )
3436
0
        {
3437
0
            union { int64_t s; uint64_t u; } u;
3438
3439
0
            MP4_GET8BYTES( segment_duration );
3440
0
            MP4_GET8BYTES( u.u );
3441
0
            media_time = u.s;
3442
0
        }
3443
0
        else
3444
0
        {
3445
0
            union { int32_t s; uint32_t u; } u;
3446
3447
0
            MP4_GET4BYTES( segment_duration );
3448
0
            MP4_GET4BYTES( u.u );
3449
0
            media_time = u.s;
3450
0
        }
3451
3452
0
        p_elst->entries[i].i_segment_duration = segment_duration;
3453
0
        p_elst->entries[i].i_media_time = media_time;
3454
0
        MP4_GET2BYTES( p_elst->entries[i].i_media_rate_integer );
3455
0
        MP4_GET2BYTES( p_elst->entries[i].i_media_rate_fraction );
3456
0
    }
3457
3458
0
#ifdef MP4_VERBOSE
3459
0
    msg_Dbg( p_stream, "read box: \"elst\" entry-count %" PRIu32,
3460
0
             p_elst->i_entry_count );
3461
0
#endif
3462
0
    MP4_READBOX_EXIT( 1 );
3463
0
}
3464
3465
static void MP4_FreeBox_cprt( MP4_Box_t *p_box )
3466
0
{
3467
0
    free( p_box->data.p_cprt->psz_notice );
3468
0
}
3469
3470
static int MP4_ReadBox_cprt( stream_t *p_stream, MP4_Box_t *p_box )
3471
0
{
3472
0
    uint16_t i_language;
3473
0
    bool b_mac;
3474
3475
0
    MP4_READBOX_ENTER( MP4_Box_data_cprt_t, MP4_FreeBox_cprt );
3476
3477
0
    MP4_GETVERSIONFLAGS( p_box->data.p_cprt );
3478
3479
0
    MP4_GET2BYTES( i_language );
3480
0
    decodeQtLanguageCode( i_language, p_box->data.p_cprt->rgs_language, &b_mac );
3481
3482
0
    MP4_GETSTRINGZ( p_box->data.p_cprt->psz_notice );
3483
3484
0
#ifdef MP4_VERBOSE
3485
0
    msg_Dbg( p_stream, "read box: \"cprt\" language %3.3s notice %s",
3486
0
                      p_box->data.p_cprt->rgs_language,
3487
0
                      p_box->data.p_cprt->psz_notice );
3488
3489
0
#endif
3490
0
    MP4_READBOX_EXIT( 1 );
3491
0
}
3492
3493
static int MP4_ReadBox_dcom( stream_t *p_stream, MP4_Box_t *p_box )
3494
0
{
3495
0
    MP4_READBOX_ENTER( MP4_Box_data_dcom_t, NULL );
3496
3497
0
    MP4_GETFOURCC( p_box->data.p_dcom->i_algorithm );
3498
0
#ifdef MP4_VERBOSE
3499
0
    msg_Dbg( p_stream,
3500
0
             "read box: \"dcom\" compression algorithm : %4.4s",
3501
0
                      (char*)&p_box->data.p_dcom->i_algorithm );
3502
0
#endif
3503
0
    MP4_READBOX_EXIT( 1 );
3504
0
}
3505
3506
static void MP4_FreeBox_cmvd( MP4_Box_t *p_box )
3507
0
{
3508
0
    free( p_box->data.p_cmvd->p_data );
3509
0
}
3510
3511
static int MP4_ReadBox_cmvd( stream_t *p_stream, MP4_Box_t *p_box )
3512
0
{
3513
0
    MP4_READBOX_ENTER( MP4_Box_data_cmvd_t, MP4_FreeBox_cmvd );
3514
3515
0
    MP4_GET4BYTES( p_box->data.p_cmvd->i_uncompressed_size );
3516
3517
0
    p_box->data.p_cmvd->i_compressed_size = i_read;
3518
3519
0
    if( !( p_box->data.p_cmvd->p_data = malloc( i_read ) ) )
3520
0
        MP4_READBOX_EXIT( 0 );
3521
3522
    /* now copy compressed data */
3523
0
    memcpy( p_box->data.p_cmvd->p_data, p_peek,i_read);
3524
3525
0
#ifdef MP4_VERBOSE
3526
0
    msg_Dbg( p_stream, "read box: \"cmvd\" compressed data size %d",
3527
0
                      p_box->data.p_cmvd->i_compressed_size );
3528
0
#endif
3529
3530
0
    MP4_READBOX_EXIT( 1 );
3531
0
}
3532
3533
static int MP4_ReadBox_cmov( stream_t *p_stream, MP4_Box_t *p_box )
3534
0
{
3535
0
#ifndef HAVE_ZLIB
3536
0
    (void)p_box;
3537
0
    msg_Dbg( p_stream, "read box: \"cmov\" zlib unsupported" );
3538
0
    return 0;
3539
#else
3540
3541
    MP4_Box_t *p_dcom;
3542
    MP4_Box_t *p_cmvd;
3543
3544
    stream_t *p_stream_memory;
3545
    z_stream z_data;
3546
    uint8_t *p_data;
3547
3548
    if( !MP4_ReadBoxContainer( p_stream, p_box ) )
3549
    {
3550
        return 0;
3551
    }
3552
3553
    if( ( p_dcom = MP4_BoxGet( p_box, "dcom" ) ) == NULL ||
3554
        ( p_cmvd = MP4_BoxGet( p_box, "cmvd" ) ) == NULL ||
3555
        p_cmvd->data.p_cmvd->p_data == NULL )
3556
    {
3557
        msg_Warn( p_stream, "read box: \"cmov\" incomplete" );
3558
        return 0;
3559
    }
3560
3561
    if( p_dcom->data.p_dcom->i_algorithm != ATOM_zlib )
3562
    {
3563
        msg_Dbg( p_stream, "read box: \"cmov\" compression algorithm : %4.4s "
3564
                 "not supported", (char*)&p_dcom->data.p_dcom->i_algorithm );
3565
        return 0;
3566
    }
3567
3568
    /* decompress data */
3569
    /* allocate a new buffer */
3570
    if( !( p_data = malloc( p_cmvd->data.p_cmvd->i_uncompressed_size ) ) )
3571
        return 0;
3572
    /* init default structures */
3573
    z_data.next_in   = p_cmvd->data.p_cmvd->p_data;
3574
    z_data.avail_in  = p_cmvd->data.p_cmvd->i_compressed_size;
3575
    z_data.next_out  = p_data;
3576
    z_data.avail_out = p_cmvd->data.p_cmvd->i_uncompressed_size;
3577
    z_data.zalloc    = (alloc_func)Z_NULL;
3578
    z_data.zfree     = (free_func)Z_NULL;
3579
    z_data.opaque    = (voidpf)Z_NULL;
3580
3581
    /* init zlib */
3582
    if( inflateInit( &z_data ) != Z_OK )
3583
    {
3584
        msg_Err( p_stream, "read box: \"cmov\" error while uncompressing" );
3585
        free( p_data );
3586
        return 0;
3587
    }
3588
3589
    /* uncompress */
3590
    if( inflate( &z_data, Z_FINISH ) != Z_STREAM_END )
3591
    {
3592
        msg_Err( p_stream, "read box: \"cmov\" error while uncompressing" );
3593
        inflateEnd( &z_data );
3594
        free( p_data );
3595
        return 0;
3596
    }
3597
3598
    if( p_cmvd->data.p_cmvd->i_uncompressed_size != z_data.total_out )
3599
    {
3600
        msg_Warn( p_stream, "read box: \"cmov\" uncompressing data size "
3601
                  "mismatch" );
3602
    }
3603
3604
    /* close zlib */
3605
    if( inflateEnd( &z_data ) != Z_OK )
3606
    {
3607
        msg_Warn( p_stream, "read box: \"cmov\" error while uncompressing "
3608
                  "data (ignored)" );
3609
    }
3610
3611
    msg_Dbg( p_stream, "read box: \"cmov\" box successfully uncompressed" );
3612
3613
    /* now create a memory stream */
3614
    p_stream_memory = vlc_stream_MemoryNew( VLC_OBJECT(p_stream),
3615
                                            p_data, z_data.total_out, false );
3616
    if( !p_stream_memory )
3617
    {
3618
        free( p_data );
3619
        return 0;
3620
    }
3621
3622
    /* and read uncompressd moov */
3623
    MP4_Box_t *p_moov =  MP4_ReadBox( p_stream_memory, NULL );
3624
3625
    vlc_stream_Delete( p_stream_memory );
3626
3627
    if( p_moov )
3628
        MP4_BoxAddChild( p_box, p_moov );
3629
3630
#ifdef MP4_VERBOSE
3631
    msg_Dbg( p_stream, "read box: \"cmov\" compressed movie header completed");
3632
#endif
3633
3634
    return p_moov ? 1 : 0;
3635
#endif /* HAVE_ZLIB */
3636
0
}
3637
3638
static void MP4_FreeBox_rdrf( MP4_Box_t *p_box )
3639
0
{
3640
0
    free( p_box->data.p_rdrf->psz_ref );
3641
0
}
3642
3643
static int MP4_ReadBox_rdrf( stream_t *p_stream, MP4_Box_t *p_box )
3644
0
{
3645
0
    uint32_t i_len;
3646
0
    MP4_READBOX_ENTER( MP4_Box_data_rdrf_t, MP4_FreeBox_rdrf );
3647
3648
0
    MP4_GETVERSIONFLAGS( p_box->data.p_rdrf );
3649
0
    MP4_GETFOURCC( p_box->data.p_rdrf->i_ref_type );
3650
0
    MP4_GET4BYTES( i_len );
3651
0
    i_len++;
3652
3653
0
    if( i_len > 0 )
3654
0
    {
3655
0
        p_box->data.p_rdrf->psz_ref = malloc( i_len );
3656
0
        if( p_box->data.p_rdrf->psz_ref == NULL )
3657
0
            MP4_READBOX_EXIT( 0 );
3658
0
        i_len--;
3659
3660
0
        for( unsigned i = 0; i < i_len; i++ )
3661
0
        {
3662
0
            MP4_GET1BYTE( p_box->data.p_rdrf->psz_ref[i] );
3663
0
        }
3664
0
        p_box->data.p_rdrf->psz_ref[i_len] = '\0';
3665
0
    }
3666
0
    else
3667
0
    {
3668
0
        p_box->data.p_rdrf->psz_ref = NULL;
3669
0
    }
3670
3671
0
#ifdef MP4_VERBOSE
3672
0
    msg_Dbg( p_stream,
3673
0
            "read box: \"rdrf\" type:%4.4s ref %s",
3674
0
            (char*)&p_box->data.p_rdrf->i_ref_type,
3675
0
            p_box->data.p_rdrf->psz_ref );
3676
0
#endif
3677
0
    MP4_READBOX_EXIT( 1 );
3678
0
}
3679
3680
3681
3682
static int MP4_ReadBox_rmdr( stream_t *p_stream, MP4_Box_t *p_box )
3683
0
{
3684
0
    MP4_READBOX_ENTER( MP4_Box_data_rmdr_t, NULL );
3685
3686
0
    MP4_GETVERSIONFLAGS( p_box->data.p_rmdr );
3687
3688
0
    MP4_GET4BYTES( p_box->data.p_rmdr->i_rate );
3689
3690
0
#ifdef MP4_VERBOSE
3691
0
    msg_Dbg( p_stream,
3692
0
             "read box: \"rmdr\" rate:%d",
3693
0
             p_box->data.p_rmdr->i_rate );
3694
0
#endif
3695
0
    MP4_READBOX_EXIT( 1 );
3696
0
}
3697
3698
static int MP4_ReadBox_rmqu( stream_t *p_stream, MP4_Box_t *p_box )
3699
0
{
3700
0
    MP4_READBOX_ENTER( MP4_Box_data_rmqu_t, NULL );
3701
3702
0
    MP4_GET4BYTES( p_box->data.p_rmqu->i_quality );
3703
3704
0
#ifdef MP4_VERBOSE
3705
0
    msg_Dbg( p_stream,
3706
0
             "read box: \"rmqu\" quality:%d",
3707
0
             p_box->data.p_rmqu->i_quality );
3708
0
#endif
3709
0
    MP4_READBOX_EXIT( 1 );
3710
0
}
3711
3712
static int MP4_ReadBox_rmvc( stream_t *p_stream, MP4_Box_t *p_box )
3713
0
{
3714
0
    MP4_READBOX_ENTER( MP4_Box_data_rmvc_t, NULL );
3715
0
    MP4_GETVERSIONFLAGS( p_box->data.p_rmvc );
3716
3717
0
    MP4_GETFOURCC( p_box->data.p_rmvc->i_gestaltType );
3718
0
    MP4_GET4BYTES( p_box->data.p_rmvc->i_val1 );
3719
0
    MP4_GET4BYTES( p_box->data.p_rmvc->i_val2 );
3720
0
    MP4_GET2BYTES( p_box->data.p_rmvc->i_checkType );
3721
3722
0
#ifdef MP4_VERBOSE
3723
0
    msg_Dbg( p_stream,
3724
0
             "read box: \"rmvc\" gestaltType:%4.4s val1:0x%x val2:0x%x checkType:0x%x",
3725
0
             (char*)&p_box->data.p_rmvc->i_gestaltType,
3726
0
             p_box->data.p_rmvc->i_val1,p_box->data.p_rmvc->i_val2,
3727
0
             p_box->data.p_rmvc->i_checkType );
3728
0
#endif
3729
3730
0
    MP4_READBOX_EXIT( 1 );
3731
0
}
3732
3733
static int MP4_ReadBox_frma( stream_t *p_stream, MP4_Box_t *p_box )
3734
0
{
3735
0
    MP4_READBOX_ENTER( MP4_Box_data_frma_t, NULL );
3736
3737
0
    MP4_GETFOURCC( p_box->data.p_frma->i_type );
3738
3739
0
#ifdef MP4_VERBOSE
3740
0
    msg_Dbg( p_stream, "read box: \"frma\" i_type:%4.4s",
3741
0
             (char *)&p_box->data.p_frma->i_type );
3742
0
#endif
3743
3744
0
    MP4_READBOX_EXIT( 1 );
3745
0
}
3746
3747
static int MP4_ReadBox_skcr( stream_t *p_stream, MP4_Box_t *p_box )
3748
0
{
3749
0
    MP4_READBOX_ENTER( MP4_Box_data_skcr_t, NULL );
3750
3751
0
    MP4_GET4BYTES( p_box->data.p_skcr->i_init );
3752
0
    MP4_GET4BYTES( p_box->data.p_skcr->i_encr );
3753
0
    MP4_GET4BYTES( p_box->data.p_skcr->i_decr );
3754
3755
0
#ifdef MP4_VERBOSE
3756
0
    msg_Dbg( p_stream, "read box: \"skcr\" i_init:%d i_encr:%d i_decr:%d",
3757
0
             p_box->data.p_skcr->i_init,
3758
0
             p_box->data.p_skcr->i_encr,
3759
0
             p_box->data.p_skcr->i_decr );
3760
0
#endif
3761
3762
0
    MP4_READBOX_EXIT( 1 );
3763
0
}
3764
3765
static int MP4_ReadBox_drms( stream_t *p_stream, MP4_Box_t *p_box )
3766
0
{
3767
0
    VLC_UNUSED(p_box);
3768
    /* ATOMs 'user', 'key', 'iviv', and 'priv' will be skipped,
3769
     * so unless data decrypt itself by magic, there will be no playback,
3770
     * but we never know... */
3771
0
    msg_Warn( p_stream, "DRM protected streams are not supported." );
3772
0
    return 1;
3773
0
}
3774
3775
static void MP4_FreeBox_Binary( MP4_Box_t *p_box )
3776
0
{
3777
0
    free( p_box->data.p_binary->p_blob );
3778
0
}
3779
3780
static int MP4_ReadBox_Binary( stream_t *p_stream, MP4_Box_t *p_box )
3781
0
{
3782
0
    MP4_READBOX_ENTER( MP4_Box_data_binary_t, MP4_FreeBox_Binary );
3783
0
    i_read = __MIN( i_read, UINT32_MAX );
3784
0
    if ( i_read > 0 )
3785
0
    {
3786
0
        p_box->data.p_binary->p_blob = malloc( i_read );
3787
0
        if ( p_box->data.p_binary->p_blob )
3788
0
        {
3789
0
            memcpy( p_box->data.p_binary->p_blob, p_peek, i_read );
3790
0
            p_box->data.p_binary->i_blob = i_read;
3791
0
        }
3792
0
    }
3793
0
    MP4_READBOX_EXIT( 1 );
3794
0
}
3795
3796
static void MP4_FreeBox_data( MP4_Box_t *p_box )
3797
0
{
3798
0
    free( p_box->data.p_data->p_blob );
3799
0
}
3800
3801
static int MP4_ReadBox_data( stream_t *p_stream, MP4_Box_t *p_box )
3802
0
{
3803
0
    MP4_READBOX_ENTER( MP4_Box_data_data_t, MP4_FreeBox_data );
3804
0
    MP4_Box_data_data_t *p_data = p_box->data.p_data;
3805
3806
0
    if ( i_read < 8 || i_read - 8 > UINT32_MAX )
3807
0
        MP4_READBOX_EXIT( 0 );
3808
3809
0
    uint8_t i_type;
3810
0
    MP4_GET1BYTE( i_type );
3811
0
    if ( i_type != 0 )
3812
0
    {
3813
0
#ifdef MP4_VERBOSE
3814
0
        msg_Dbg( p_stream, "skipping unknown 'data' atom with type %"PRIu8, i_type );
3815
0
#endif
3816
0
        MP4_READBOX_EXIT( 0 );
3817
0
    }
3818
3819
0
    MP4_GET3BYTES( p_data->e_wellknowntype );
3820
0
    MP4_GET2BYTES( p_data->locale.i_country );
3821
0
    MP4_GET2BYTES( p_data->locale.i_language );
3822
0
#ifdef MP4_VERBOSE
3823
0
        msg_Dbg( p_stream, "read 'data' atom: knowntype=%"PRIu32", country=%"PRIu16" lang=%"PRIu16
3824
0
                 ", size %"PRIu64" bytes", p_data->e_wellknowntype,
3825
0
                 p_data->locale.i_country, p_data->locale.i_language, i_read );
3826
0
#endif
3827
0
    p_box->data.p_data->p_blob = malloc( i_read );
3828
0
    if ( !p_box->data.p_data->p_blob )
3829
0
        MP4_READBOX_EXIT( 0 );
3830
3831
0
    p_box->data.p_data->i_blob = i_read;
3832
0
    memcpy( p_box->data.p_data->p_blob, p_peek, i_read);
3833
3834
0
    MP4_READBOX_EXIT( 1 );
3835
0
}
3836
3837
static int MP4_ReadBox_Metadata( stream_t *p_stream, MP4_Box_t *p_box )
3838
0
{
3839
0
    const uint8_t *p_peek;
3840
0
    if ( vlc_stream_Peek( p_stream, &p_peek, 16 ) < 16 )
3841
0
        return 0;
3842
0
    if ( vlc_stream_Read( p_stream, NULL, 8 ) != 8 )
3843
0
        return 0;
3844
0
    const uint32_t stoplist[] = { ATOM_data, 0 };
3845
0
    return MP4_ReadBoxContainerChildren( p_stream, p_box, stoplist );
3846
0
}
3847
3848
/* Chapter support */
3849
static void MP4_FreeBox_chpl( MP4_Box_t *p_box )
3850
0
{
3851
0
    MP4_Box_data_chpl_t *p_chpl = p_box->data.p_chpl;
3852
0
    for( unsigned i = 0; i < p_chpl->i_chapter; i++ )
3853
0
        free( p_chpl->chapter[i].psz_name );
3854
0
}
3855
3856
static int MP4_ReadBox_chpl( stream_t *p_stream, MP4_Box_t *p_box )
3857
0
{
3858
0
    MP4_Box_data_chpl_t *p_chpl;
3859
0
    uint32_t i_dummy;
3860
0
    VLC_UNUSED(i_dummy);
3861
0
    int i;
3862
0
    MP4_READBOX_ENTER( MP4_Box_data_chpl_t, MP4_FreeBox_chpl );
3863
3864
0
    p_chpl = p_box->data.p_chpl;
3865
3866
0
    MP4_GETVERSIONFLAGS( p_chpl );
3867
3868
0
    if ( i_read < 5 || p_chpl->i_version != 0x1 )
3869
0
        MP4_READBOX_EXIT( 0 );
3870
3871
0
    MP4_GET4BYTES( i_dummy );
3872
3873
0
    MP4_GET1BYTE( p_chpl->i_chapter );
3874
3875
0
    for( i = 0; i < p_chpl->i_chapter; i++ )
3876
0
    {
3877
0
        uint64_t i_start;
3878
0
        uint8_t i_len;
3879
0
        int i_copy;
3880
0
        if ( i_read < 9 )
3881
0
            break;
3882
0
        MP4_GET8BYTES( i_start );
3883
0
        MP4_GET1BYTE( i_len );
3884
3885
0
        p_chpl->chapter[i].psz_name = malloc( i_len + 1 );
3886
0
        if( !p_chpl->chapter[i].psz_name )
3887
0
            MP4_READBOX_EXIT( 0 );
3888
3889
0
        i_copy = __MIN( i_len, i_read );
3890
0
        if( i_copy > 0 )
3891
0
            memcpy( p_chpl->chapter[i].psz_name, p_peek, i_copy );
3892
0
        p_chpl->chapter[i].psz_name[i_copy] = '\0';
3893
0
        p_chpl->chapter[i].i_start = i_start;
3894
3895
0
        p_peek += i_copy;
3896
0
        i_read -= i_copy;
3897
0
    }
3898
3899
0
    if ( i != p_chpl->i_chapter )
3900
0
        p_chpl->i_chapter = i;
3901
3902
    /* Bubble sort by increasing start date */
3903
0
    do
3904
0
    {
3905
0
        for( i = 0; i < p_chpl->i_chapter - 1; i++ )
3906
0
        {
3907
0
            if( p_chpl->chapter[i].i_start > p_chpl->chapter[i+1].i_start )
3908
0
            {
3909
0
                char *psz = p_chpl->chapter[i+1].psz_name;
3910
0
                int64_t i64 = p_chpl->chapter[i+1].i_start;
3911
3912
0
                p_chpl->chapter[i+1].psz_name = p_chpl->chapter[i].psz_name;
3913
0
                p_chpl->chapter[i+1].i_start = p_chpl->chapter[i].i_start;
3914
3915
0
                p_chpl->chapter[i].psz_name = psz;
3916
0
                p_chpl->chapter[i].i_start = i64;
3917
3918
0
                i = -1;
3919
0
                break;
3920
0
            }
3921
0
        }
3922
0
    } while( i == -1 );
3923
3924
0
#ifdef MP4_VERBOSE
3925
0
    msg_Dbg( p_stream, "read box: \"chpl\" %d chapters",
3926
0
                       p_chpl->i_chapter );
3927
0
#endif
3928
0
    MP4_READBOX_EXIT( 1 );
3929
0
}
3930
3931
/* GoPro HiLight tags support */
3932
static void MP4_FreeBox_HMMT( MP4_Box_t *p_box )
3933
0
{
3934
0
    free( p_box->data.p_hmmt->pi_chapter_start );
3935
0
}
3936
3937
static int MP4_ReadBox_HMMT( stream_t *p_stream, MP4_Box_t *p_box )
3938
0
{
3939
0
#define MAX_CHAPTER_COUNT 100
3940
3941
0
    MP4_Box_data_HMMT_t *p_hmmt;
3942
0
    MP4_READBOX_ENTER( MP4_Box_data_HMMT_t, MP4_FreeBox_HMMT );
3943
3944
0
    if( i_read < 4 )
3945
0
        MP4_READBOX_EXIT( 0 );
3946
3947
0
    p_hmmt = p_box->data.p_hmmt;
3948
3949
0
    MP4_GET4BYTES( p_hmmt->i_chapter_count );
3950
3951
0
    if( p_hmmt->i_chapter_count <= 0 )
3952
0
    {
3953
0
        p_hmmt->pi_chapter_start = NULL;
3954
0
        MP4_READBOX_EXIT( 1 );
3955
0
    }
3956
3957
0
    if( ( i_read / sizeof(uint32_t) ) < p_hmmt->i_chapter_count )
3958
0
        MP4_READBOX_EXIT( 0 );
3959
3960
    /* Cameras are allowing a maximum of 100 tags */
3961
0
    if( p_hmmt->i_chapter_count > MAX_CHAPTER_COUNT )
3962
0
        p_hmmt->i_chapter_count = MAX_CHAPTER_COUNT;
3963
3964
0
    p_hmmt->pi_chapter_start = vlc_alloc( p_hmmt->i_chapter_count, sizeof(uint32_t) );
3965
0
    if( p_hmmt->pi_chapter_start == NULL )
3966
0
        MP4_READBOX_EXIT( 0 );
3967
3968
0
    for( uint32_t i = 0; i < p_hmmt->i_chapter_count; i++ )
3969
0
    {
3970
0
        MP4_GET4BYTES( p_hmmt->pi_chapter_start[i] );
3971
0
    }
3972
3973
0
#ifdef MP4_VERBOSE
3974
0
    msg_Dbg( p_stream, "read box: \"HMMT\" %d HiLight tags", p_hmmt->i_chapter_count );
3975
0
#endif
3976
3977
0
    MP4_READBOX_EXIT( 1 );
3978
0
}
3979
3980
static void MP4_FreeBox_TrackReference( MP4_Box_t *p_box )
3981
0
{
3982
0
    free( p_box->data.p_track_reference->i_track_ID );
3983
0
}
3984
3985
static int MP4_ReadBox_TrackReference( stream_t *p_stream, MP4_Box_t *p_box )
3986
0
{
3987
0
    uint32_t count;
3988
3989
0
    MP4_READBOX_ENTER( MP4_Box_data_trak_reference_t, MP4_FreeBox_TrackReference );
3990
3991
0
    p_box->data.p_track_reference->i_track_ID = NULL;
3992
0
    count = i_read / sizeof(uint32_t);
3993
0
    p_box->data.p_track_reference->i_entry_count = count;
3994
0
    p_box->data.p_track_reference->i_track_ID = vlc_alloc( count,
3995
0
                                                        sizeof(uint32_t) );
3996
0
    if( p_box->data.p_track_reference->i_track_ID == NULL )
3997
0
        MP4_READBOX_EXIT( 0 );
3998
3999
0
    for( unsigned i = 0; i < count; i++ )
4000
0
    {
4001
0
        MP4_GET4BYTES( p_box->data.p_track_reference->i_track_ID[i] );
4002
0
    }
4003
0
#ifdef MP4_VERBOSE
4004
0
        msg_Dbg( p_stream, "read box: \"chap\" %d references",
4005
0
                 p_box->data.p_track_reference->i_entry_count );
4006
0
#endif
4007
4008
0
    MP4_READBOX_EXIT( 1 );
4009
0
}
4010
4011
static int MP4_ReadBox_tref( stream_t *p_stream, MP4_Box_t *p_box )
4012
0
{
4013
    /* skip header */
4014
0
    size_t i_header = mp4_box_headersize( p_box );
4015
0
    if( vlc_stream_Read( p_stream, NULL, i_header ) != (ssize_t) i_header )
4016
0
        return 0;
4017
    /* read each reference atom with forced handler */
4018
0
    uint64_t i_remain = p_box->i_size - 8;
4019
0
    while ( i_remain > 8 )
4020
0
    {
4021
0
        MP4_Box_t *p_childbox = MP4_ReadBoxUsing( p_stream, p_box,
4022
0
                                                  MP4_ReadBox_TrackReference );
4023
0
        if( !p_childbox || i_remain < p_childbox->i_size )
4024
0
        {
4025
0
            MP4_BoxFree( p_childbox );
4026
0
            break;
4027
0
        }
4028
4029
0
        MP4_BoxAddChild( p_box, p_childbox );
4030
0
        i_remain -= p_childbox->i_size;
4031
0
    }
4032
4033
0
    return MP4_Seek( p_stream, p_box->i_pos + p_box->i_size ) ? 0 : 1;
4034
0
}
4035
4036
static void MP4_FreeBox_keys( MP4_Box_t *p_box )
4037
0
{
4038
0
    for( uint32_t i=0; i<p_box->data.p_keys->i_entry_count; i++ )
4039
0
        free( p_box->data.p_keys->p_entries[i].psz_value );
4040
0
    free( p_box->data.p_keys->p_entries );
4041
0
}
4042
4043
static int MP4_ReadBox_keys( stream_t *p_stream, MP4_Box_t *p_box )
4044
0
{
4045
0
    MP4_READBOX_ENTER( MP4_Box_data_keys_t, MP4_FreeBox_keys );
4046
4047
0
    if ( i_read < 8 )
4048
0
        MP4_READBOX_EXIT( 0 );
4049
4050
0
    uint32_t i_count;
4051
0
    MP4_GET4BYTES( i_count ); /* reserved + flags */
4052
0
    if ( i_count != 0 )
4053
0
        MP4_READBOX_EXIT( 0 );
4054
4055
0
    MP4_GET4BYTES( i_count );
4056
0
    p_box->data.p_keys->p_entries = calloc( i_count, sizeof(*p_box->data.p_keys->p_entries) );
4057
0
    if ( !p_box->data.p_keys->p_entries )
4058
0
        MP4_READBOX_EXIT( 0 );
4059
0
    p_box->data.p_keys->i_entry_count = i_count;
4060
4061
0
    uint32_t i=0;
4062
0
    for( ; i < i_count; i++ )
4063
0
    {
4064
0
        if ( i_read < 8 )
4065
0
            break;
4066
0
        uint32_t i_keysize;
4067
0
        MP4_GET4BYTES( i_keysize );
4068
0
        if ( (i_keysize < 8) || (i_keysize - 4 > i_read) )
4069
0
            break;
4070
0
        MP4_GETFOURCC( p_box->data.p_keys->p_entries[i].i_namespace );
4071
0
        i_keysize -= 8;
4072
0
        p_box->data.p_keys->p_entries[i].psz_value = malloc( i_keysize + 1 );
4073
0
        if ( !p_box->data.p_keys->p_entries[i].psz_value )
4074
0
            break;
4075
0
        memcpy( p_box->data.p_keys->p_entries[i].psz_value, p_peek, i_keysize );
4076
0
        p_box->data.p_keys->p_entries[i].psz_value[i_keysize] = 0;
4077
0
        p_peek += i_keysize;
4078
0
        i_read -= i_keysize;
4079
#ifdef MP4_ULTRA_VERBOSE
4080
        msg_Dbg( p_stream, "read box: \"keys\": %u '%s'", i + 1,
4081
                 p_box->data.p_keys->p_entries[i].psz_value );
4082
#endif
4083
0
    }
4084
0
    if ( i < i_count )
4085
0
        p_box->data.p_keys->i_entry_count = i;
4086
4087
0
    MP4_READBOX_EXIT( 1 );
4088
0
}
4089
4090
static int MP4_ReadBox_colr( stream_t *p_stream, MP4_Box_t *p_box )
4091
0
{
4092
0
    MP4_READBOX_ENTER( MP4_Box_data_colr_t, NULL );
4093
0
    MP4_GETFOURCC( p_box->data.p_colr->i_type );
4094
0
    if ( p_box->data.p_colr->i_type == VLC_FOURCC( 'n', 'c', 'l', 'c' ) ||
4095
0
         p_box->data.p_colr->i_type == VLC_FOURCC( 'n', 'c', 'l', 'x' ) )
4096
0
    {
4097
0
        MP4_GET2BYTES( p_box->data.p_colr->nclc.i_primary_idx );
4098
0
        MP4_GET2BYTES( p_box->data.p_colr->nclc.i_transfer_function_idx );
4099
0
        MP4_GET2BYTES( p_box->data.p_colr->nclc.i_matrix_idx );
4100
0
        if ( p_box->data.p_colr->i_type == VLC_FOURCC( 'n', 'c', 'l', 'x' ) )
4101
0
            MP4_GET1BYTE( p_box->data.p_colr->nclc.i_full_range );
4102
0
    }
4103
0
    else
4104
0
    {
4105
0
#ifdef MP4_VERBOSE
4106
0
        msg_Warn( p_stream, "Unhandled colr type: %4.4s", (char*)&p_box->data.p_colr->i_type );
4107
0
#endif
4108
0
    }
4109
0
    MP4_READBOX_EXIT( 1 );
4110
0
}
4111
4112
static int MP4_ReadBox_irot( stream_t *p_stream, MP4_Box_t *p_box )
4113
0
{
4114
0
    MP4_READBOX_ENTER( MP4_Box_data_irot_t, NULL );
4115
0
    MP4_GET1BYTE( p_box->data.p_irot->i_ccw_degrees );
4116
0
    p_box->data.p_irot->i_ccw_degrees &= 0x03;
4117
0
    p_box->data.p_irot->i_ccw_degrees *= 90;
4118
0
    MP4_READBOX_EXIT( 1 );
4119
0
}
4120
4121
static int MP4_ReadBox_dvcC( stream_t *p_stream, MP4_Box_t *p_box )
4122
0
{
4123
0
    MP4_Box_data_dvcC_t *p_dvcC;
4124
0
    uint16_t flags;
4125
0
    MP4_READBOX_ENTER( MP4_Box_data_dvcC_t, NULL );
4126
0
    p_dvcC = p_box->data.p_dvcC;
4127
0
    MP4_GET1BYTE( p_dvcC->i_version_major );
4128
0
    MP4_GET1BYTE( p_dvcC->i_version_minor );
4129
0
    MP4_GET2BYTES( flags );
4130
0
    p_dvcC->i_profile       = (flags >> 9) & 0x7f;  // 7 bits
4131
0
    p_dvcC->i_level         = (flags >> 3) & 0x3f;  // 6 bits
4132
0
    p_dvcC->i_rpu_present   = (flags >> 2) & 0x01;  // 1 bit
4133
0
    p_dvcC->i_el_present    = (flags >> 1) & 0x01;  // 1 bit
4134
0
    p_dvcC->i_bl_present    =  flags       & 0x01;  // 1 bit
4135
    /* TODO: remainder of box, if needed */
4136
0
    MP4_READBOX_EXIT( 1 );
4137
0
}
4138
4139
static int MP4_ReadBox_meta( stream_t *p_stream, MP4_Box_t *p_box )
4140
0
{
4141
0
    const uint8_t *p_peek;
4142
0
    const size_t i_headersize = mp4_box_headersize( p_box );
4143
4144
0
    if( p_box->i_size < 16 || p_box->i_size - i_headersize < 8 )
4145
0
        return 0;
4146
4147
    /* skip over box header */
4148
0
    if( vlc_stream_Read( p_stream, NULL, i_headersize ) != (ssize_t) i_headersize )
4149
0
        return 0;
4150
4151
    /* meta content starts with a 4 byte version/flags value (should be 0) */
4152
0
    if( vlc_stream_Peek( p_stream, &p_peek, 8 ) < 8 )
4153
0
        return 0;
4154
4155
0
    if( !memcmp( p_peek, "\0\0\0", 4 ) ) /* correct header case */
4156
0
    {
4157
0
        if( vlc_stream_Read( p_stream, NULL, 4 ) != 4 )
4158
0
            return 0;
4159
0
    }
4160
0
    else if( memcmp( &p_peek[4], "hdlr", 4 ) ) /* Broken, headerless ones */
4161
0
    {
4162
0
       return 0;
4163
0
    }
4164
4165
    /* load child atoms up to the handler (which should be next anyway) */
4166
0
    const uint32_t stoplist[] = { ATOM_hdlr, 0 };
4167
0
    if ( !MP4_ReadBoxContainerChildren( p_stream, p_box, stoplist ) )
4168
0
        return 0;
4169
4170
    /* Mandatory */
4171
0
    const MP4_Box_t *p_hdlr = MP4_BoxGet( p_box, "hdlr" );
4172
0
    if ( p_hdlr && BOXDATA(p_hdlr) && BOXDATA(p_hdlr)->i_version == 0 )
4173
0
    {
4174
0
        p_box->i_handler = BOXDATA(p_hdlr)->i_handler_type;
4175
0
        switch( p_box->i_handler )
4176
0
        {
4177
0
            case HANDLER_pict:
4178
0
            case HANDLER_mdta:
4179
0
            case HANDLER_mdir:
4180
                /* then it behaves like a container */
4181
0
                return MP4_ReadBoxContainerChildren( p_stream, p_box, NULL );
4182
0
            default:
4183
                /* skip parsing, will be seen as empty container */
4184
0
                break;
4185
0
        }
4186
0
    }
4187
4188
0
    return 1;
4189
0
}
4190
4191
static int MP4_ReadBox_iods( stream_t *p_stream, MP4_Box_t *p_box )
4192
0
{
4193
0
    char i_unused;
4194
0
    VLC_UNUSED(i_unused);
4195
4196
0
    MP4_READBOX_ENTER( MP4_Box_data_iods_t, NULL );
4197
0
    MP4_GETVERSIONFLAGS( p_box->data.p_iods );
4198
4199
0
    MP4_GET1BYTE( i_unused ); /* tag */
4200
0
    MP4_GET1BYTE( i_unused ); /* length */
4201
4202
0
    MP4_GET2BYTES( p_box->data.p_iods->i_object_descriptor ); /* 10bits, 6 other bits
4203
                                                              are used for other flags */
4204
0
    MP4_GET1BYTE( p_box->data.p_iods->i_OD_profile_level );
4205
0
    MP4_GET1BYTE( p_box->data.p_iods->i_scene_profile_level );
4206
0
    MP4_GET1BYTE( p_box->data.p_iods->i_audio_profile_level );
4207
0
    MP4_GET1BYTE( p_box->data.p_iods->i_visual_profile_level );
4208
0
    MP4_GET1BYTE( p_box->data.p_iods->i_graphics_profile_level );
4209
4210
0
#ifdef MP4_VERBOSE
4211
0
    msg_Dbg( p_stream,
4212
0
             "read box: \"iods\" objectDescriptorId: %i, OD: %i, scene: %i, audio: %i, "
4213
0
             "visual: %i, graphics: %i",
4214
0
             p_box->data.p_iods->i_object_descriptor >> 6,
4215
0
             p_box->data.p_iods->i_OD_profile_level,
4216
0
             p_box->data.p_iods->i_scene_profile_level,
4217
0
             p_box->data.p_iods->i_audio_profile_level,
4218
0
             p_box->data.p_iods->i_visual_profile_level,
4219
0
             p_box->data.p_iods->i_graphics_profile_level );
4220
0
#endif
4221
4222
0
    MP4_READBOX_EXIT( 1 );
4223
0
}
4224
4225
static int MP4_ReadBox_btrt( stream_t *p_stream, MP4_Box_t *p_box )
4226
0
{
4227
0
    MP4_READBOX_ENTER( MP4_Box_data_btrt_t, NULL );
4228
4229
0
    if(i_read != 12)
4230
0
        MP4_READBOX_EXIT( 0 );
4231
4232
0
    MP4_GET4BYTES( p_box->data.p_btrt->i_buffer_size );
4233
0
    MP4_GET4BYTES( p_box->data.p_btrt->i_max_bitrate );
4234
0
    MP4_GET4BYTES( p_box->data.p_btrt->i_avg_bitrate );
4235
4236
0
    MP4_READBOX_EXIT( 1 );
4237
0
}
4238
4239
static int MP4_ReadBox_pasp( stream_t *p_stream, MP4_Box_t *p_box )
4240
0
{
4241
0
    MP4_READBOX_ENTER( MP4_Box_data_pasp_t, NULL );
4242
4243
0
    MP4_GET4BYTES( p_box->data.p_pasp->i_horizontal_spacing );
4244
0
    MP4_GET4BYTES( p_box->data.p_pasp->i_vertical_spacing );
4245
4246
0
#ifdef MP4_VERBOSE
4247
0
    msg_Dbg( p_stream,
4248
0
             "read box: \"paps\" %dx%d",
4249
0
             p_box->data.p_pasp->i_horizontal_spacing,
4250
0
             p_box->data.p_pasp->i_vertical_spacing);
4251
0
#endif
4252
4253
0
    MP4_READBOX_EXIT( 1 );
4254
0
}
4255
4256
static int MP4_ReadBox_clap( stream_t *p_stream, MP4_Box_t *p_box )
4257
0
{
4258
0
    MP4_READBOX_ENTER( MP4_Box_data_clap_t, NULL );
4259
4260
0
    if ( i_read != 32 )
4261
0
        MP4_READBOX_EXIT( 0 );
4262
4263
0
    MP4_Box_data_clap_t *p_clap = p_box->data.p_clap;
4264
0
    uint32_t num, den;
4265
4266
0
    MP4_GET4BYTES( num ); MP4_GET4BYTES( den );
4267
0
    p_clap->i_width = num / (den ? den : 1);
4268
0
    MP4_GET4BYTES( num ); MP4_GET4BYTES( den );
4269
0
    p_clap->i_height = num / (den ? den : 1);
4270
0
    MP4_GET4BYTES( num ); MP4_GET4BYTES( den );
4271
0
    p_clap->i_x_offset = num / (den ? den : 1);
4272
0
    MP4_GET4BYTES( num ); MP4_GET4BYTES( den );
4273
0
    p_clap->i_y_offset = num / (den ? den : 1);
4274
4275
0
    if( UINT32_MAX - p_clap->i_width < p_clap->i_x_offset ||
4276
0
        UINT32_MAX - p_clap->i_height < p_clap->i_y_offset )
4277
0
        MP4_READBOX_EXIT( 0 );
4278
4279
0
#ifdef MP4_VERBOSE
4280
0
    msg_Dbg( p_stream,
4281
0
             "read box: \"clap\" %"PRIu32"x%"PRIu32"+%"PRIu32"+%"PRIu32,
4282
0
             p_box->data.p_clap->i_width, p_box->data.p_clap->i_height,
4283
0
             p_box->data.p_clap->i_x_offset, p_box->data.p_clap->i_y_offset );
4284
0
#endif
4285
4286
0
    MP4_READBOX_EXIT( 1 );
4287
0
}
4288
4289
static int MP4_ReadBox_mehd( stream_t *p_stream, MP4_Box_t *p_box )
4290
0
{
4291
0
    MP4_READBOX_ENTER( MP4_Box_data_mehd_t, NULL );
4292
4293
0
    MP4_GETVERSIONFLAGS( p_box->data.p_mehd );
4294
0
    if( p_box->data.p_mehd->i_version == 1 )
4295
0
        MP4_GET8BYTES( p_box->data.p_mehd->i_fragment_duration );
4296
0
    else /* version == 0 */
4297
0
        MP4_GET4BYTES( p_box->data.p_mehd->i_fragment_duration );
4298
4299
0
#ifdef MP4_VERBOSE
4300
0
    msg_Dbg( p_stream,
4301
0
             "read box: \"mehd\" frag dur. %"PRIu64"",
4302
0
             p_box->data.p_mehd->i_fragment_duration );
4303
0
#endif
4304
4305
0
    MP4_READBOX_EXIT( 1 );
4306
0
}
4307
4308
static int MP4_ReadBox_trex( stream_t *p_stream, MP4_Box_t *p_box )
4309
0
{
4310
0
    MP4_READBOX_ENTER( MP4_Box_data_trex_t, NULL );
4311
0
    MP4_GETVERSIONFLAGS( p_box->data.p_trex );
4312
4313
0
    MP4_GET4BYTES( p_box->data.p_trex->i_track_ID );
4314
0
    MP4_GET4BYTES( p_box->data.p_trex->i_default_sample_description_index );
4315
0
    MP4_GET4BYTES( p_box->data.p_trex->i_default_sample_duration );
4316
0
    MP4_GET4BYTES( p_box->data.p_trex->i_default_sample_size );
4317
0
    MP4_GET4BYTES( p_box->data.p_trex->i_default_sample_flags );
4318
4319
0
#ifdef MP4_VERBOSE
4320
0
    msg_Dbg( p_stream,
4321
0
             "read box: \"trex\" trackID: %"PRIu32"",
4322
0
             p_box->data.p_trex->i_track_ID );
4323
0
#endif
4324
4325
0
    MP4_READBOX_EXIT( 1 );
4326
0
}
4327
4328
static void MP4_FreeBox_sdtp( MP4_Box_t *p_box )
4329
0
{
4330
0
    free( p_box->data.p_sdtp->p_sample_table );
4331
0
}
4332
4333
static int MP4_ReadBox_sdtp( stream_t *p_stream, MP4_Box_t *p_box )
4334
0
{
4335
0
    uint32_t i_sample_count;
4336
0
    MP4_READBOX_ENTER( MP4_Box_data_sdtp_t, MP4_FreeBox_sdtp );
4337
0
    MP4_Box_data_sdtp_t *p_sdtp = p_box->data.p_sdtp;
4338
0
    MP4_GETVERSIONFLAGS( p_box->data.p_sdtp );
4339
0
    i_sample_count = i_read;
4340
4341
0
    p_sdtp->p_sample_table = malloc( i_sample_count );
4342
0
    if( unlikely(p_sdtp->p_sample_table == NULL) )
4343
0
        MP4_READBOX_EXIT( 0 );
4344
4345
0
    for( uint32_t i = 0; i < i_sample_count; i++ )
4346
0
        MP4_GET1BYTE( p_sdtp->p_sample_table[i] );
4347
4348
0
#ifdef MP4_VERBOSE
4349
0
    msg_Dbg( p_stream, "i_sample_count is %"PRIu32"", i_sample_count );
4350
0
    if ( i_sample_count > 3 )
4351
0
        msg_Dbg( p_stream,
4352
0
             "read box: \"sdtp\" head: %"PRIx8" %"PRIx8" %"PRIx8" %"PRIx8"",
4353
0
                 p_sdtp->p_sample_table[0],
4354
0
                 p_sdtp->p_sample_table[1],
4355
0
                 p_sdtp->p_sample_table[2],
4356
0
                 p_sdtp->p_sample_table[3] );
4357
0
#endif
4358
4359
0
    MP4_READBOX_EXIT( 1 );
4360
0
}
4361
4362
static int MP4_ReadBox_tsel( stream_t *p_stream, MP4_Box_t *p_box )
4363
0
{
4364
0
    MP4_READBOX_ENTER( MP4_Box_data_tsel_t, NULL );
4365
0
    uint32_t i_version;
4366
0
    MP4_GET4BYTES( i_version );
4367
0
    if ( i_version != 0 || i_read < 4 )
4368
0
        MP4_READBOX_EXIT( 0 );
4369
0
    MP4_GET4BYTES( p_box->data.p_tsel->i_switch_group );
4370
    /* ignore list of attributes as es are present before switch */
4371
0
    MP4_READBOX_EXIT( 1 );
4372
0
}
4373
4374
static int MP4_ReadBox_mfro( stream_t *p_stream, MP4_Box_t *p_box )
4375
0
{
4376
0
    MP4_READBOX_ENTER( MP4_Box_data_mfro_t, NULL );
4377
4378
0
    MP4_GETVERSIONFLAGS( p_box->data.p_mfro );
4379
0
    MP4_GET4BYTES( p_box->data.p_mfro->i_size );
4380
4381
0
#ifdef MP4_VERBOSE
4382
0
    msg_Dbg( p_stream,
4383
0
             "read box: \"mfro\" size: %"PRIu32"",
4384
0
             p_box->data.p_mfro->i_size);
4385
0
#endif
4386
4387
0
    MP4_READBOX_EXIT( 1 );
4388
0
}
4389
4390
static void MP4_FreeBox_tfra( MP4_Box_t *p_box )
4391
0
{
4392
0
    free( p_box->data.p_tfra->p_time );
4393
0
    free( p_box->data.p_tfra->p_moof_offset );
4394
0
    free( p_box->data.p_tfra->p_traf_number );
4395
0
    free( p_box->data.p_tfra->p_trun_number );
4396
0
    free( p_box->data.p_tfra->p_sample_number );
4397
0
}
4398
4399
static int MP4_ReadBox_tfra( stream_t *p_stream, MP4_Box_t *p_box )
4400
0
{
4401
0
#define READ_VARIABLE_LENGTH(lengthvar, p_array) switch (lengthvar)\
4402
0
{\
4403
0
    case 0:\
4404
0
        MP4_GET1BYTE( p_array[i] );\
4405
0
        break;\
4406
0
    case 1:\
4407
0
        MP4_GET2BYTES( *((uint16_t *)&p_array[i*2]) );\
4408
0
        break;\
4409
0
    case 2:\
4410
0
        MP4_GET3BYTES( *((uint32_t *)&p_array[i*4]) );\
4411
0
        break;\
4412
0
    case 3:\
4413
0
        MP4_GET4BYTES( *((uint32_t *)&p_array[i*4]) );\
4414
0
        break;\
4415
0
    default:\
4416
0
        goto error;\
4417
0
}
4418
0
#define FIX_VARIABLE_LENGTH(lengthvar) if ( lengthvar == 3 ) lengthvar = 4
4419
4420
0
    uint32_t i_number_of_entries;
4421
0
    MP4_READBOX_ENTER( MP4_Box_data_tfra_t, MP4_FreeBox_tfra );
4422
0
    MP4_Box_data_tfra_t *p_tfra = p_box->data.p_tfra;
4423
0
    MP4_GETVERSIONFLAGS( p_box->data.p_tfra );
4424
0
    if ( p_tfra->i_version > 1 )
4425
0
        MP4_READBOX_EXIT( 0 );
4426
0
    MP4_GET4BYTES( p_tfra->i_track_ID );
4427
0
    uint32_t i_lengths = 0;
4428
0
    MP4_GET4BYTES( i_lengths );
4429
0
    MP4_GET4BYTES( p_tfra->i_number_of_entries );
4430
0
    i_number_of_entries = p_tfra->i_number_of_entries;
4431
0
    p_tfra->i_length_size_of_traf_num = i_lengths >> 4;
4432
0
    p_tfra->i_length_size_of_trun_num = ( i_lengths & 0x0c ) >> 2;
4433
0
    p_tfra->i_length_size_of_sample_num = i_lengths & 0x03;
4434
4435
0
    size_t size;
4436
0
    p_tfra->p_time = calloc( i_number_of_entries, sizeof(*p_tfra->p_time) );
4437
0
    p_tfra->p_moof_offset = calloc( i_number_of_entries, sizeof(*p_tfra->p_moof_offset) );
4438
4439
0
    size = 1 + p_tfra->i_length_size_of_traf_num; /* size in [|1, 4|] */
4440
0
    if ( size == 3 ) size++;
4441
0
    p_tfra->p_traf_number = calloc( i_number_of_entries, size );
4442
0
    size = 1 + p_tfra->i_length_size_of_trun_num;
4443
0
    if ( size == 3 ) size++;
4444
0
    p_tfra->p_trun_number = calloc( i_number_of_entries, size );
4445
0
    size = 1 + p_tfra->i_length_size_of_sample_num;
4446
0
    if ( size == 3 ) size++;
4447
0
    p_tfra->p_sample_number = calloc( i_number_of_entries, size );
4448
4449
0
    if( !p_tfra->p_time || !p_tfra->p_moof_offset || !p_tfra->p_traf_number
4450
0
                        || !p_tfra->p_trun_number || !p_tfra->p_sample_number )
4451
0
        goto error;
4452
4453
0
    unsigned i_fields_length = 3 + p_tfra->i_length_size_of_traf_num
4454
0
            + p_tfra->i_length_size_of_trun_num
4455
0
            + p_tfra->i_length_size_of_sample_num;
4456
4457
0
    uint32_t i;
4458
0
    for( i = 0; i < i_number_of_entries; i++ )
4459
0
    {
4460
4461
0
        if( p_tfra->i_version == 1 )
4462
0
        {
4463
0
            if ( i_read < i_fields_length + 16 )
4464
0
                break;
4465
0
            MP4_GET8BYTES( p_tfra->p_time[i] );
4466
0
            MP4_GET8BYTES( p_tfra->p_moof_offset[i] );
4467
0
        }
4468
0
        else
4469
0
        {
4470
0
            if ( i_read < i_fields_length + 8 )
4471
0
                break;
4472
0
            MP4_GET4BYTES( p_tfra->p_time[i] );
4473
0
            MP4_GET4BYTES( p_tfra->p_moof_offset[i] );
4474
0
        }
4475
4476
0
        READ_VARIABLE_LENGTH(p_tfra->i_length_size_of_traf_num, p_tfra->p_traf_number);
4477
0
        READ_VARIABLE_LENGTH(p_tfra->i_length_size_of_trun_num, p_tfra->p_trun_number);
4478
0
        READ_VARIABLE_LENGTH(p_tfra->i_length_size_of_sample_num, p_tfra->p_sample_number);
4479
0
    }
4480
0
    if ( i < i_number_of_entries )
4481
0
        i_number_of_entries = i;
4482
4483
0
    FIX_VARIABLE_LENGTH(p_tfra->i_length_size_of_traf_num);
4484
0
    FIX_VARIABLE_LENGTH(p_tfra->i_length_size_of_trun_num);
4485
0
    FIX_VARIABLE_LENGTH(p_tfra->i_length_size_of_sample_num);
4486
4487
#ifdef MP4_ULTRA_VERBOSE
4488
    for( i = 0; i < i_number_of_entries; i++ )
4489
    {
4490
        msg_Dbg( p_stream, "tfra[%"PRIu32"] time[%"PRIu32"]: %"PRIu64", "
4491
                            "moof_offset[%"PRIu32"]: %"PRIu64"",
4492
                    p_tfra->i_track_ID,
4493
                    i, p_tfra->p_time[i],
4494
                    i, p_tfra->p_moof_offset[i] );
4495
    }
4496
#endif
4497
0
#ifdef MP4_VERBOSE
4498
0
    msg_Dbg( p_stream, "tfra[%"PRIu32"] %"PRIu32" entries",
4499
0
             p_tfra->i_track_ID, i_number_of_entries );
4500
0
#endif
4501
4502
0
    MP4_READBOX_EXIT( 1 );
4503
0
error:
4504
0
    MP4_READBOX_EXIT( 0 );
4505
4506
0
#undef READ_VARIABLE_LENGTH
4507
0
#undef FIX_VARIABLE_LENGTH
4508
0
}
4509
4510
static int MP4_ReadBox_pnot( stream_t *p_stream, MP4_Box_t *p_box )
4511
0
{
4512
0
    if ( p_box->i_size != 20 )
4513
0
        return 0;
4514
0
    MP4_READBOX_ENTER( MP4_Box_data_pnot_t, NULL );
4515
0
    MP4_GET4BYTES( p_box->data.p_pnot->i_date );
4516
0
    uint16_t i_version;
4517
0
    MP4_GET2BYTES( i_version );
4518
0
    if ( i_version != 0 )
4519
0
        MP4_READBOX_EXIT( 0 );
4520
0
    MP4_GETFOURCC( p_box->data.p_pnot->i_type );
4521
0
    MP4_GET2BYTES( p_box->data.p_pnot->i_index );
4522
0
    MP4_READBOX_EXIT( 1 );
4523
0
}
4524
4525
static int MP4_ReadBox_SA3D( stream_t *p_stream, MP4_Box_t *p_box )
4526
0
{
4527
0
    MP4_READBOX_ENTER( MP4_Box_data_SA3D_t, NULL );
4528
4529
0
    uint8_t i_version;
4530
0
    MP4_GET1BYTE( i_version );
4531
0
    if ( i_version != 0 )
4532
0
        MP4_READBOX_EXIT( 0 );
4533
4534
0
    MP4_GET1BYTE( p_box->data.p_SA3D->i_ambisonic_type );
4535
0
    MP4_GET4BYTES( p_box->data.p_SA3D->i_ambisonic_order );
4536
0
    MP4_GET1BYTE( p_box->data.p_SA3D->i_ambisonic_channel_ordering );
4537
0
    MP4_GET1BYTE( p_box->data.p_SA3D->i_ambisonic_normalization );
4538
0
    MP4_GET4BYTES( p_box->data.p_SA3D->i_num_channels );
4539
0
    MP4_READBOX_EXIT( 1 );
4540
0
}
4541
4542
static void MP4_FreeBox_Reference( MP4_Box_t *p_box )
4543
0
{
4544
0
    MP4_Box_data_refbox_t *p_data = p_box->data.p_refbox;
4545
0
    free( p_data->p_references );
4546
0
}
4547
4548
static int MP4_ReadBox_Reference( stream_t *p_stream, MP4_Box_t *p_box )
4549
0
{
4550
0
    MP4_READBOX_ENTER( MP4_Box_data_refbox_t, MP4_FreeBox_Reference );
4551
0
    MP4_Box_data_refbox_t *p_data = p_box->data.p_refbox;
4552
4553
0
    if( p_box->p_father->data.p_iref->i_flags == 0 )
4554
0
        MP4_GET2BYTES( p_data->i_from_item_id );
4555
0
    else
4556
0
        MP4_GET4BYTES( p_data->i_from_item_id );
4557
0
    MP4_GET2BYTES( p_data->i_reference_count );
4558
0
    if( i_read / ((p_box->p_father->data.p_iref->i_flags == 0 ) ? 2 : 4) <
4559
0
            p_data->i_reference_count )
4560
0
        MP4_READBOX_EXIT( 0 );
4561
4562
0
    p_data->p_references = malloc( sizeof(*p_data->p_references) *
4563
0
                                   p_data->i_reference_count );
4564
0
    if( !p_data->p_references )
4565
0
        MP4_READBOX_EXIT( 0 );
4566
0
    for( uint16_t i=0; i<p_data->i_reference_count; i++ )
4567
0
    {
4568
0
        if( p_box->p_father->data.p_iref->i_flags == 0 )
4569
0
            MP4_GET2BYTES( p_data->p_references[i].i_to_item_id );
4570
0
        else
4571
0
            MP4_GET4BYTES( p_data->p_references[i].i_to_item_id );
4572
0
    }
4573
4574
0
    MP4_READBOX_EXIT( 1 );
4575
0
}
4576
4577
static int MP4_ReadBox_iref( stream_t *p_stream, MP4_Box_t *p_box )
4578
0
{
4579
0
    MP4_READBOX_ENTER_PARTIAL( MP4_Box_data_iref_t, 12, NULL );
4580
0
    MP4_Box_data_iref_t *p_data = p_box->data.p_iref;
4581
0
    if( i_read < 4 )
4582
0
        MP4_READBOX_EXIT( 0 );
4583
4584
0
    MP4_GET1BYTE( p_data->i_version );
4585
0
    MP4_GET3BYTES( p_data->i_flags );
4586
0
    if( p_data->i_version > 0 )
4587
0
        MP4_READBOX_EXIT( 0 );
4588
4589
0
    assert( i_read == 0 );
4590
4591
0
    uint64_t i_remain = p_box->i_size - 12;
4592
0
    while ( i_remain > 8 )
4593
0
    {
4594
0
        MP4_Box_t *p_childbox = MP4_ReadBoxUsing( p_stream, p_box,
4595
0
                                                  MP4_ReadBox_Reference );
4596
0
        if( !p_childbox || i_remain < p_childbox->i_size )
4597
0
        {
4598
0
            MP4_BoxFree( p_childbox );
4599
0
            break;
4600
0
        }
4601
4602
0
        MP4_BoxAddChild( p_box, p_childbox );
4603
0
        i_remain -= p_childbox->i_size;
4604
0
    }
4605
4606
0
    if ( MP4_Seek( p_stream, p_box->i_pos + p_box->i_size ) )
4607
0
        MP4_READBOX_EXIT( 0 );
4608
4609
0
    MP4_READBOX_EXIT( 1 );
4610
0
}
4611
4612
static void MP4_FreeBox_iloc( MP4_Box_t *p_box )
4613
0
{
4614
0
    MP4_Box_data_iloc_t *p_data = p_box->data.p_iloc;
4615
0
    if( p_data->p_items )
4616
0
    {
4617
0
        for( uint32_t i=0; i<p_data->i_item_count; i++ )
4618
0
            free( p_data->p_items[i].p_extents );
4619
0
        free( p_data->p_items );
4620
0
    }
4621
0
}
4622
4623
static int MP4_ReadBox_iloc( stream_t *p_stream, MP4_Box_t *p_box )
4624
0
{
4625
0
    MP4_READBOX_ENTER( MP4_Box_data_iloc_t, MP4_FreeBox_iloc );
4626
0
    MP4_Box_data_iloc_t *p_data = p_box->data.p_iloc;
4627
4628
0
    uint16_t i_foo;
4629
4630
0
    uint8_t i_version;
4631
0
    uint32_t i_flags;
4632
0
    MP4_GET1BYTE( i_version );
4633
0
    MP4_GET3BYTES( i_flags );
4634
0
    VLC_UNUSED(i_flags);
4635
4636
0
    MP4_GET1BYTE( p_data->i_offset_size );
4637
0
    p_data->i_length_size = p_data->i_offset_size & 0x0F;
4638
0
    p_data->i_offset_size >>= 4;
4639
0
    MP4_GET1BYTE( p_data->i_base_offset_size );
4640
0
    if( i_version == 0 )
4641
0
        p_data->i_index_size = 0;
4642
0
    else
4643
0
        p_data->i_index_size = p_data->i_base_offset_size & 0x0F;
4644
0
    p_data->i_base_offset_size >>= 4;
4645
4646
    /* Only accept 0,4,8 */
4647
0
    if( (p_data->i_offset_size & 0xF3) || p_data->i_offset_size > 8 ||
4648
0
        (p_data->i_length_size & 0xF3) || p_data->i_length_size > 8 ||
4649
0
        (p_data->i_base_offset_size & 0xF3) || p_data->i_base_offset_size > 8 ||
4650
0
        (p_data->i_index_size & 0xF3) || p_data->i_index_size > 8 )
4651
0
        MP4_READBOX_EXIT( 0 );
4652
4653
0
    if( i_version < 2 )
4654
0
        MP4_GET2BYTES( p_data->i_item_count );
4655
0
    else if( i_version == 2 )
4656
0
        MP4_GET4BYTES( p_data->i_item_count );
4657
0
    else
4658
0
        MP4_READBOX_EXIT( 0 );
4659
4660
0
    if( i_read / 6 < p_data->i_item_count )
4661
0
        MP4_READBOX_EXIT( 0 );
4662
4663
0
    p_data->p_items = malloc( p_data->i_item_count * sizeof(p_data->p_items[0]) );
4664
0
    if( !p_data->p_items )
4665
0
        MP4_READBOX_EXIT( 0 );
4666
4667
0
    for( uint32_t i=0; i<p_data->i_item_count; i++ )
4668
0
    {
4669
0
        if( i_version < 2 )
4670
0
            MP4_GET2BYTES( p_data->p_items[i].i_item_id );
4671
0
        else
4672
0
            MP4_GET4BYTES( p_data->p_items[i].i_item_id );
4673
4674
0
        if( i_version > 0 )
4675
0
        {
4676
0
            MP4_GET2BYTES( i_foo );
4677
0
            p_data->p_items[i].i_construction_method = i_foo & 0x0F;
4678
0
        }
4679
0
        else p_data->p_items[i].i_construction_method = 0;
4680
4681
0
        MP4_GET2BYTES( p_data->p_items[i].i_data_reference_index );
4682
4683
0
        switch( p_data->i_base_offset_size )
4684
0
        {
4685
0
            case 4: MP4_GET4BYTES( p_data->p_items[i].i_base_offset ); break;
4686
0
            case 8: MP4_GET8BYTES( p_data->p_items[i].i_base_offset ); break;
4687
0
            default: p_data->p_items[i].i_base_offset = 0; break;
4688
0
        }
4689
4690
0
        MP4_GET2BYTES( p_data->p_items[i].i_extent_count );
4691
4692
0
        uint64_t i_entrysize = (( i_version > 0 ) ? p_data->i_index_size : 0) +
4693
0
                               p_data->i_offset_size + p_data->i_length_size;
4694
0
        if( i_read / i_entrysize < p_data->p_items[i].i_extent_count )
4695
0
        {
4696
0
            p_data->i_item_count = i;
4697
0
            MP4_READBOX_EXIT( 0 );
4698
0
        }
4699
4700
0
        p_data->p_items[i].p_extents = malloc( p_data->p_items[i].i_extent_count *
4701
0
                                               sizeof(p_data->p_items[i].p_extents[0]) );
4702
0
        for( uint16_t j=0; j<p_data->p_items[i].i_extent_count; j++ )
4703
0
        {
4704
0
            if( i_version > 0 )
4705
0
            {
4706
0
                switch( p_data->i_index_size )
4707
0
                {
4708
0
                    case 4: MP4_GET4BYTES( p_data->p_items[i].p_extents[j].i_extent_index ); break;
4709
0
                    case 8: MP4_GET8BYTES( p_data->p_items[i].p_extents[j].i_extent_index ); break;
4710
0
                    default: p_data->p_items[i].p_extents[j].i_extent_index = 0 ; break;
4711
0
                }
4712
0
            }
4713
0
            switch( p_data->i_offset_size )
4714
0
            {
4715
0
                case 4: MP4_GET4BYTES( p_data->p_items[i].p_extents[j].i_extent_offset ); break;
4716
0
                case 8: MP4_GET8BYTES( p_data->p_items[i].p_extents[j].i_extent_offset ); break;
4717
0
                default: p_data->p_items[i].p_extents[j].i_extent_offset = 0; break;
4718
0
            }
4719
0
            switch( p_data->i_length_size )
4720
0
            {
4721
0
                case 4: MP4_GET4BYTES( p_data->p_items[i].p_extents[j].i_extent_length ); break;
4722
0
                case 8: MP4_GET8BYTES( p_data->p_items[i].p_extents[j].i_extent_length ); break;
4723
0
                default: p_data->p_items[i].p_extents[j].i_extent_length = 0; break;
4724
0
            }
4725
0
        }
4726
0
    }
4727
4728
0
    MP4_READBOX_EXIT( 1 );
4729
0
}
4730
4731
static int MP4_ReadBox_iinf( stream_t *p_stream, MP4_Box_t *p_box )
4732
0
{
4733
0
    const uint8_t *p_versionpeek;
4734
0
    if( vlc_stream_Peek( p_stream, &p_versionpeek, 9 ) < 9 )
4735
0
        return 0;
4736
4737
0
    size_t i_header = 12 + (( p_versionpeek[8] == 0 ) ? 2 : 4);
4738
0
    MP4_READBOX_ENTER_PARTIAL( MP4_Box_data_iinf_t, i_header, NULL );
4739
0
    if( i_read + 8 < i_header )
4740
0
        MP4_READBOX_EXIT( 0 );
4741
4742
0
    uint8_t i_version;
4743
0
    uint32_t i_flags;
4744
0
    MP4_GET1BYTE( i_version );
4745
0
    MP4_GET3BYTES( i_flags ); VLC_UNUSED(i_flags);
4746
0
    if( i_version > 2 )
4747
0
        MP4_READBOX_EXIT( 0 );
4748
4749
0
    if( i_version == 0 )
4750
0
        MP4_GET2BYTES( p_box->data.p_iinf->i_entry_count );
4751
0
    else
4752
0
        MP4_GET4BYTES( p_box->data.p_iinf->i_entry_count );
4753
4754
0
    assert( i_read == 0 );
4755
4756
0
    uint32_t i = 0;
4757
0
    uint64_t i_remain = p_box->i_size - i_header;
4758
0
    while ( i_remain > 8 && i < p_box->data.p_iinf->i_entry_count )
4759
0
    {
4760
0
        MP4_Box_t *p_childbox = MP4_ReadBox( p_stream, p_box );
4761
0
        if( !p_childbox || i_remain < p_childbox->i_size )
4762
0
        {
4763
0
            MP4_BoxFree( p_childbox );
4764
0
            p_box->data.p_iinf->i_entry_count = i;
4765
0
            break;
4766
0
        }
4767
4768
0
        MP4_BoxAddChild( p_box, p_childbox );
4769
0
        i_remain -= p_childbox->i_size;
4770
0
        i++;
4771
0
    }
4772
4773
0
    if ( MP4_Seek( p_stream, p_box->i_pos + p_box->i_size ) )
4774
0
        MP4_READBOX_EXIT( 0 );
4775
4776
0
    MP4_READBOX_EXIT( 1 );
4777
0
}
4778
4779
static void MP4_FreeBox_infe( MP4_Box_t *p_box )
4780
0
{
4781
0
    MP4_Box_data_infe_t *p_data = p_box->data.p_infe;
4782
0
    free( p_data->psz_content_encoding );
4783
0
    free( p_data->psz_content_type );
4784
0
    free( p_data->psz_item_name );
4785
0
    free( p_data->psz_item_uri_type );
4786
0
}
4787
4788
static int MP4_ReadBox_infe( stream_t *p_stream, MP4_Box_t *p_box )
4789
0
{
4790
0
    MP4_READBOX_ENTER( MP4_Box_data_infe_t, MP4_FreeBox_infe );
4791
0
    MP4_Box_data_infe_t *p_data = p_box->data.p_infe;
4792
4793
0
    uint8_t i_version;
4794
0
    MP4_GET1BYTE( i_version );
4795
0
    MP4_GET3BYTES( p_data->i_flags );
4796
0
    if( i_version > 3 )
4797
0
        MP4_READBOX_EXIT( 0 );
4798
4799
0
    if( i_version < 2 )
4800
0
    {
4801
0
        MP4_GET2BYTES( p_data->i_item_id );
4802
0
        MP4_GET2BYTES( p_data->i_item_protection_index );
4803
0
        p_data->psz_item_name = mp4_getstringz( &p_peek, &i_read );
4804
0
        if( i_read > 0 )
4805
0
        {
4806
0
            p_data->psz_content_type = mp4_getstringz( &p_peek, &i_read );
4807
0
            if( i_read > 0 )
4808
0
                p_data->psz_content_encoding = mp4_getstringz( &p_peek, &i_read );
4809
0
        }
4810
4811
        //if( i_version == 1 )
4812
0
        {
4813
            /* extensions, we do not care */
4814
0
        }
4815
0
    }
4816
0
    else
4817
0
    {
4818
0
        if( i_version == 2 )
4819
0
            MP4_GET2BYTES( p_data->i_item_id );
4820
0
        else
4821
0
            MP4_GET4BYTES( p_data->i_item_id );
4822
0
        MP4_GET2BYTES( p_data->i_item_protection_index );
4823
0
        MP4_GETFOURCC( p_data->item_type );
4824
0
        p_data->psz_item_name = mp4_getstringz( &p_peek, &i_read );
4825
0
        if( p_data->item_type == VLC_FOURCC('m','i','m','e') )
4826
0
        {
4827
0
            p_data->psz_content_type = mp4_getstringz( &p_peek, &i_read );
4828
0
            if( i_read > 0 )
4829
0
                p_data->psz_content_encoding = mp4_getstringz( &p_peek, &i_read );
4830
0
        }
4831
0
        else if( p_data->item_type == VLC_FOURCC('u','r','i',' ') )
4832
0
        {
4833
0
            p_data->psz_item_uri_type = mp4_getstringz( &p_peek, &i_read );
4834
0
        }
4835
0
    }
4836
4837
0
    MP4_READBOX_EXIT( 1 );
4838
0
}
4839
4840
static int MP4_ReadBox_pitm( stream_t *p_stream, MP4_Box_t *p_box )
4841
0
{
4842
0
    MP4_READBOX_ENTER( MP4_Box_data_pitm_t, NULL );
4843
0
    MP4_Box_data_pitm_t *p_data = p_box->data.p_pitm;
4844
4845
0
    uint8_t i_version;
4846
0
    uint32_t i_flags;
4847
0
    MP4_GET1BYTE( i_version );
4848
0
    MP4_GET3BYTES( i_flags ); VLC_UNUSED(i_flags);
4849
4850
0
    if( i_version == 0 )
4851
0
        MP4_GET2BYTES( p_data->i_item_id );
4852
0
    else
4853
0
        MP4_GET4BYTES( p_data->i_item_id );
4854
4855
0
    MP4_READBOX_EXIT( 1 );
4856
0
}
4857
4858
static int MP4_ReadBox_ispe( stream_t *p_stream, MP4_Box_t *p_box )
4859
0
{
4860
0
    MP4_READBOX_ENTER( MP4_Box_data_ispe_t, NULL );
4861
0
    MP4_Box_data_ispe_t *p_data = p_box->data.p_ispe;
4862
4863
0
    uint8_t i_version;
4864
0
    uint32_t i_flags;
4865
0
    MP4_GET1BYTE( i_version );
4866
0
    MP4_GET3BYTES( i_flags ); VLC_UNUSED(i_flags);
4867
0
    if( i_version > 0 )
4868
0
        MP4_READBOX_EXIT( 0 );
4869
4870
0
    MP4_GET4BYTES( p_data->i_width );
4871
0
    MP4_GET4BYTES( p_data->i_height );
4872
4873
0
    MP4_READBOX_EXIT( 1 );
4874
0
}
4875
4876
static void MP4_FreeBox_ipma( MP4_Box_t *p_box )
4877
0
{
4878
0
    MP4_Box_data_ipma_t *p_data = p_box->data.p_ipma;
4879
0
    for( uint32_t i=0; i<p_data->i_entry_count; i++ )
4880
0
        free( p_data->p_entries[i].p_assocs );
4881
0
    free( p_data->p_entries );
4882
0
}
4883
4884
static int MP4_ReadBox_ipma( stream_t *p_stream, MP4_Box_t *p_box )
4885
0
{
4886
0
    MP4_READBOX_ENTER( MP4_Box_data_ipma_t, MP4_FreeBox_ipma );
4887
0
    MP4_Box_data_ipma_t *p_data = p_box->data.p_ipma;
4888
4889
0
    uint8_t i_version;
4890
0
    uint32_t i_flags;
4891
0
    MP4_GET1BYTE( i_version );
4892
0
    MP4_GET3BYTES( i_flags );
4893
4894
0
    MP4_GET4BYTES( p_data->i_entry_count );
4895
0
    if( (i_read / ((i_version < 1) ? 3 : 5) <  p_data->i_entry_count) )
4896
0
    {
4897
0
        p_data->i_entry_count = 0;
4898
0
        MP4_READBOX_EXIT( 0 );
4899
0
    }
4900
4901
0
    p_data->p_entries = malloc( sizeof(p_data->p_entries[0]) * p_data->i_entry_count );
4902
0
    if( !p_data->p_entries )
4903
0
    {
4904
0
        p_data->i_entry_count = 0;
4905
0
        MP4_READBOX_EXIT( 0 );
4906
0
    }
4907
4908
0
    for( uint32_t i=0; i<p_data->i_entry_count; i++ )
4909
0
    {
4910
0
        if( i_read < ((i_version < 1) ? 3 : 5) )
4911
0
        {
4912
0
            p_data->i_entry_count = i;
4913
0
            MP4_READBOX_EXIT( 0 );
4914
0
        }
4915
0
        if( i_version < 1 )
4916
0
            MP4_GET2BYTES( p_data->p_entries[i].i_item_id );
4917
0
        else
4918
0
            MP4_GET4BYTES( p_data->p_entries[i].i_item_id );
4919
0
        MP4_GET1BYTE( p_data->p_entries[i].i_association_count );
4920
4921
0
        if( i_read / ((i_flags & 0x01) ? 2 : 1) <
4922
0
               p_data->p_entries[i].i_association_count )
4923
0
        {
4924
0
            p_data->i_entry_count = i;
4925
0
            MP4_READBOX_EXIT( 0 );
4926
0
        }
4927
4928
0
        p_data->p_entries[i].p_assocs =
4929
0
                malloc( sizeof(p_data->p_entries[i].p_assocs[0]) *
4930
0
                        p_data->p_entries[i].i_association_count );
4931
0
        if( !p_data->p_entries[i].p_assocs )
4932
0
        {
4933
0
            p_data->p_entries[i].i_association_count = 0;
4934
0
            p_data->i_entry_count = i;
4935
0
            MP4_READBOX_EXIT( 0 );
4936
0
        }
4937
4938
0
        for( uint8_t j=0; j<p_data->p_entries[i].i_association_count; j++ )
4939
0
        {
4940
0
            MP4_GET1BYTE( p_data->p_entries[i].p_assocs[j].i_property_index );
4941
0
            p_data->p_entries[i].p_assocs[j].b_essential =
4942
0
                    p_data->p_entries[i].p_assocs[j].i_property_index & 0x80;
4943
0
            p_data->p_entries[i].p_assocs[j].i_property_index &= 0x7F;
4944
0
            if( i_flags & 0x01 )
4945
0
            {
4946
0
                p_data->p_entries[i].p_assocs[j].i_property_index <<= 8;
4947
0
                uint8_t i_low;
4948
0
                MP4_GET1BYTE( i_low );
4949
0
                p_data->p_entries[i].p_assocs[j].i_property_index |= i_low;
4950
0
            }
4951
0
        }
4952
0
    }
4953
4954
0
    MP4_READBOX_EXIT( 1 );
4955
0
}
4956
4957
/* For generic */
4958
static int MP4_ReadBox_default( stream_t *p_stream, MP4_Box_t *p_box )
4959
0
{
4960
0
    if( !p_box->p_father )
4961
0
    {
4962
0
        goto unknown;
4963
0
    }
4964
4965
0
unknown:
4966
0
    if MP4_BOX_TYPE_ASCII()
4967
0
        msg_Warn( p_stream,
4968
0
                "unknown box type %4.4s (incompletely loaded)",
4969
0
                (char*)&p_box->i_type );
4970
0
    else
4971
0
        msg_Warn( p_stream,
4972
0
                "unknown box type c%3.3s (incompletely loaded)",
4973
0
                (char*)&p_box->i_type+1 );
4974
0
    p_box->e_flags |= BOX_FLAG_INCOMPLETE;
4975
4976
0
    return 1;
4977
0
}
4978
4979
/**** ------------------------------------------------------------------- ****/
4980
4981
static int MP4_ReadBox_uuid( stream_t *p_stream, MP4_Box_t *p_box )
4982
0
{
4983
0
    if( !CmpUUID( &p_box->i_uuid, &TfrfBoxUUID ) )
4984
0
        return MP4_ReadBox_tfrf( p_stream, p_box );
4985
0
    if( !CmpUUID( &p_box->i_uuid, &TfxdBoxUUID ) )
4986
0
        return MP4_ReadBox_tfxd( p_stream, p_box );
4987
0
    if( !CmpUUID( &p_box->i_uuid, &XML360BoxUUID ) )
4988
0
        return MP4_ReadBox_XML360( p_stream, p_box );
4989
0
    if( !CmpUUID( &p_box->i_uuid, &PS3DDSBoxUUID ) && p_box->i_size == 28 )
4990
0
        return MP4_ReadBox_Binary( p_stream, p_box );
4991
4992
0
#ifdef MP4_VERBOSE
4993
0
    msg_Warn( p_stream, "Unknown uuid type box: "
4994
0
    "%2.2x%2.2x%2.2x%2.2x-%2.2x%2.2x-%2.2x%2.2x-"
4995
0
    "%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
4996
0
    p_box->i_uuid.b[0],  p_box->i_uuid.b[1],  p_box->i_uuid.b[2],  p_box->i_uuid.b[3],
4997
0
    p_box->i_uuid.b[4],  p_box->i_uuid.b[5],  p_box->i_uuid.b[6],  p_box->i_uuid.b[7],
4998
0
    p_box->i_uuid.b[8],  p_box->i_uuid.b[9],  p_box->i_uuid.b[10], p_box->i_uuid.b[11],
4999
0
    p_box->i_uuid.b[12], p_box->i_uuid.b[13], p_box->i_uuid.b[14], p_box->i_uuid.b[15] );
5000
#else
5001
    msg_Warn( p_stream, "Unknown uuid type box" );
5002
#endif
5003
0
    return 1;
5004
0
}
5005
5006
/**** ------------------------------------------------------------------- ****/
5007
/****                   "Higher level" Functions                          ****/
5008
/**** ------------------------------------------------------------------- ****/
5009
5010
static const struct
5011
{
5012
    uint32_t i_type;
5013
    int  (*MP4_ReadBox_function )( stream_t *p_stream, MP4_Box_t *p_box );
5014
    uint32_t i_parent; /* set parent to restrict, duplicating if needed; 0 for any */
5015
} MP4_Box_Function [] =
5016
{
5017
    /* Containers */
5018
    { ATOM_moov,    MP4_ReadBoxContainer,     0 },
5019
    { ATOM_trak,    MP4_ReadBoxContainer,     ATOM_moov },
5020
    { ATOM_trak,    MP4_ReadBoxContainer,     ATOM_foov },
5021
    { ATOM_mdia,    MP4_ReadBox_mdia,         ATOM_trak },
5022
    { ATOM_moof,    MP4_ReadBoxContainer,     0 },
5023
    { ATOM_minf,    MP4_ReadBoxContainer,     ATOM_mdia },
5024
    { ATOM_stbl,    MP4_ReadBoxContainer,     ATOM_minf },
5025
    { ATOM_dinf,    MP4_ReadBoxContainer,     ATOM_minf },
5026
    { ATOM_dinf,    MP4_ReadBoxContainer,     ATOM_meta },
5027
    { ATOM_edts,    MP4_ReadBoxContainer,     ATOM_trak },
5028
    { ATOM_udta,    MP4_ReadBoxContainer,     0 },
5029
    { ATOM_nmhd,    MP4_ReadBoxContainer,     ATOM_minf },
5030
    { ATOM_hnti,    MP4_ReadBoxContainer,     ATOM_udta },
5031
    { ATOM_rmra,    MP4_ReadBoxContainer,     ATOM_moov },
5032
    { ATOM_rmda,    MP4_ReadBoxContainer,     ATOM_rmra },
5033
    { ATOM_tref,    MP4_ReadBox_tref,         ATOM_trak },
5034
    { ATOM_gmhd,    MP4_ReadBoxContainer,     ATOM_minf },
5035
    { ATOM_wave,    MP4_ReadBoxContainer,     ATOM_stsd },
5036
    { ATOM_wave,    MP4_ReadBoxContainer,     ATOM_mp4a }, /* some quicktime mp4a/wave/mp4a.. */
5037
    { ATOM_wave,    MP4_ReadBoxContainer,     ATOM_WMA2 }, /* flip4mac */
5038
    { ATOM_wave,    MP4_ReadBoxContainer,     ATOM_in24 },
5039
    { ATOM_wave,    MP4_ReadBoxContainer,     ATOM_in32 },
5040
    { ATOM_wave,    MP4_ReadBoxContainer,     ATOM_fl32 },
5041
    { ATOM_wave,    MP4_ReadBoxContainer,     ATOM_fl64 },
5042
    { ATOM_wave,    MP4_ReadBoxContainer,     ATOM_QDMC },
5043
    { ATOM_wave,    MP4_ReadBoxContainer,     ATOM_QDM2 },
5044
    { ATOM_wave,    MP4_ReadBoxContainer,     ATOM_XiFL }, /* XiphQT */
5045
    { ATOM_wave,    MP4_ReadBoxContainer,     ATOM_XiVs }, /* XiphQT */
5046
    { ATOM_ilst,    MP4_ReadBox_ilst,         ATOM_meta },
5047
    { ATOM_mvex,    MP4_ReadBoxContainer,     ATOM_moov },
5048
    { ATOM_mvex,    MP4_ReadBoxContainer,     ATOM_ftyp },
5049
5050
    /* Quicktime compression */
5051
    { ATOM_foov,    MP4_ReadBoxContainer,     0 },
5052
    { ATOM_cmov,    MP4_ReadBox_cmov,         ATOM_foov },
5053
    { ATOM_cmov,    MP4_ReadBox_cmov,         ATOM_moov },
5054
    { ATOM_dcom,    MP4_ReadBox_dcom,         ATOM_cmov },
5055
    { ATOM_cmvd,    MP4_ReadBox_cmvd,         ATOM_cmov },
5056
5057
    /* specific box */
5058
    { ATOM_ftyp,    MP4_ReadBox_ftyp,         0 },
5059
    { ATOM_styp,    MP4_ReadBox_ftyp,         0 },
5060
    { ATOM_mvhd,    MP4_ReadBox_mvhd,         ATOM_moov },
5061
    { ATOM_mvhd,    MP4_ReadBox_mvhd,         ATOM_foov },
5062
    { ATOM_tkhd,    MP4_ReadBox_tkhd,         ATOM_trak },
5063
    { ATOM_load,    MP4_ReadBox_load,         ATOM_trak },
5064
    { ATOM_mdhd,    MP4_ReadBox_mdhd,         ATOM_mdia },
5065
    { ATOM_hdlr,    MP4_ReadBox_hdlr,         ATOM_mdia },
5066
    { ATOM_hdlr,    MP4_ReadBox_hdlr,         ATOM_meta },
5067
    { ATOM_hdlr,    MP4_ReadBox_hdlr,         ATOM_minf },
5068
    { ATOM_vmhd,    MP4_ReadBox_vmhd,         ATOM_minf },
5069
    { ATOM_smhd,    MP4_ReadBox_smhd,         ATOM_minf },
5070
    { ATOM_hmhd,    MP4_ReadBox_hmhd,         ATOM_minf },
5071
    { ATOM_alis,    MP4_ReadBoxSkip,          ATOM_dref },
5072
    { ATOM_url,     MP4_ReadBox_url,          0 },
5073
    { ATOM_urn,     MP4_ReadBox_urn,          0 },
5074
    { ATOM_dref,    MP4_ReadBox_LtdContainer, 0 },
5075
    { ATOM_stts,    MP4_ReadBox_stts,         ATOM_stbl },
5076
    { ATOM_ctts,    MP4_ReadBox_ctts,         ATOM_stbl },
5077
    { ATOM_cslg,    MP4_ReadBox_cslg,         ATOM_stbl },
5078
    { ATOM_stsd,    MP4_ReadBox_stsd,         ATOM_stbl },
5079
    { ATOM_stsz,    MP4_ReadBox_stsz,         ATOM_stbl },
5080
    { ATOM_stz2,    MP4_ReadBox_stz2,         ATOM_stbl },
5081
    { ATOM_stsc,    MP4_ReadBox_stsc,         ATOM_stbl },
5082
    { ATOM_stco,    MP4_ReadBox_stco_co64,    ATOM_stbl },
5083
    { ATOM_co64,    MP4_ReadBox_stco_co64,    ATOM_stbl },
5084
    { ATOM_stss,    MP4_ReadBox_stss,         ATOM_stbl },
5085
    { ATOM_stsh,    MP4_ReadBox_stsh,         ATOM_stbl },
5086
    { ATOM_stdp,    MP4_ReadBox_stdp,         0 },
5087
    { ATOM_elst,    MP4_ReadBox_elst,         ATOM_edts },
5088
    { ATOM_cprt,    MP4_ReadBox_cprt,         0 },
5089
    { ATOM_esds,    MP4_ReadBox_esds,         ATOM_wave }, /* mp4a in wave chunk */
5090
    { ATOM_esds,    MP4_ReadBox_esds,         ATOM_mp4a },
5091
    { ATOM_esds,    MP4_ReadBox_esds,         ATOM_mp4v },
5092
    { ATOM_esds,    MP4_ReadBox_esds,         ATOM_mp4s },
5093
    { ATOM_dfLa,    MP4_ReadBox_Binary,       ATOM_fLaC },
5094
    { ATOM_av1C,    MP4_ReadBox_av1C,         ATOM_av01 },
5095
    { ATOM_avcC,    MP4_ReadBox_avcC,         ATOM_avc1 },
5096
    { ATOM_avcC,    MP4_ReadBox_avcC,         ATOM_avc3 },
5097
    { ATOM_vvcC,    MP4_ReadBox_Binary,       ATOM_vvc1 },
5098
    { ATOM_hvcC,    MP4_ReadBox_Binary,       0 },
5099
    { ATOM_jpeC,    MP4_ReadBox_Binary,       0 }, /* heif */
5100
    { ATOM_av1C,    MP4_ReadBox_av1C,         ATOM_ipco }, /* heif */
5101
    { ATOM_vpcC,    MP4_ReadBox_vpcC,         ATOM_vp08 },
5102
    { ATOM_vpcC,    MP4_ReadBox_vpcC,         ATOM_vp09 },
5103
    { ATOM_vpcC,    MP4_ReadBox_vpcC,         ATOM_vp10 },
5104
    { ATOM_SmDm,    MP4_ReadBox_SmDm,         ATOM_vpcC }, /* SMPTE2086 mastering display */
5105
    { ATOM_mdcv,    MP4_ReadBox_SmDm,         0 }, /* */
5106
    { ATOM_CoLL,    MP4_ReadBox_CoLL,         ATOM_vpcC }, /* CEA861-3 light level */
5107
    { ATOM_clli,    MP4_ReadBox_CoLL,         0 }, /* */
5108
    { ATOM_dac3,    MP4_ReadBox_dac3,         0 },
5109
    { ATOM_dec3,    MP4_ReadBox_dec3,         0 },
5110
    { ATOM_dvc1,    MP4_ReadBox_dvc1,         ATOM_vc1  },
5111
    { ATOM_fiel,    MP4_ReadBox_fiel,         0 },
5112
    { ATOM_glbl,    MP4_ReadBox_Binary,       0 },
5113
    { ATOM_enda,    MP4_ReadBox_enda,         0 },
5114
    { ATOM_pcmC,    MP4_ReadBox_pcmC,         0 }, /* ISO-IEC 23003-5 */
5115
    { ATOM_iods,    MP4_ReadBox_iods,         0 },
5116
    { ATOM_pasp,    MP4_ReadBox_pasp,         0 },
5117
    { ATOM_clap,    MP4_ReadBox_clap,         0 },
5118
    { ATOM_btrt,    MP4_ReadBox_btrt,         0 }, /* codecs bitrate stsd/????/btrt */
5119
    { ATOM_keys,    MP4_ReadBox_keys,         ATOM_meta },
5120
    { ATOM_colr,    MP4_ReadBox_colr,         0 },
5121
    { ATOM_irot,    MP4_ReadBox_irot,         0 }, /* heif */
5122
    { ATOM_dvcC,    MP4_ReadBox_dvcC,         0 }, /* dolby vision config record */
5123
    { ATOM_dvvC,    MP4_ReadBox_dvcC,         0 },
5124
    { ATOM_dvwC,    MP4_ReadBox_dvcC,         0 },
5125
5126
    /* XiphQT */
5127
    { ATOM_vCtH,    MP4_ReadBox_Binary,       ATOM_wave },
5128
    { ATOM_vCtC,    MP4_ReadBox_Binary,       ATOM_wave },
5129
    { ATOM_vCtd,    MP4_ReadBox_Binary,       ATOM_wave },
5130
    { ATOM_fCtS,    MP4_ReadBox_Binary,       ATOM_wave },
5131
5132
    /* Samples groups specific information */
5133
    { ATOM_sbgp,    MP4_ReadBox_sbgp,         ATOM_stbl },
5134
    { ATOM_sbgp,    MP4_ReadBox_sbgp,         ATOM_traf },
5135
    { ATOM_sgpd,    MP4_ReadBox_sgpd,         ATOM_stbl },
5136
    { ATOM_sgpd,    MP4_ReadBox_sgpd,         ATOM_traf },
5137
5138
    /* Quicktime preview atoms, all at root */
5139
    { ATOM_pnot,    MP4_ReadBox_pnot,         0 },
5140
    { ATOM_pict,    MP4_ReadBox_Binary,       0 },
5141
    { ATOM_PICT,    MP4_ReadBox_Binary,       0 },
5142
    /* Other preview atoms */
5143
    { ATOM_thum,    MP4_ReadBox_Binary,       0 },
5144
5145
    /* Nothing to do with this box */
5146
    { ATOM_mdat,    MP4_ReadBoxSkip,          0 },
5147
    { ATOM_skip,    MP4_ReadBoxSkip,          0 },
5148
    { ATOM_free,    MP4_ReadBoxSkip,          0 },
5149
    { ATOM_wide,    MP4_ReadBoxSkip,          0 },
5150
    { ATOM_binm,    MP4_ReadBoxSkip,          0 },
5151
5152
    /* In sample WebVTT subtitle atoms. No ATOM_wvtt in normal parsing */
5153
    { ATOM_vttc,    MP4_ReadBoxContainer,         ATOM_wvtt },
5154
    { ATOM_payl,    MP4_ReadBox_Binary,           ATOM_vttc },
5155
5156
    /* Sound extensions */
5157
    { ATOM_chan,    MP4_ReadBox_stsdext_chan, 0 },
5158
    { ATOM_srat,    MP4_ReadBox_stsdext_srat, 0 },
5159
    { ATOM_WMA2,    MP4_ReadBox_WMA2,         ATOM_wave }, /* flip4mac */
5160
    { ATOM_dOps,    MP4_ReadBox_Binary,       ATOM_Opus },
5161
    { ATOM_wfex,    MP4_ReadBox_WMA2,         ATOM_wma  }, /* ismv formatex */
5162
5163
    { ATOM_mjqt,    MP4_ReadBox_default,      0 }, /* found in mjpa/b */
5164
    { ATOM_mjht,    MP4_ReadBox_default,      0 },
5165
5166
    { ATOM_strf,    MP4_ReadBox_strf,         ATOM_WVC1 }, /* MS smooth */
5167
    { ATOM_strf,    MP4_ReadBox_strf,         ATOM_H264 }, /* MS smooth */
5168
5169
    { ATOM_strf,    MP4_ReadBox_strf,         ATOM_WMV3 }, /* flip4mac */
5170
    { ATOM_ASF ,    MP4_ReadBox_ASF,          ATOM_WMV3 }, /* flip4mac */
5171
    { ATOM_ASF ,    MP4_ReadBox_ASF,          ATOM_wave }, /* flip4mac */
5172
5173
    { ATOM_hint,    MP4_ReadBox_default,      ATOM_stbl },
5174
5175
    /* found in hnti */
5176
    { ATOM_rtp,     MP4_ReadBox_rtp,          ATOM_hnti },
5177
    { ATOM_sdp,     MP4_ReadBox_sdp,          ATOM_hnti },
5178
5179
    /* found in rrtp sample description */
5180
    { ATOM_tims,     MP4_ReadBox_tims,        0 },
5181
    { ATOM_tsro,     MP4_ReadBox_tsro,        0 },
5182
    { ATOM_tssy,     MP4_ReadBox_tssy,        0 },
5183
5184
    /* found in rmra/rmda */
5185
    { ATOM_rdrf,    MP4_ReadBox_rdrf,         ATOM_rmda },
5186
    { ATOM_rmdr,    MP4_ReadBox_rmdr,         ATOM_rmda },
5187
    { ATOM_rmqu,    MP4_ReadBox_rmqu,         ATOM_rmda },
5188
    { ATOM_rmvc,    MP4_ReadBox_rmvc,         ATOM_rmda },
5189
5190
    { ATOM_sinf,    MP4_ReadBoxContainer,     0 },
5191
    { ATOM_schi,    MP4_ReadBoxContainer,     0 },
5192
    { ATOM_user,    MP4_ReadBox_drms,         0 },
5193
    { ATOM_key,     MP4_ReadBox_drms,         0 },
5194
    { ATOM_iviv,    MP4_ReadBox_drms,         0 },
5195
    { ATOM_priv,    MP4_ReadBox_drms,         0 },
5196
    { ATOM_frma,    MP4_ReadBox_frma,         ATOM_sinf }, /* and rinf */
5197
    { ATOM_frma,    MP4_ReadBox_frma,         ATOM_wave }, /* flip4mac */
5198
    { ATOM_skcr,    MP4_ReadBox_skcr,         0 },
5199
5200
    /* ilst meta tags */
5201
    { ATOM_0xa9ART, MP4_ReadBox_Metadata,    ATOM_ilst },
5202
    { ATOM_0xa9alb, MP4_ReadBox_Metadata,    ATOM_ilst },
5203
    { ATOM_0xa9cmt, MP4_ReadBox_Metadata,    ATOM_ilst },
5204
    { ATOM_0xa9com, MP4_ReadBox_Metadata,    ATOM_ilst },
5205
    { ATOM_0xa9cpy, MP4_ReadBox_Metadata,    ATOM_ilst },
5206
    { ATOM_0xa9day, MP4_ReadBox_Metadata,    ATOM_ilst },
5207
    { ATOM_0xa9des, MP4_ReadBox_Metadata,    ATOM_ilst },
5208
    { ATOM_0xa9enc, MP4_ReadBox_Metadata,    ATOM_ilst },
5209
    { ATOM_0xa9gen, MP4_ReadBox_Metadata,    ATOM_ilst },
5210
    { ATOM_0xa9grp, MP4_ReadBox_Metadata,    ATOM_ilst },
5211
    { ATOM_0xa9lyr, MP4_ReadBox_Metadata,    ATOM_ilst },
5212
    { ATOM_0xa9nam, MP4_ReadBox_Metadata,    ATOM_ilst },
5213
    { ATOM_0xa9too, MP4_ReadBox_Metadata,    ATOM_ilst },
5214
    { ATOM_0xa9trk, MP4_ReadBox_Metadata,    ATOM_ilst },
5215
    { ATOM_0xa9wrt, MP4_ReadBox_Metadata,    ATOM_ilst },
5216
    { ATOM_aART,    MP4_ReadBox_Metadata,    ATOM_ilst },
5217
    { ATOM_atID,    MP4_ReadBox_Metadata,    ATOM_ilst }, /* iTunes */
5218
    { ATOM_cnID,    MP4_ReadBox_Metadata,    ATOM_ilst }, /* iTunes */
5219
    { ATOM_covr,    MP4_ReadBoxContainer,    ATOM_ilst },
5220
    { ATOM_desc,    MP4_ReadBox_Metadata,    ATOM_ilst },
5221
    { ATOM_disk,    MP4_ReadBox_Metadata,    ATOM_ilst },
5222
    { ATOM_flvr,    MP4_ReadBox_Metadata,    ATOM_ilst },
5223
    { ATOM_gnre,    MP4_ReadBox_Metadata,    ATOM_ilst },
5224
    { ATOM_rtng,    MP4_ReadBox_Metadata,    ATOM_ilst },
5225
    { ATOM_trkn,    MP4_ReadBox_Metadata,    ATOM_ilst },
5226
    { ATOM_xid_,    MP4_ReadBox_Metadata,    ATOM_ilst },
5227
    { ATOM_gshh,    MP4_ReadBox_Metadata,    ATOM_ilst }, /* YouTube gs?? */
5228
    { ATOM_gspm,    MP4_ReadBox_Metadata,    ATOM_ilst },
5229
    { ATOM_gspu,    MP4_ReadBox_Metadata,    ATOM_ilst },
5230
    { ATOM_gssd,    MP4_ReadBox_Metadata,    ATOM_ilst },
5231
    { ATOM_gsst,    MP4_ReadBox_Metadata,    ATOM_ilst },
5232
    { ATOM_gstd,    MP4_ReadBox_Metadata,    ATOM_ilst },
5233
    { ATOM_ITUN,    MP4_ReadBox_Metadata,    ATOM_ilst }, /* iTunesInfo */
5234
    { ATOM_purl,    MP4_ReadBox_Metadata,    ATOM_ilst },
5235
5236
    /* udta */
5237
    { ATOM_0x40PRM, MP4_ReadBox_Binary,    ATOM_udta },
5238
    { ATOM_0x40PRQ, MP4_ReadBox_Binary,    ATOM_udta },
5239
    { ATOM_0xa9ART, MP4_ReadBox_Binary,    ATOM_udta },
5240
    { ATOM_0xa9alb, MP4_ReadBox_Binary,    ATOM_udta },
5241
    { ATOM_0xa9ard, MP4_ReadBox_Binary,    ATOM_udta },
5242
    { ATOM_0xa9arg, MP4_ReadBox_Binary,    ATOM_udta },
5243
    { ATOM_0xa9aut, MP4_ReadBox_Binary,    ATOM_udta },
5244
    { ATOM_0xa9cak, MP4_ReadBox_Binary,    ATOM_udta },
5245
    { ATOM_0xa9cmt, MP4_ReadBox_Binary,    ATOM_udta },
5246
    { ATOM_0xa9con, MP4_ReadBox_Binary,    ATOM_udta },
5247
    { ATOM_0xa9com, MP4_ReadBox_Binary,    ATOM_udta },
5248
    { ATOM_0xa9cpy, MP4_ReadBox_Binary,    ATOM_udta },
5249
    { ATOM_0xa9day, MP4_ReadBox_Binary,    ATOM_udta },
5250
    { ATOM_0xa9des, MP4_ReadBox_Binary,    ATOM_udta },
5251
    { ATOM_0xa9dir, MP4_ReadBox_Binary,    ATOM_udta },
5252
    { ATOM_0xa9dis, MP4_ReadBox_Binary,    ATOM_udta },
5253
    { ATOM_0xa9dsa, MP4_ReadBox_Binary,    ATOM_udta },
5254
    { ATOM_0xa9fmt, MP4_ReadBox_Binary,    ATOM_udta },
5255
    { ATOM_0xa9gen, MP4_ReadBox_Binary,    ATOM_udta },
5256
    { ATOM_0xa9grp, MP4_ReadBox_Binary,    ATOM_udta },
5257
    { ATOM_0xa9hst, MP4_ReadBox_Binary,    ATOM_udta },
5258
    { ATOM_0xa9inf, MP4_ReadBox_Binary,    ATOM_udta },
5259
    { ATOM_0xa9isr, MP4_ReadBox_Binary,    ATOM_udta },
5260
    { ATOM_0xa9lab, MP4_ReadBox_Binary,    ATOM_udta },
5261
    { ATOM_0xa9lal, MP4_ReadBox_Binary,    ATOM_udta },
5262
    { ATOM_0xa9lnt, MP4_ReadBox_Binary,    ATOM_udta },
5263
    { ATOM_0xa9lyr, MP4_ReadBox_Binary,    ATOM_udta },
5264
    { ATOM_0xa9mak, MP4_ReadBox_Binary,    ATOM_udta },
5265
    { ATOM_0xa9mal, MP4_ReadBox_Binary,    ATOM_udta },
5266
    { ATOM_0xa9mod, MP4_ReadBox_Binary,    ATOM_udta },
5267
    { ATOM_0xa9nam, MP4_ReadBox_Binary,    ATOM_udta },
5268
    { ATOM_0xa9ope, MP4_ReadBox_Binary,    ATOM_udta },
5269
    { ATOM_0xa9phg, MP4_ReadBox_Binary,    ATOM_udta },
5270
    { ATOM_0xa9PRD, MP4_ReadBox_Binary,    ATOM_udta },
5271
    { ATOM_0xa9prd, MP4_ReadBox_Binary,    ATOM_udta },
5272
    { ATOM_0xa9prf, MP4_ReadBox_Binary,    ATOM_udta },
5273
    { ATOM_0xa9pub, MP4_ReadBox_Binary,    ATOM_udta },
5274
    { ATOM_0xa9req, MP4_ReadBox_Binary,    ATOM_udta },
5275
    { ATOM_0xa9sne, MP4_ReadBox_Binary,    ATOM_udta },
5276
    { ATOM_0xa9snm, MP4_ReadBox_Binary,    ATOM_udta },
5277
    { ATOM_0xa9sol, MP4_ReadBox_Binary,    ATOM_udta },
5278
    { ATOM_0xa9src, MP4_ReadBox_Binary,    ATOM_udta },
5279
    { ATOM_0xa9st3, MP4_ReadBox_Binary,    ATOM_udta },
5280
    { ATOM_0xa9swr, MP4_ReadBox_Binary,    ATOM_udta },
5281
    { ATOM_0xa9thx, MP4_ReadBox_Binary,    ATOM_udta },
5282
    { ATOM_0xa9too, MP4_ReadBox_Binary,    ATOM_udta },
5283
    { ATOM_0xa9trk, MP4_ReadBox_Binary,    ATOM_udta },
5284
    { ATOM_0xa9url, MP4_ReadBox_Binary,    ATOM_udta },
5285
    { ATOM_0xa9wrn, MP4_ReadBox_Binary,    ATOM_udta },
5286
    { ATOM_0xa9xpd, MP4_ReadBox_Binary,    ATOM_udta },
5287
    { ATOM_0xa9xyz, MP4_ReadBox_Binary,    ATOM_udta },
5288
    { ATOM_chpl,    MP4_ReadBox_chpl,      ATOM_udta }, /* nero unlabeled chapters list */
5289
    { ATOM_MCPS,    MP4_ReadBox_Binary,    ATOM_udta },
5290
    { ATOM_name,    MP4_ReadBox_Binary,    ATOM_udta },
5291
    { ATOM_vndr,    MP4_ReadBox_Binary,    ATOM_udta },
5292
    { ATOM_SDLN,    MP4_ReadBox_Binary,    ATOM_udta },
5293
    { ATOM_HMMT,    MP4_ReadBox_HMMT,      ATOM_udta }, /* GoPro HiLight tags */
5294
5295
    /* udta, non meta */
5296
    { ATOM_tsel,    MP4_ReadBox_tsel,    ATOM_udta },
5297
5298
    /* iTunes/Quicktime meta info */
5299
    { ATOM_meta,    MP4_ReadBox_meta,    0 },
5300
    { ATOM_ID32,    MP4_ReadBox_Binary,  ATOM_meta }, /* ID3v2 in 3GPP / ETSI TS 126 244 8.3 */
5301
    { ATOM_data,    MP4_ReadBox_data,    0 }, /* ilst/@too and others, ITUN/data */
5302
    { ATOM_mean,    MP4_ReadBox_Binary,  ATOM_ITUN },
5303
    { ATOM_name,    MP4_ReadBox_Binary,  ATOM_ITUN },
5304
5305
    /* found in smoothstreaming */
5306
    { ATOM_traf,    MP4_ReadBoxContainer,    ATOM_moof },
5307
    { ATOM_mfra,    MP4_ReadBoxContainer,    0 },
5308
    { ATOM_mfhd,    MP4_ReadBox_mfhd,        ATOM_moof },
5309
    { ATOM_sidx,    MP4_ReadBox_sidx,        0 },
5310
    { ATOM_tfhd,    MP4_ReadBox_tfhd,        ATOM_traf },
5311
    { ATOM_trun,    MP4_ReadBox_trun,        ATOM_traf },
5312
    { ATOM_tfdt,    MP4_ReadBox_tfdt,        ATOM_traf },
5313
    { ATOM_trex,    MP4_ReadBox_trex,        ATOM_mvex },
5314
    { ATOM_mehd,    MP4_ReadBox_mehd,        ATOM_mvex },
5315
    { ATOM_sdtp,    MP4_ReadBox_sdtp,        0 },
5316
    { ATOM_tfra,    MP4_ReadBox_tfra,        ATOM_mfra },
5317
    { ATOM_mfro,    MP4_ReadBox_mfro,        ATOM_mfra },
5318
    { ATOM_uuid,    MP4_ReadBox_uuid,        0 },
5319
5320
    /* spatial/360°/VR */
5321
    { ATOM_st3d,    MP4_ReadBox_st3d,        0 },
5322
    { ATOM_sv3d,    MP4_ReadBoxContainer,    0 },
5323
    { ATOM_proj,    MP4_ReadBoxContainer,    ATOM_sv3d },
5324
    { ATOM_prhd,    MP4_ReadBox_prhd,        ATOM_proj },
5325
    { ATOM_equi,    MP4_ReadBox_equi,        ATOM_proj },
5326
    { ATOM_cbmp,    MP4_ReadBox_cbmp,        ATOM_proj },
5327
5328
    /* Ambisonics */
5329
    { ATOM_SA3D,    MP4_ReadBox_SA3D,        0 },
5330
5331
    /* iso4 brand meta references */
5332
    { ATOM_idat,    MP4_ReadBoxSkip,         ATOM_meta },
5333
    { ATOM_iloc,    MP4_ReadBox_iloc,        ATOM_meta },
5334
    { ATOM_iinf,    MP4_ReadBox_iinf,        ATOM_meta },
5335
    { ATOM_infe,    MP4_ReadBox_infe,        ATOM_iinf },
5336
    { ATOM_iref,    MP4_ReadBox_iref,        ATOM_meta },
5337
    { ATOM_pitm,    MP4_ReadBox_pitm,        ATOM_meta },
5338
5339
    /* HEIF specific meta references */
5340
    { ATOM_iprp,    MP4_ReadBoxContainer,    ATOM_meta },
5341
    { ATOM_ipco,    MP4_ReadBoxContainer,    ATOM_iprp },
5342
    { ATOM_ispe,    MP4_ReadBox_ispe,        ATOM_ipco },
5343
    { ATOM_ipma,    MP4_ReadBox_ipma,        ATOM_iprp },
5344
5345
    /* Last entry */
5346
    { 0,              MP4_ReadBox_default,   0 }
5347
};
5348
5349
static int MP4_Box_Read_Specific( stream_t *p_stream, MP4_Box_t *p_box, MP4_Box_t *p_father )
5350
0
{
5351
0
    int i_index;
5352
5353
0
    for( i_index = 0; ; i_index++ )
5354
0
    {
5355
0
        if ( MP4_Box_Function[i_index].i_parent &&
5356
0
             p_father && p_father->i_type != MP4_Box_Function[i_index].i_parent )
5357
0
            continue;
5358
5359
0
        if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
5360
0
            ( MP4_Box_Function[i_index].i_type == 0 ) )
5361
0
        {
5362
0
            break;
5363
0
        }
5364
0
    }
5365
5366
0
    if( !(MP4_Box_Function[i_index].MP4_ReadBox_function)( p_stream, p_box ) )
5367
0
    {
5368
0
        return VLC_EGENERIC;
5369
0
    }
5370
5371
0
    return VLC_SUCCESS;
5372
0
}
5373
5374
static MP4_Box_t *MP4_ReadBoxAllocateCheck( stream_t *p_stream, MP4_Box_t *p_father )
5375
0
{
5376
0
    MP4_Box_t *p_box = calloc( 1, sizeof( MP4_Box_t ) ); /* Needed to ensure simple on error handler */
5377
0
    if( p_box == NULL )
5378
0
        return NULL;
5379
5380
0
    if( !MP4_PeekBoxHeader( p_stream, p_box ) )
5381
0
    {
5382
0
        msg_Warn( p_stream, "cannot read one box" );
5383
0
        free( p_box );
5384
0
        return NULL;
5385
0
    }
5386
5387
0
    if( p_father && p_father->i_size > 0 &&
5388
0
        p_father->i_pos + p_father->i_size < p_box->i_pos + p_box->i_size )
5389
0
    {
5390
0
        msg_Dbg( p_stream, "out of bound child" );
5391
0
        free( p_box );
5392
0
        return NULL;
5393
0
    }
5394
5395
0
    if( !p_box->i_size )
5396
0
    {
5397
0
        msg_Dbg( p_stream, "found an empty box (null size)" );
5398
0
        free( p_box );
5399
0
        return NULL;
5400
0
    }
5401
0
    p_box->p_father = p_father;
5402
5403
0
    return p_box;
5404
0
}
5405
5406
/*****************************************************************************
5407
 * MP4_ReadBoxUsing : parse the actual box and the children using handler
5408
 *****************************************************************************/
5409
static MP4_Box_t *MP4_ReadBoxUsing( stream_t *p_stream, MP4_Box_t *p_father,
5410
                                    int(*MP4_ReadBox_function)(stream_t *, MP4_Box_t *) )
5411
0
{
5412
0
    MP4_Box_t *p_box = MP4_ReadBoxAllocateCheck( p_stream, p_father );
5413
0
    if( !p_box )
5414
0
        return NULL;
5415
5416
0
    if( MP4_ReadBox_function( p_stream, p_box ) != 1 )
5417
0
    {
5418
0
        uint64_t i_end = p_box->i_pos + p_box->i_size;
5419
0
        MP4_BoxFree( p_box );
5420
0
        MP4_Seek( p_stream, i_end ); /* Skip the failed box */
5421
0
        return NULL;
5422
0
    }
5423
0
    return p_box;
5424
0
}
5425
5426
/*****************************************************************************
5427
 * MP4_ReadBox : parse the actual box and the children
5428
 *  XXX : Do not go to the next box
5429
 *****************************************************************************/
5430
static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father )
5431
0
{
5432
0
    MP4_Box_t *p_box = MP4_ReadBoxAllocateCheck( p_stream, p_father );
5433
0
    if( !p_box )
5434
0
        return NULL;
5435
5436
0
    if( MP4_Box_Read_Specific( p_stream, p_box, p_father ) != VLC_SUCCESS )
5437
0
    {
5438
0
        uint64_t i_end = p_box->i_pos + p_box->i_size;
5439
0
        MP4_BoxFree( p_box );
5440
0
        MP4_Seek( p_stream, i_end ); /* Skip the failed box */
5441
0
        return NULL;
5442
0
    }
5443
0
    return p_box;
5444
0
}
5445
5446
/*****************************************************************************
5447
 * MP4_BoxNew : creates and initializes an arbitrary box
5448
 *****************************************************************************/
5449
MP4_Box_t * MP4_BoxNew( uint32_t i_type )
5450
0
{
5451
0
    MP4_Box_t *p_box = calloc( 1, sizeof( MP4_Box_t ) );
5452
0
    if( likely( p_box != NULL ) )
5453
0
    {
5454
0
        p_box->i_type = i_type;
5455
0
    }
5456
0
    return p_box;
5457
0
}
5458
5459
/*****************************************************************************
5460
 * MP4_FreeBox : free memory after read with MP4_ReadBox and all
5461
 * the children
5462
 *****************************************************************************/
5463
void MP4_BoxFree( MP4_Box_t *p_box )
5464
0
{
5465
0
    MP4_Box_t    *p_child;
5466
5467
0
    if( !p_box )
5468
0
        return; /* hehe */
5469
5470
0
    for( p_child = p_box->p_first; p_child != NULL; )
5471
0
    {
5472
0
        MP4_Box_t *p_next;
5473
5474
0
        p_next = p_child->p_next;
5475
0
        MP4_BoxFree( p_child );
5476
0
        p_child = p_next;
5477
0
    }
5478
5479
0
    if( p_box->pf_free )
5480
0
        p_box->pf_free( p_box );
5481
5482
0
    free( p_box->data.p_payload );
5483
0
    free( p_box );
5484
0
}
5485
5486
MP4_Box_t *MP4_BoxGetNextChunk( stream_t *s )
5487
0
{
5488
    /* p_chunk is a virtual root container for the moof and mdat boxes */
5489
0
    MP4_Box_t *p_fakeroot;
5490
0
    MP4_Box_t *p_tmp_box;
5491
5492
0
    p_fakeroot = MP4_BoxNew( ATOM_root );
5493
0
    if( unlikely( p_fakeroot == NULL ) )
5494
0
        return NULL;
5495
0
    p_fakeroot->i_shortsize = 1;
5496
5497
0
    const uint32_t stoplist[] = { ATOM_moov, ATOM_moof, 0 };
5498
0
    MP4_ReadBoxContainerChildren( s, p_fakeroot, stoplist );
5499
5500
0
    p_tmp_box = p_fakeroot->p_first;
5501
0
    if( p_tmp_box == NULL )
5502
0
    {
5503
0
        MP4_BoxFree( p_fakeroot );
5504
0
        return NULL;
5505
0
    }
5506
0
    else while( p_tmp_box )
5507
0
    {
5508
0
        p_fakeroot->i_size += p_tmp_box->i_size;
5509
0
        p_tmp_box = p_tmp_box->p_next;
5510
0
    }
5511
5512
0
    return p_fakeroot;
5513
0
}
5514
5515
/*****************************************************************************
5516
 * MP4_BoxGetRoot : Parse the entire file, and create all boxes in memory
5517
 *****************************************************************************
5518
 *  The first box is a virtual box "root" and is the father for all first
5519
 *  level boxes for the file, a sort of virtual container
5520
 *****************************************************************************/
5521
MP4_Box_t *MP4_BoxGetRoot( stream_t *p_stream )
5522
0
{
5523
0
    int i_result;
5524
5525
0
    MP4_Box_t *p_vroot = MP4_BoxNew( ATOM_root );
5526
0
    if( p_vroot == NULL )
5527
0
        return NULL;
5528
5529
0
    p_vroot->i_shortsize = 1;
5530
0
    uint64_t i_size;
5531
0
    if( vlc_stream_GetSize( p_stream, &i_size ) == 0 )
5532
0
        p_vroot->i_size = i_size;
5533
5534
    /* First get the moov */
5535
0
    {
5536
0
        const uint32_t stoplist[] = { ATOM_moov, ATOM_mdat, 0 };
5537
0
        i_result = MP4_ReadBoxContainerChildren( p_stream, p_vroot, stoplist );
5538
0
    }
5539
5540
    /* mdat appeared first */
5541
0
    if( i_result && !MP4_BoxGet( p_vroot, "moov" ) )
5542
0
    {
5543
0
        bool b_seekable;
5544
0
        if( vlc_stream_Control( p_stream, STREAM_CAN_SEEK, &b_seekable ) != VLC_SUCCESS || !b_seekable )
5545
0
        {
5546
0
            msg_Err( p_stream, "no moov before mdat and the stream is not seekable" );
5547
0
            goto error;
5548
0
        }
5549
5550
        /* continue loading up to moov */
5551
0
        const uint32_t stoplist[] = { ATOM_moov, 0 };
5552
0
        i_result = MP4_ReadBoxContainerChildren( p_stream, p_vroot, stoplist );
5553
0
    }
5554
5555
0
    if( !i_result )
5556
0
        return p_vroot;
5557
5558
    /* If there is a mvex box, it means fragmented MP4, and we're done */
5559
0
    if( MP4_BoxCount( p_vroot, "moov/mvex" ) > 0 )
5560
0
    {
5561
        /* Read a bit more atoms as we might have an index between moov and moof */
5562
0
        const uint32_t stoplist[] = { ATOM_sidx, 0 };
5563
0
        const uint32_t excludelist[] = { ATOM_moof, ATOM_mdat, 0 };
5564
0
        MP4_ReadBoxContainerChildrenIndexed( p_stream, p_vroot, stoplist, excludelist, false );
5565
0
        return p_vroot;
5566
0
    }
5567
5568
0
    if( vlc_stream_Tell( p_stream ) + 8 < (uint64_t) stream_Size( p_stream ) )
5569
0
    {
5570
        /* Get the rest of the file */
5571
0
        i_result = MP4_ReadBoxContainerChildren( p_stream, p_vroot, NULL );
5572
5573
0
        if( !i_result )
5574
0
            goto error;
5575
0
    }
5576
5577
0
    MP4_Box_t *p_cmov;
5578
    /* check if there is a cmov, if so replace
5579
      compressed moov by  uncompressed one */
5580
0
    if( ( p_cmov = MP4_BoxGet( p_vroot, "moov/cmov" ) ) ||
5581
0
        ( p_cmov = MP4_BoxGet( p_vroot, "foov/cmov" ) ) )
5582
0
    {
5583
0
        MP4_Box_t *p_moov = MP4_BoxExtract( &p_vroot->p_first, p_cmov->p_father->i_type );
5584
        /* get uncompressed p_moov */
5585
0
        MP4_Box_t *p_umoov = MP4_BoxExtract( &p_cmov->p_first, ATOM_moov );
5586
        /* make p_root father of this new moov */
5587
0
        MP4_BoxAddChild( p_vroot, p_umoov );
5588
        /* Release old moov and compressed info */
5589
0
        MP4_BoxFree( p_moov );
5590
0
    }
5591
5592
0
    return p_vroot;
5593
5594
0
error:
5595
0
    MP4_BoxFree( p_vroot );
5596
0
    MP4_Seek( p_stream, 0 );
5597
0
    return NULL;
5598
0
}
5599
5600
5601
static void MP4_BoxDumpStructure_Internal( stream_t *s, const MP4_Box_t *p_box,
5602
                                           unsigned int i_level )
5603
0
{
5604
0
    const MP4_Box_t *p_child;
5605
0
    uint32_t i_displayedtype = p_box->i_type;
5606
0
    if( ! MP4_BOX_TYPE_ASCII() ) ((char*)&i_displayedtype)[0] = 'c';
5607
5608
0
    if( !i_level )
5609
0
    {
5610
0
        msg_Dbg( s, "dumping root Box \"%4.4s\"",
5611
0
                          (char*)&i_displayedtype );
5612
0
    }
5613
0
    else
5614
0
    {
5615
0
        char str[512];
5616
0
        if( i_level >= (sizeof(str) - 1)/4 )
5617
0
            return;
5618
5619
0
        memset( str, ' ', sizeof(str) );
5620
0
        for( unsigned i = 0; i < i_level; i++ )
5621
0
        {
5622
0
            str[i*4] = '|';
5623
0
        }
5624
5625
0
        snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
5626
0
                  "+ %4.4s size %"PRIu64" offset %"PRIu64"%s",
5627
0
                  (char *)&i_displayedtype, p_box->i_size, p_box->i_pos,
5628
0
                  p_box->e_flags & BOX_FLAG_INCOMPLETE ? " (\?\?\?\?)" : "" );
5629
0
        msg_Dbg( s, "%s", str );
5630
0
    }
5631
0
    p_child = p_box->p_first;
5632
0
    while( p_child )
5633
0
    {
5634
0
        MP4_BoxDumpStructure_Internal( s, p_child, i_level + 1 );
5635
0
        p_child = p_child->p_next;
5636
0
    }
5637
0
}
5638
5639
void MP4_BoxDumpStructure( stream_t *s, const MP4_Box_t *p_box )
5640
0
{
5641
0
    MP4_BoxDumpStructure_Internal( s, p_box, 0 );
5642
0
}
5643
5644
5645
/*****************************************************************************
5646
 *****************************************************************************
5647
 **
5648
 **  High level methods to access an MP4 file
5649
 **
5650
 *****************************************************************************
5651
 *****************************************************************************/
5652
static bool get_token( const char **ppsz_path, char **ppsz_token, int *pi_number )
5653
0
{
5654
0
    size_t i_len ;
5655
0
    if( !*ppsz_path[0] )
5656
0
    {
5657
0
        *ppsz_token = NULL;
5658
0
        *pi_number = 0;
5659
0
        return true;
5660
0
    }
5661
0
    i_len = strcspn( *ppsz_path, "/[" );
5662
0
    if( !i_len && **ppsz_path == '/' )
5663
0
    {
5664
0
        i_len = 1;
5665
0
    }
5666
0
    *ppsz_token = strndup( *ppsz_path, i_len );
5667
0
    if( unlikely(!*ppsz_token) )
5668
0
        return false;
5669
5670
0
    *ppsz_path += i_len;
5671
5672
    /* Parse the token number token[n] */
5673
0
    if( **ppsz_path == '[' )
5674
0
    {
5675
0
        (*ppsz_path)++;
5676
0
        *pi_number = strtol( *ppsz_path, NULL, 10 );
5677
0
        while( **ppsz_path && **ppsz_path != ']' )
5678
0
        {
5679
0
            (*ppsz_path)++;
5680
0
        }
5681
0
        if( **ppsz_path == ']' )
5682
0
        {
5683
0
            (*ppsz_path)++;
5684
0
        }
5685
0
    }
5686
0
    else
5687
0
    {
5688
0
        *pi_number = 0;
5689
0
    }
5690
5691
    /* Forward to start of next token */
5692
0
    while( **ppsz_path == '/' )
5693
0
    {
5694
0
        (*ppsz_path)++;
5695
0
    }
5696
5697
0
    return true;
5698
0
}
5699
5700
static void MP4_BoxGet_Path( const MP4_Box_t **pp_result, const MP4_Box_t *p_box,
5701
                             const char *psz_path)
5702
0
{
5703
0
    char *psz_token = NULL;
5704
5705
0
    if( !p_box )
5706
0
    {
5707
0
        *pp_result = NULL;
5708
0
        return;
5709
0
    }
5710
5711
0
    assert( psz_path && psz_path[0] );
5712
5713
//    fprintf( stderr, "path:'%s'\n", psz_path );
5714
0
    for( ; ; )
5715
0
    {
5716
0
        int i_number;
5717
5718
0
        if( !get_token( &psz_path, &psz_token, &i_number ) )
5719
0
            goto error_box;
5720
//        fprintf( stderr, "path:'%s', token:'%s' n:%d\n",
5721
//                 psz_path,psz_token,i_number );
5722
0
        if( !psz_token )
5723
0
        {
5724
0
            *pp_result = p_box;
5725
0
            return;
5726
0
        }
5727
0
        else
5728
0
        if( !strcmp( psz_token, "/" ) )
5729
0
        {
5730
            /* Find root box */
5731
0
            while( p_box && p_box->i_type != ATOM_root )
5732
0
            {
5733
0
                p_box = p_box->p_father;
5734
0
            }
5735
0
            if( !p_box )
5736
0
            {
5737
0
                goto error_box;
5738
0
            }
5739
0
        }
5740
0
        else
5741
0
        if( !strcmp( psz_token, "." ) )
5742
0
        {
5743
            /* Do nothing */
5744
0
        }
5745
0
        else
5746
0
        if( !strcmp( psz_token, ".." ) )
5747
0
        {
5748
0
            p_box = p_box->p_father;
5749
0
            if( !p_box )
5750
0
            {
5751
0
                goto error_box;
5752
0
            }
5753
0
        }
5754
0
        else
5755
0
        if( strlen( psz_token ) == 4 )
5756
0
        {
5757
0
            uint32_t i_fourcc;
5758
0
            i_fourcc = VLC_FOURCC( psz_token[0], psz_token[1],
5759
0
                                   psz_token[2], psz_token[3] );
5760
0
            p_box = p_box->p_first;
5761
0
            for( ; ; )
5762
0
            {
5763
0
                if( !p_box )
5764
0
                {
5765
0
                    goto error_box;
5766
0
                }
5767
0
                if( p_box->i_type == i_fourcc )
5768
0
                {
5769
0
                    if( !i_number )
5770
0
                    {
5771
0
                        break;
5772
0
                    }
5773
0
                    i_number--;
5774
0
                }
5775
0
                p_box = p_box->p_next;
5776
0
            }
5777
0
        }
5778
0
        else
5779
0
        if( *psz_token == '\0' )
5780
0
        {
5781
0
            p_box = p_box->p_first;
5782
0
            for( ; ; )
5783
0
            {
5784
0
                if( !p_box )
5785
0
                {
5786
0
                    goto error_box;
5787
0
                }
5788
0
                if( !i_number )
5789
0
                {
5790
0
                    break;
5791
0
                }
5792
0
                i_number--;
5793
0
                p_box = p_box->p_next;
5794
0
            }
5795
0
        }
5796
0
        else
5797
0
        {
5798
//            fprintf( stderr, "Argg malformed token \"%s\"",psz_token );
5799
0
            goto error_box;
5800
0
        }
5801
5802
0
        free( psz_token );
5803
0
    }
5804
5805
0
    return;
5806
5807
0
error_box:
5808
0
    free( psz_token );
5809
0
    *pp_result = NULL;
5810
0
    return;
5811
0
}
5812
5813
static void MP4_BoxGet_Internal( const MP4_Box_t **pp_result, const MP4_Box_t *p_box,
5814
                                 const char *psz_fmt, va_list args)
5815
0
{
5816
0
    char *psz_path;
5817
5818
0
    if( !p_box )
5819
0
    {
5820
0
        *pp_result = NULL;
5821
0
        return;
5822
0
    }
5823
5824
0
    if( vasprintf( &psz_path, psz_fmt, args ) == -1 )
5825
0
        psz_path = NULL;
5826
5827
0
    if( !psz_path || !psz_path[0] )
5828
0
    {
5829
0
        free( psz_path );
5830
0
        *pp_result = NULL;
5831
0
        return;
5832
0
    }
5833
5834
0
    MP4_BoxGet_Path( pp_result, p_box, psz_path );
5835
5836
0
    free( psz_path );
5837
0
}
5838
5839
/*****************************************************************************
5840
 * MP4_BoxGet: find a box given a path relative to p_box
5841
 *****************************************************************************
5842
 * Path Format: . .. / as usual
5843
 *              [number] to specifie box number ex: trak[12]
5844
 *
5845
 * ex: /moov/trak[12]
5846
 *     ../mdia
5847
 *****************************************************************************/
5848
MP4_Box_t *MP4_BoxGetVa( const MP4_Box_t *p_box, const char *psz_fmt, ... )
5849
0
{
5850
0
    va_list args;
5851
0
    const MP4_Box_t *p_result;
5852
5853
0
    va_start( args, psz_fmt );
5854
0
    MP4_BoxGet_Internal( &p_result, p_box, psz_fmt, args );
5855
0
    va_end( args );
5856
5857
0
    return( (MP4_Box_t *) p_result );
5858
0
}
5859
5860
MP4_Box_t *MP4_BoxGet( const MP4_Box_t *p_box, const char *psz_fmt )
5861
0
{
5862
0
    const MP4_Box_t *p_result;
5863
5864
0
    MP4_BoxGet_Path( &p_result, p_box, psz_fmt );
5865
5866
0
    return( (MP4_Box_t *) p_result );
5867
0
}
5868
5869
/*****************************************************************************
5870
 * MP4_BoxCount: count box given a path relative to p_box
5871
 *****************************************************************************
5872
 * Path Format: . .. / as usual
5873
 *              [number] to specifie box number ex: trak[12]
5874
 *
5875
 * ex: /moov/trak[12]
5876
 *     ../mdia
5877
 *****************************************************************************/
5878
unsigned MP4_BoxCountVa( const MP4_Box_t *p_box, const char *psz_fmt, ... )
5879
0
{
5880
0
    va_list args;
5881
0
    unsigned i_count;
5882
0
    const MP4_Box_t *p_result, *p_next;
5883
5884
0
    va_start( args, psz_fmt );
5885
0
    MP4_BoxGet_Internal( &p_result, p_box, psz_fmt, args );
5886
0
    va_end( args );
5887
0
    if( !p_result )
5888
0
    {
5889
0
        return( 0 );
5890
0
    }
5891
5892
0
    i_count = 1;
5893
0
    for( p_next = p_result->p_next; p_next != NULL; p_next = p_next->p_next)
5894
0
    {
5895
0
        if( p_next->i_type == p_result->i_type)
5896
0
        {
5897
0
            i_count++;
5898
0
        }
5899
0
    }
5900
0
    return( i_count );
5901
0
}
5902
5903
unsigned MP4_BoxCount( const MP4_Box_t *p_box, const char *psz_fmt )
5904
0
{
5905
0
    unsigned i_count;
5906
0
    const MP4_Box_t *p_result, *p_next;
5907
5908
0
    MP4_BoxGet_Path( &p_result, p_box, psz_fmt );
5909
0
    if( !p_result )
5910
0
    {
5911
0
        return( 0 );
5912
0
    }
5913
5914
0
    i_count = 1;
5915
0
    for( p_next = p_result->p_next; p_next != NULL; p_next = p_next->p_next)
5916
0
    {
5917
0
        if( p_next->i_type == p_result->i_type)
5918
0
        {
5919
0
            i_count++;
5920
0
        }
5921
0
    }
5922
0
    return( i_count );
5923
0
}