libmp4.c 80.3 KB
Newer Older
1
2
3
4
/*****************************************************************************
 * libmp4.c : LibMP4 library for mp4 module for vlc
 *****************************************************************************
 * Copyright (C) 2001 VideoLAN
5
 * $Id: libmp4.c,v 1.41 2004/01/06 01:41:10 jlj Exp $
6
7
 *
 * Author: Laurent Aimar <fenrir@via.ecp.fr>
8
 *
9
10
11
12
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
13
 *
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */

#include <vlc/vlc.h>
#include <vlc/input.h>

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

32
#include "libmp4.h"
33
#include "drms.h"
34
35

/*****************************************************************************
36
37
 * Here are defined some macro to make life simpler but before using it
 *  *look* at the code.
38
39
40
41
42
 *
 *****************************************************************************/
#define MP4_BOX_HEADERSIZE( p_box ) \
  ( 8 + ( p_box->i_shortsize == 1 ? 8 : 0 ) \
      + ( p_box->i_type == FOURCC_uuid ? 16 : 0 ) )
43

44
45
46
47
48
49
50
51
52
53
54
#define MP4_GET1BYTE( dst ) \
    dst = *p_peek; p_peek++; i_read--

#define MP4_GET2BYTES( dst ) \
    dst = GetWBE( p_peek ); p_peek += 2; i_read -= 2

#define MP4_GET3BYTES( dst ) \
    dst = Get24bBE( p_peek ); p_peek += 3; i_read -= 3

#define MP4_GET4BYTES( dst ) \
    dst = GetDWBE( p_peek ); p_peek += 4; i_read -= 4
55

56
#define MP4_GETFOURCC( dst ) \
57
58
    dst = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] ); \
    p_peek += 4; i_read -= 4
59
60
61

#define MP4_GET8BYTES( dst ) \
    dst = GetQWBE( p_peek ); p_peek += 8; i_read -= 8
62

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

67
68
69
70
71
72
73
74
75
76
77
78
79
#define MP4_GETSTRINGZ( p_str ) \
    if( ( i_read > 0 )&&(p_peek[0] ) ) \
    { \
        p_str = calloc( sizeof( char ), __MIN( strlen( p_peek ), i_read )+1);\
        memcpy( p_str, p_peek, __MIN( strlen( p_peek ), i_read ) ); \
        p_str[__MIN( strlen( p_peek ), i_read )] = 0; \
        p_peek += strlen( p_str ) + 1; \
        i_read -= strlen( p_str ) + 1; \
    } \
    else \
    { \
        p_str = NULL; \
    }
80

81
82

#define MP4_READBOX_ENTER( MP4_Box_data_TYPE_t ) \
83
84
    int64_t  i_read = p_box->i_size; \
    uint8_t *p_peek, *p_buff; \
85
86
87
88
89
    i_read = p_box->i_size; \
    if( !( p_peek = p_buff = malloc( i_read ) ) ) \
    { \
        return( 0 ); \
    } \
90
    if( MP4_ReadStream( p_stream, p_peek, i_read ) )\
91
92
93
94
95
96
97
98
99
100
    { \
        free( p_buff ); \
        return( 0 ); \
    } \
    p_peek += MP4_BOX_HEADERSIZE( p_box ); \
    i_read -= MP4_BOX_HEADERSIZE( p_box ); \
    if( !( p_box->data.p_data = malloc( sizeof( MP4_Box_data_TYPE_t ) ) ) ) \
    { \
      free( p_buff ); \
      return( 0 ); \
101
102
    }

103
104
105
106
#define MP4_READBOX_EXIT( i_code ) \
    free( p_buff ); \
    if( i_read < 0 ) \
    { \
gbazin's avatar
   
gbazin committed
107
        msg_Warn( p_stream->p_input, "Not enough data" ); \
108
109
110
111
112
113
    } \
    return( i_code )

#define FREE( p ) \
    if( p ) {free( p ); p = NULL; }

114
115


116
/* Some assumptions:
117
118
        * The input method HAVE to be seekable

119
120
*/

Laurent Aimar's avatar
Laurent Aimar committed
121
static uint32_t Get24bBE( uint8_t *p )
122
{
Laurent Aimar's avatar
Laurent Aimar committed
123
    return( ( p[0] <<16 ) + ( p[1] <<8 ) + p[2] );
124
125
}

126
static void GetUUID( UUID_t *p_uuid, uint8_t *p_buff )
127
{
Laurent Aimar's avatar
Laurent Aimar committed
128
    memcpy( p_uuid, p_buff, 16 );
129
130
}

131
static void CreateUUID( UUID_t *p_uuid, uint32_t i_fourcc )
132
{
133
    /* made by 0xXXXXXXXX-0011-0010-8000-00aa00389b71
134
135
136
137
138
139
            where XXXXXXXX is the fourcc */
    /* FIXME implement this */
}

/* some functions for mp4 encoding of variables */

Laurent Aimar's avatar
Laurent Aimar committed
140
static void MP4_ConvertDate2Str( char *psz, uint64_t i_date )
141
142
143
144
145
146
{
    int i_day;
    int i_hour;
    int i_min;
    int i_sec;

Laurent Aimar's avatar
Laurent Aimar committed
147
    /* date begin at 1 jan 1904 */
gbazin's avatar
gbazin committed
148
    i_date += ((1904U * 365) + 17) * 24 * 60 * 60;
Laurent Aimar's avatar
Laurent Aimar committed
149

150
151
152
153
154
155
156
157
    i_day = i_date / ( 60*60*24);
    i_hour = ( i_date /( 60*60 ) ) % 60;
    i_min  = ( i_date / 60 ) % 60;
    i_sec =  i_date % 60;
    sprintf( psz, "%dd-%2.2dh:%2.2dm:%2.2ds",
                   i_day, i_hour, i_min, i_sec );
}

Laurent Aimar's avatar
Laurent Aimar committed
158
159
160
161
/*****************************************************************************
 * Some prototypes.
 *****************************************************************************/
static MP4_Box_t *MP4_ReadBox( MP4_Stream_t *p_stream, MP4_Box_t *p_father );
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193

/*****************************************************************************
 * Some basic functions to manipulate MP4_Stream_t, an abstraction o p_input
 *  in the way that you can read from a memory buffer or from an input
 *
 *****************************************************************************/

/****  ------- First some function to make abstract from input --------  */

/****************************************************************************
 * MP4_InputStream create an stram with an input
 *
 ****************************************************************************/
MP4_Stream_t *MP4_InputStream( input_thread_t *p_input )
{
    MP4_Stream_t *p_stream;

    if( !( p_stream = malloc( sizeof( MP4_Stream_t ) ) ) )
    {
        return( NULL );
    }
    p_stream->b_memory = 0;
    p_stream->p_input = p_input;
    p_stream->i_start = 0;
    p_stream->i_stop = 0;
    p_stream->p_buffer = NULL;
    return( p_stream );
}


/****************************************************************************
 * MP4_MemoryStream create a memory stream
194
 * if p_buffer == NULL, will allocate a buffer of i_size, else
195
196
197
198
 *     it uses p_buffer XXX you have to unallocate it yourself !
 *
 ****************************************************************************/
MP4_Stream_t *MP4_MemoryStream( input_thread_t *p_input,
199
                                int i_size, uint8_t *p_buffer )
200
201
202
203
204
205
206
207
208
209
210
{
    MP4_Stream_t *p_stream;

    if( !( p_stream = malloc( sizeof( MP4_Stream_t ) ) ) )
    {
        return( NULL );
    }
    p_stream->b_memory = 1;
    p_stream->p_input = p_input;
    p_stream->i_start = 0;
    p_stream->i_stop = i_size;
211
    if( !p_buffer )
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
    {
        if( !( p_stream->p_buffer = malloc( i_size ) ) )
        {
            free( p_stream );
            return( NULL );
        }
    }
    else
    {
        p_stream->p_buffer = p_buffer;
    }

    return( p_stream );
}
/****************************************************************************
 * MP4_ReadStream read from a MP4_Stream_t
 *
 ****************************************************************************/
230
int MP4_ReadStream( MP4_Stream_t *p_stream, uint8_t *p_buff, int i_size )
231
232
233
234
235
{
    if( p_stream->b_memory )
    {
        if( i_size > p_stream->i_stop - p_stream->i_start )
        {
236
            return( VLC_EGENERIC );
237
        }
238
        memcpy( p_buff,
239
240
241
                p_stream->p_buffer + p_stream->i_start,
                i_size );
        p_stream->i_start += i_size;
242
        return( VLC_SUCCESS );
243
244
245
    }
    else
    {
Laurent Aimar's avatar
Laurent Aimar committed
246
        return( stream_Read( p_stream->p_input->s, p_buff, i_size ) < i_size ? VLC_EGENERIC : VLC_SUCCESS);
247
248
249
250
251
252
253
    }
}

/****************************************************************************
 * MP4_PeekStream peek from a MP4_Stream_t
 *
 ****************************************************************************/
254
int MP4_PeekStream( MP4_Stream_t *p_stream, uint8_t **pp_peek, int i_size )
255
256
257
258
259
260
261
262
263
{
    if( p_stream->b_memory )
    {
        *pp_peek = p_stream->p_buffer + p_stream->i_start;

        return( __MIN(i_size,p_stream->i_stop - p_stream->i_start ));
    }
    else
    {
264
265
266
267

        if( p_stream->p_input->stream.p_selected_area->i_size > 0 )
        {
            int64_t i_max =
Laurent Aimar's avatar
Laurent Aimar committed
268
                p_stream->p_input->stream.p_selected_area->i_size - stream_Tell( p_stream->p_input->s );
269
270
271
272
273
            if( i_size > i_max )
            {
                i_size = i_max;
            }
        }
Laurent Aimar's avatar
Laurent Aimar committed
274
        return( stream_Peek( p_stream->p_input->s, pp_peek, i_size ) );
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
    }
}

/****************************************************************************
 * MP4_TellStream give absolute position in the stream
 * XXX for a memory stream give position from begining of the buffer
 ****************************************************************************/
off_t MP4_TellStream( MP4_Stream_t *p_stream )
{
    if( p_stream->b_memory )
    {
        return( p_stream->i_start );
    }
    else
    {
Laurent Aimar's avatar
Laurent Aimar committed
290
        return( stream_Tell( p_stream->p_input->s ) );
291
292
293
294
295
296
297
298
299
300
301
302
303
304
    }
}

/****************************************************************************
 * MP4_SeekStream seek in a MP4_Stream_t
 *
 ****************************************************************************/
int MP4_SeekStream( MP4_Stream_t *p_stream, off_t i_pos)
{
    if( p_stream->b_memory )
    {
        if( i_pos < p_stream->i_stop )
        {
            p_stream->i_start = i_pos;
305
            return( VLC_SUCCESS );
306
307
308
        }
        else
        {
309
            return( VLC_EGENERIC );
310
311
312
313
        }
    }
    else
    {
Laurent Aimar's avatar
Laurent Aimar committed
314
        return( stream_Seek( p_stream->p_input->s, (int64_t)i_pos ) );
315
316
317
318
319
320
    }
}



/*****************************************************************************
321
 * MP4_ReadBoxCommon : Load only common parameters for all boxes
322
 *****************************************************************************
323
 * p_box need to be an already allocated MP4_Box_t, and all data
324
325
326
327
 *  will only be peek not read
 *
 * RETURN : 0 if it fail, 1 otherwise
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
328
static int MP4_ReadBoxCommon( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
329
{
330
    int      i_read;
331
    uint8_t  *p_peek;
332

333
334
335
336
337
338
339
340
341
342
343
    if( ( ( i_read = MP4_PeekStream( p_stream, &p_peek, 32 ) ) < 8 ) )
    {
        return( 0 );
    }
    p_box->i_pos = MP4_TellStream( p_stream );

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

345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
    MP4_GET4BYTES( p_box->i_shortsize );
    MP4_GETFOURCC( p_box->i_type );

    /* Now special case */

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

361
362
363
364
365
366
367
368
369
370
371
372
373
    if( p_box->i_type == FOURCC_uuid )
    {
        /* get extented type on 16 bytes */
        GetUUID( &p_box->i_uuid, p_peek );
        p_peek += 16; i_read -= 16;
    }
    else
    {
        CreateUUID( &p_box->i_uuid, p_box->i_type );
    }
#ifdef MP4_VERBOSE
    if( p_box->i_size )
    {
Laurent Aimar's avatar
Laurent Aimar committed
374
        msg_Dbg( p_stream->p_input, "Found Box: %4.4s size "I64Fd,
375
                 (char*)&p_box->i_type,
Laurent Aimar's avatar
Laurent Aimar committed
376
                 p_box->i_size );
377
378
379
    }
#endif

380
    return( 1 );
381
382
383
384
}


/*****************************************************************************
385
 * MP4_NextBox : Go to the next box
386
387
388
 *****************************************************************************
 * if p_box == NULL, go to the next box in witch we are( at the begining ).
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
389
static int MP4_NextBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
{
    MP4_Box_t box;

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

    if( !p_box->i_size )
    {
        return( 2 ); /* Box with infinite size */
    }

    if( p_box->p_father )
    {
        /* check if it's within p-father */
407
        if( p_box->i_size + p_box->i_pos >=
408
409
410
411
412
                    p_box->p_father->i_size + p_box->p_father->i_pos )
        {
            return( 0 ); /* out of bound */
        }
    }
413
    return( MP4_SeekStream( p_stream, p_box->i_size + p_box->i_pos ) ? 0 : 1 );
414
415
416
}

/*****************************************************************************
417
 * For all known box a loader is given,
418
419
 *  XXX: all common struct have to be already read by MP4_ReadBoxCommon
 *       after called one of theses functions, file position is unknown
420
 *       you need to call MP4_GotoBox to go where you want
421
 *****************************************************************************/
422
static int MP4_ReadBoxContainerRaw( MP4_Stream_t *p_stream, MP4_Box_t *p_container )
423
424
{
    MP4_Box_t *p_box;
425

426
    if( MP4_TellStream( p_stream ) + 8 >
427
                 (off_t)(p_container->i_pos + p_container->i_size) )
428
429
430
431
    {
        /* there is no box to load */
        return( 0 );
    }
432

433
434
    do
    {
Laurent Aimar's avatar
Laurent Aimar committed
435
        if( ( p_box = MP4_ReadBox( p_stream, p_container ) ) == NULL )
436
        {
Laurent Aimar's avatar
Laurent Aimar committed
437
438
439
440
441
442
            break;
        }
        /* chain this box with the father and the other at same level */
        if( !p_container->p_first )
        {
            p_container->p_first = p_box;
443
444
445
        }
        else
        {
Laurent Aimar's avatar
Laurent Aimar committed
446
            p_container->p_last->p_next = p_box;
447
        }
Laurent Aimar's avatar
Laurent Aimar committed
448
449
        p_container->p_last = p_box;
    } while( MP4_NextBox( p_stream, p_box ) == 1 );
450

451
452
453
454
    return( 1 );
}


455
static int MP4_ReadBoxContainer( MP4_Stream_t *p_stream, MP4_Box_t *p_container )
456
{
457
    if( p_container->i_size <= (size_t)MP4_BOX_HEADERSIZE(p_container ) + 8 )
458
459
460
461
    {
        /* container is empty, 8 stand for the first header in this box */
        return( 1 );
    }
462

463
    /* enter box */
464
    MP4_SeekStream( p_stream, p_container->i_pos + MP4_BOX_HEADERSIZE( p_container ) );
465
466
467
468

    return( MP4_ReadBoxContainerRaw( p_stream, p_container ) );
}

469
static void MP4_FreeBox_Common( MP4_Box_t *p_box )
470
471
472
473
{
    /* Up to now do nothing */
}

474
static int MP4_ReadBoxSkip( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
475
{
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
    /* XXX sometime moov is hiden in a free box */
    if( p_box->p_father && p_box->p_father->i_type == VLC_FOURCC( 'r', 'o', 'o', 't' )&&
        p_box->i_type == FOURCC_free )
    {
        uint8_t *p_peek;
        int     i_read;
        vlc_fourcc_t i_fcc;

        i_read  = MP4_PeekStream( p_stream, &p_peek, 44 );

        p_peek += MP4_BOX_HEADERSIZE( p_box ) + 4;
        i_read -= MP4_BOX_HEADERSIZE( p_box ) + 4;

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

            if( i_fcc == FOURCC_cmov || i_fcc == FOURCC_mvhd )
            {
                msg_Warn( p_stream->p_input, "Detected moov hidden in a free box ..." );

                p_box->i_type = FOURCC_foov;
                return MP4_ReadBoxContainer( p_stream, p_box );
            }
        }
    }
502
503
    /* Nothing to do */
#ifdef MP4_VERBOSE
504
505
    msg_Dbg( p_stream->p_input, "Skip box: \"%4.4s\"",
            (char*)&p_box->i_type );
506
507
508
509
#endif
    return( 1 );
}

510
static int MP4_ReadBox_ftyp( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
511
512
{
    MP4_READBOX_ENTER( MP4_Box_data_ftyp_t );
513

514
515
    MP4_GETFOURCC( p_box->data.p_ftyp->i_major_brand );
    MP4_GET4BYTES( p_box->data.p_ftyp->i_minor_version );
516

517
518
    if( ( p_box->data.p_ftyp->i_compatible_brands_count = i_read / 4 ) )
    {
519
        unsigned int i;
520
        p_box->data.p_ftyp->i_compatible_brands =
521
            calloc( p_box->data.p_ftyp->i_compatible_brands_count, sizeof(uint32_t));
522
523
524
525
526
527
528
529
530
531
532
533
534
535

        for( i =0; i < p_box->data.p_ftyp->i_compatible_brands_count; i++ )
        {
            MP4_GETFOURCC( p_box->data.p_ftyp->i_compatible_brands[i] );
        }
    }
    else
    {
        p_box->data.p_ftyp->i_compatible_brands = NULL;
    }

    MP4_READBOX_EXIT( 1 );
}

536
static void MP4_FreeBox_ftyp( MP4_Box_t *p_box )
537
538
539
540
541
{
    FREE( p_box->data.p_ftyp->i_compatible_brands );
}


542
static int MP4_ReadBox_mvhd(  MP4_Stream_t *p_stream, MP4_Box_t *p_box )
543
{
544
    unsigned int i;
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
#ifdef MP4_VERBOSE
    char s_creation_time[128];
    char s_modification_time[128];
    char s_duration[128];
#endif
    MP4_READBOX_ENTER( MP4_Box_data_mvhd_t );

    MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );

    if( p_box->data.p_mvhd->i_version )
    {
        MP4_GET8BYTES( p_box->data.p_mvhd->i_creation_time );
        MP4_GET8BYTES( p_box->data.p_mvhd->i_modification_time );
        MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
        MP4_GET8BYTES( p_box->data.p_mvhd->i_duration );
    }
    else
    {
        MP4_GET4BYTES( p_box->data.p_mvhd->i_creation_time );
        MP4_GET4BYTES( p_box->data.p_mvhd->i_modification_time );
        MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
        MP4_GET4BYTES( p_box->data.p_mvhd->i_duration );
    }
568
569
    MP4_GET4BYTES( p_box->data.p_mvhd->i_rate );
    MP4_GET2BYTES( p_box->data.p_mvhd->i_volume );
570
571
    MP4_GET2BYTES( p_box->data.p_mvhd->i_reserved1 );

572

573
574
575
576
577
578
579
580
581
582
583
584
    for( i = 0; i < 2; i++ )
    {
        MP4_GET4BYTES( p_box->data.p_mvhd->i_reserved2[i] );
    }
    for( i = 0; i < 9; i++ )
    {
        MP4_GET4BYTES( p_box->data.p_mvhd->i_matrix[i] );
    }
    for( i = 0; i < 6; i++ )
    {
        MP4_GET4BYTES( p_box->data.p_mvhd->i_predefined[i] );
    }
585

586
    MP4_GET4BYTES( p_box->data.p_mvhd->i_next_track_id );
587
588


589
590
#ifdef MP4_VERBOSE
    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
591
    MP4_ConvertDate2Str( s_modification_time,
592
593
594
                         p_box->data.p_mvhd->i_modification_time );
    if( p_box->data.p_mvhd->i_rate )
    {
595
        MP4_ConvertDate2Str( s_duration,
596
597
598
599
600
                 p_box->data.p_mvhd->i_duration / p_box->data.p_mvhd->i_rate );
    }
    else
    {
        s_duration[0] = 0;
601
    }
602
603
604
    msg_Dbg( p_stream->p_input, "Read Box: \"mvhd\" creation %s modification %s time scale %d duration %s rate %f volume %f next track id %d",
                  s_creation_time,
                  s_modification_time,
605
                  (uint32_t)p_box->data.p_mvhd->i_timescale,
606
607
608
                  s_duration,
                  (float)p_box->data.p_mvhd->i_rate / (1<<16 ),
                  (float)p_box->data.p_mvhd->i_volume / 256 ,
609
                  (uint32_t)p_box->data.p_mvhd->i_next_track_id );
610
611
612
613
#endif
    MP4_READBOX_EXIT( 1 );
}

614
static int MP4_ReadBox_tkhd(  MP4_Stream_t *p_stream, MP4_Box_t *p_box )
615
{
616
    unsigned int i;
617
618
619
620
621
622
#ifdef MP4_VERBOSE
    char s_creation_time[128];
    char s_modification_time[128];
    char s_duration[128];
#endif
    MP4_READBOX_ENTER( MP4_Box_data_tkhd_t );
623

624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
    MP4_GETVERSIONFLAGS( p_box->data.p_tkhd );

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

643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
    for( i = 0; i < 2; i++ )
    {
        MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved2[i] );
    }
    MP4_GET2BYTES( p_box->data.p_tkhd->i_layer );
    MP4_GET2BYTES( p_box->data.p_tkhd->i_predefined );
    MP4_GET2BYTES( p_box->data.p_tkhd->i_volume );
    MP4_GET2BYTES( p_box->data.p_tkhd->i_reserved3 );

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

659
660
661
662
#ifdef MP4_VERBOSE
    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
    MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mvhd->i_modification_time );
    MP4_ConvertDate2Str( s_duration, p_box->data.p_mvhd->i_duration );
663

664
665
666
667
668
669
670
671
672
673
674
675
676
677
    msg_Dbg( p_stream->p_input, "Read Box: \"tkhd\" creation %s modification %s duration %s track ID %d layer %d volume %f width %f height %f",
                  s_creation_time,
                  s_modification_time,
                  s_duration,
                  p_box->data.p_tkhd->i_track_ID,
                  p_box->data.p_tkhd->i_layer,
                  (float)p_box->data.p_tkhd->i_volume / 256 ,
                  (float)p_box->data.p_tkhd->i_width / 65536,
                  (float)p_box->data.p_tkhd->i_height / 65536 );
#endif
    MP4_READBOX_EXIT( 1 );
}


678
static int MP4_ReadBox_mdhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
679
{
680
    unsigned int i;
681
    uint16_t i_language;
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
#ifdef MP4_VERBOSE
    char s_creation_time[128];
    char s_modification_time[128];
    char s_duration[128];
#endif
    MP4_READBOX_ENTER( MP4_Box_data_mdhd_t );

    MP4_GETVERSIONFLAGS( p_box->data.p_mdhd );

    if( p_box->data.p_mdhd->i_version )
    {
        MP4_GET8BYTES( p_box->data.p_mdhd->i_creation_time );
        MP4_GET8BYTES( p_box->data.p_mdhd->i_modification_time );
        MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
        MP4_GET8BYTES( p_box->data.p_mdhd->i_duration );
    }
    else
    {
        MP4_GET4BYTES( p_box->data.p_mdhd->i_creation_time );
        MP4_GET4BYTES( p_box->data.p_mdhd->i_modification_time );
        MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
        MP4_GET4BYTES( p_box->data.p_mdhd->i_duration );
    }
705
    i_language = GetWBE( p_peek );
706
707
    for( i = 0; i < 3; i++ )
    {
708
        p_box->data.p_mdhd->i_language[i] =
709
710
711
712
                    ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
    }

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

714
715
716
717
718
719
720
#ifdef MP4_VERBOSE
    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mdhd->i_creation_time );
    MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mdhd->i_modification_time );
    MP4_ConvertDate2Str( s_duration, p_box->data.p_mdhd->i_duration );
    msg_Dbg( p_stream->p_input, "Read Box: \"mdhd\" creation %s modification %s time scale %d duration %s language %c%c%c",
                  s_creation_time,
                  s_modification_time,
721
                  (uint32_t)p_box->data.p_mdhd->i_timescale,
722
723
724
725
726
727
728
729
730
                  s_duration,
                  p_box->data.p_mdhd->i_language[0],
                  p_box->data.p_mdhd->i_language[1],
                  p_box->data.p_mdhd->i_language[2] );
#endif
    MP4_READBOX_EXIT( 1 );
}


731
static int MP4_ReadBox_hdlr( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
732
{
733
    MP4_READBOX_ENTER( MP4_Box_data_hdlr_t );
734
735

    MP4_GETVERSIONFLAGS( p_box->data.p_hdlr );
736

737
738
739
740
741
742
743
    MP4_GET4BYTES( p_box->data.p_hdlr->i_predefined );
    MP4_GETFOURCC( p_box->data.p_hdlr->i_handler_type );

    p_box->data.p_hdlr->psz_name = calloc( sizeof( char ), i_read + 1 );
    memcpy( p_box->data.p_hdlr->psz_name, p_peek, i_read );

#ifdef MP4_VERBOSE
744
745
    msg_Dbg( p_stream->p_input, "Read Box: \"hdlr\" hanler type %4.4s name %s",
                       (char*)&p_box->data.p_hdlr->i_handler_type,
746
747
748
749
750
751
                       p_box->data.p_hdlr->psz_name );

#endif
    MP4_READBOX_EXIT( 1 );
}

752
static void MP4_FreeBox_hdlr( MP4_Box_t *p_box )
753
754
755
756
{
    FREE( p_box->data.p_hdlr->psz_name );
}

757
static int MP4_ReadBox_vmhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
758
{
759
    unsigned int i;
760
761

    MP4_READBOX_ENTER( MP4_Box_data_vmhd_t );
762
763

    MP4_GETVERSIONFLAGS( p_box->data.p_vmhd );
764

765
766
767
768
769
    MP4_GET2BYTES( p_box->data.p_vmhd->i_graphics_mode );
    for( i = 0; i < 3; i++ )
    {
        MP4_GET2BYTES( p_box->data.p_vmhd->i_opcolor[i] );
    }
770

771
772
773
774
775
776
777
778
779
780
#ifdef MP4_VERBOSE
    msg_Dbg( p_stream->p_input, "Read Box: \"vmhd\" graphics-mode %d opcolor (%d, %d, %d)",
                      p_box->data.p_vmhd->i_graphics_mode,
                      p_box->data.p_vmhd->i_opcolor[0],
                      p_box->data.p_vmhd->i_opcolor[1],
                      p_box->data.p_vmhd->i_opcolor[2] );
#endif
    MP4_READBOX_EXIT( 1 );
}

781
static int MP4_ReadBox_smhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
782
{
783
    MP4_READBOX_ENTER( MP4_Box_data_smhd_t );
784
785
786
787
788
789
790
791

    MP4_GETVERSIONFLAGS( p_box->data.p_smhd );



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

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

793
794
795
796
797
798
799
800
#ifdef MP4_VERBOSE
    msg_Dbg( p_stream->p_input, "Read Box: \"smhd\" balance %f",
                      (float)p_box->data.p_smhd->i_balance / 256 );
#endif
    MP4_READBOX_EXIT( 1 );
}


801
static int MP4_ReadBox_hmhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
802
{
803
    MP4_READBOX_ENTER( MP4_Box_data_hmhd_t );
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824

    MP4_GETVERSIONFLAGS( p_box->data.p_hmhd );

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

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

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

#ifdef MP4_VERBOSE
    msg_Dbg( p_stream->p_input, "Read Box: \"hmhd\" maxPDU-size %d avgPDU-size %d max-bitrate %d avg-bitrate %d",
                      p_box->data.p_hmhd->i_max_PDU_size,
                      p_box->data.p_hmhd->i_avg_PDU_size,
                      p_box->data.p_hmhd->i_max_bitrate,
                      p_box->data.p_hmhd->i_avg_bitrate );
#endif
    MP4_READBOX_EXIT( 1 );
}

825
static int MP4_ReadBox_url( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
826
{
827
    MP4_READBOX_ENTER( MP4_Box_data_url_t );
828
829
830
831
832
833
834
835
836
837
838
839
840

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

#ifdef MP4_VERBOSE
    msg_Dbg( p_stream->p_input, "Read Box: \"url\" url: %s",
                       p_box->data.p_url->psz_location );

#endif
    MP4_READBOX_EXIT( 1 );
}


841
static void MP4_FreeBox_url( MP4_Box_t *p_box )
842
843
844
845
{
    FREE( p_box->data.p_url->psz_location )
}

846
static int MP4_ReadBox_urn( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
847
848
849
850
851
852
{
    MP4_READBOX_ENTER( MP4_Box_data_urn_t );

    MP4_GETVERSIONFLAGS( p_box->data.p_urn );

    MP4_GETSTRINGZ( p_box->data.p_urn->psz_name );
853
854
    MP4_GETSTRINGZ( p_box->data.p_urn->psz_location );

855
856
857
858
859
860
861
#ifdef MP4_VERBOSE
    msg_Dbg( p_stream->p_input, "Read Box: \"urn\" name %s location %s",
                      p_box->data.p_urn->psz_name,
                      p_box->data.p_urn->psz_location );
#endif
    MP4_READBOX_EXIT( 1 );
}
862
static void MP4_FreeBox_urn( MP4_Box_t *p_box )
863
864
865
866
867
868
{
    FREE( p_box->data.p_urn->psz_name );
    FREE( p_box->data.p_urn->psz_location );
}


869
static int MP4_ReadBox_dref( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
870
871
{
    MP4_READBOX_ENTER( MP4_Box_data_dref_t );
872

873
874
875
    MP4_GETVERSIONFLAGS( p_box->data.p_dref );

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

877
878
879
880
881
882
883
884
885
886
887
888
    MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 8 );
    MP4_ReadBoxContainerRaw( p_stream, p_box );

#ifdef MP4_VERBOSE
    msg_Dbg( p_stream->p_input, "Read Box: \"dref\" entry-count %d",
                      p_box->data.p_dref->i_entry_count );

#endif
    MP4_READBOX_EXIT( 1 );
}


889
static int MP4_ReadBox_stts( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
890
{
891
    unsigned int i;
892
    MP4_READBOX_ENTER( MP4_Box_data_stts_t );
893
894
895
896

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

897
    p_box->data.p_stts->i_sample_count =
898
        calloc( sizeof( uint32_t ), p_box->data.p_stts->i_entry_count );
899
    p_box->data.p_stts->i_sample_delta =
900
        calloc( sizeof( uint32_t ), p_box->data.p_stts->i_entry_count );
901

902
903
904
905
906
    for( i = 0; (i < p_box->data.p_stts->i_entry_count )&&( i_read >=8 ); i++ )
    {
        MP4_GET4BYTES( p_box->data.p_stts->i_sample_count[i] );
        MP4_GET4BYTES( p_box->data.p_stts->i_sample_delta[i] );
    }
907

908
909
910
911
912
913
914
915
#ifdef MP4_VERBOSE
    msg_Dbg( p_stream->p_input, "Read Box: \"stts\" entry-count %d",
                      p_box->data.p_stts->i_entry_count );

#endif
    MP4_READBOX_EXIT( 1 );
}

916
static void MP4_FreeBox_stts( MP4_Box_t *p_box )
917
918
919
920
921
{
    FREE( p_box->data.p_stts->i_sample_count );
    FREE( p_box->data.p_stts->i_sample_delta );
}

922
static int MP4_ReadBox_ctts( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
923
{
924
    unsigned int i;
925
    MP4_READBOX_ENTER( MP4_Box_data_ctts_t );
926

927
    MP4_GETVERSIONFLAGS( p_box->data.p_ctts );
928

929
930
    MP4_GET4BYTES( p_box->data.p_ctts->i_entry_count );

931
    p_box->data.p_ctts->i_sample_count =
932
        calloc( sizeof( uint32_t ), p_box->data.p_ctts->i_entry_count );
933
    p_box->data.p_ctts->i_sample_offset =
934
        calloc( sizeof( uint32_t ), p_box->data.p_ctts->i_entry_count );
935

936
937
938
939
940
    for( i = 0; (i < p_box->data.p_ctts->i_entry_count )&&( i_read >=8 ); i++ )
    {
        MP4_GET4BYTES( p_box->data.p_ctts->i_sample_count[i] );
        MP4_GET4BYTES( p_box->data.p_ctts->i_sample_offset[i] );
    }
941

942
943
944
945
946
947
948
949
#ifdef MP4_VERBOSE
    msg_Dbg( p_stream->p_input, "Read Box: \"ctts\" entry-count %d",
                      p_box->data.p_ctts->i_entry_count );

#endif
    MP4_READBOX_EXIT( 1 );
}

950
static void MP4_FreeBox_ctts( MP4_Box_t *p_box )
951
952
953
954
955
{
    FREE( p_box->data.p_ctts->i_sample_count );
    FREE( p_box->data.p_ctts->i_sample_offset );
}

956
static int MP4_ReadLengthDescriptor( uint8_t **pp_peek, int64_t  *i_read )
957
{
958
959
    unsigned int i_b;
    unsigned int i_len = 0;
960
961
962
963
964
965
966
967
    do
    {
        i_b = **pp_peek;

        (*pp_peek)++;
        (*i_read)--;
        i_len = ( i_len << 7 ) + ( i_b&0x7f );
    } while( i_b&0x80 );
968
    return( i_len );
969
970
}

971
static int MP4_ReadBox_esds( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
972
973
{
#define es_descriptor p_box->data.p_esds->es_descriptor
974
975
976
    unsigned int i_len;
    unsigned int i_flags;
    unsigned int i_type;
977
978
979
980
981
982
983
984
985
986
987

    MP4_READBOX_ENTER( MP4_Box_data_esds_t );

    MP4_GETVERSIONFLAGS( p_box->data.p_esds );


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

988
989
#ifdef MP4_VERBOSE
        msg_Dbg( p_stream->p_input, "Found esds MPEG4ESDescr (%dBytes)",
990
                 i_len );
991
992
#endif

993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
        MP4_GET2BYTES( es_descriptor.i_ES_ID );
        MP4_GET1BYTE( i_flags );
        es_descriptor.b_stream_dependence = ( (i_flags&0x80) != 0);
        es_descriptor.b_url = ( (i_flags&0x40) != 0);
        es_descriptor.b_OCRstream = ( (i_flags&0x20) != 0);

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

1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
            MP4_GET1BYTE( i_len );
            es_descriptor.psz_URL = calloc( sizeof(char), i_len + 1 );
            memcpy( es_descriptor.psz_URL, p_peek, i_len );
            es_descriptor.psz_URL[i_len] = 0;
            p_peek += i_len;
            i_read -= i_len;
        }
        else
        {
            es_descriptor.psz_URL = NULL;
        }
        if( es_descriptor.b_OCRstream )
        {
            MP4_GET2BYTES( es_descriptor.i_OCR_ES_ID );
        }
        MP4_GET1BYTE( i_type ); /* get next type */
    }

    if( i_type != 0x04)/* MP4DecConfigDescrTag */
    {
1028
1029
         es_descriptor.p_decConfigDescr = NULL;
         MP4_READBOX_EXIT( 1 ); /* rest isn't interesting up to now */
1030
1031
1032
    }

    i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1033
1034
1035

#ifdef MP4_VERBOSE
        msg_Dbg( p_stream->p_input, "Found esds MP4DecConfigDescr (%dBytes)",
1036
                 i_len );
1037
1038
#endif

1039
    es_descriptor.p_decConfigDescr =
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
            malloc( sizeof( MP4_descriptor_decoder_config_t ));

    MP4_GET1BYTE( es_descriptor.p_decConfigDescr->i_objectTypeIndication );
    MP4_GET1BYTE( i_flags );
    es_descriptor.p_decConfigDescr->i_streamType = i_flags >> 2;
    es_descriptor.p_decConfigDescr->b_upStream = ( i_flags >> 1 )&0x01;
    MP4_GET3BYTES( es_descriptor.p_decConfigDescr->i_buffer_sizeDB );
    MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_max_bitrate );
    MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_avg_bitrate );
    MP4_GET1BYTE( i_type );
    if( i_type !=  0x05 )/* MP4DecSpecificDescrTag */
    {
1052
1053
        es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = 0;
        es_descriptor.p_decConfigDescr->p_decoder_specific_info  = NULL;
1054
1055
        MP4_READBOX_EXIT( 1 );
    }
1056

1057
    i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1058
1059
1060

#ifdef MP4_VERBOSE
        msg_Dbg( p_stream->p_input, "Found esds MP4DecSpecificDescr (%dBytes)",
1061
                 i_len );
1062
1063
#endif

1064
1065
    es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = i_len;
    es_descriptor.p_decConfigDescr->p_decoder_specific_info = malloc( i_len );
1066
    memcpy( es_descriptor.p_decConfigDescr->p_decoder_specific_info,
1067
1068
1069
1070
1071
1072
1073
            p_peek, i_len );

    MP4_READBOX_EXIT( 1 );

#undef es_descriptor
}

1074
static void MP4_FreeBox_esds( MP4_Box_t *p_box )
1075
1076
{
    FREE( p_box->data.p_esds->es_descriptor.psz_URL );
1077
1078
1079
1080
    if( p_box->data.p_esds->es_descriptor.p_decConfigDescr )
    {
        FREE( p_box->data.p_esds->es_descriptor.p_decConfigDescr->p_decoder_specific_info );
    }
1081
1082
1083
    FREE( p_box->data.p_esds->es_descriptor.p_decConfigDescr );
}

1084
static int MP4_ReadBox_sample_soun( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1085
{
1086
1087
    unsigned int i;

1088
1089
    MP4_READBOX_ENTER( MP4_Box_data_sample_soun_t );

gbazin's avatar
   
gbazin committed
1090
1091
1092
1093
1094
    /* Sanity check needed because the "wave" box does also contain an
     * "mp4a" box that we don't understand. */
    if( i_read < 28 )
    {
        i_read -= 30;
gbazin's avatar
   
gbazin committed
1095
        MP4_READBOX_EXIT( 1 );
gbazin's avatar
   
gbazin committed
1096
1097
    }

1098
1099
1100
1101
1102
1103
    for( i = 0; i < 6 ; i++ )
    {
        MP4_GET1BYTE( p_box->data.p_sample_soun->i_reserved1[i] );
    }

    MP4_GET2BYTES( p_box->data.p_sample_soun->i_data_reference_index );
1104

1105
1106
1107
    /*
     * XXX hack -> produce a copy of the nearly complete chunk
     */
gbazin's avatar
   
gbazin committed
1108
1109
1110
    p_box->data.p_sample_soun->i_qt_description = i_read;
    p_box->data.p_sample_soun->p_qt_description = malloc( i_read );
    memcpy( p_box->data.p_sample_soun->p_qt_description, p_peek, i_read );
1111

1112
1113
1114
1115
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_version );
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_revision_level );
    MP4_GET4BYTES( p_box->data.p_sample_soun->i_qt_vendor );

1116
1117
1118
1119
1120
1121
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_channelcount );
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_samplesize );
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_predefined );
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_reserved3 );
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratehi );
    MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratelo );
1122

1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
    if( p_box->data.p_sample_soun->i_qt_version == 1 &&
        i_read >= 16 )
    {
        /* qt3+ */
        MP4_GET4BYTES( p_box->data.p_sample_soun->i_sample_per_packet );
        MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_packet );
        MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_frame );
        MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_sample );

#ifdef MP4_VERBOSE
        msg_Dbg( p_stream->p_input,
                 "Read Box: \"soun\" qt3+ sample/packet=%d bytes/packet=%d bytes/frame=%d bytes/sample=%d",
                 p_box->data.p_sample_soun->i_sample_per_packet, p_box->data.p_sample_soun->i_bytes_per_packet,
                 p_box->data.p_sample_soun->i_bytes_per_frame, p_box->data.p_sample_soun->i_bytes_per_sample );
#endif
        MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 44 );
    }
    else
    {
        p_box->data.p_sample_soun->i_sample_per_packet = 0;
        p_box->data.p_sample_soun->i_bytes_per_packet = 0;
        p_box->data.p_sample_soun->i_bytes_per_frame = 0;
        p_box->data.p_sample_soun->i_bytes_per_sample = 0;

Laurent Aimar's avatar
Laurent Aimar committed
1147
        msg_Dbg( p_stream->p_input, "Read Box: \"soun\" mp4 or qt1/2 (rest="I64Fd")", i_read );
1148
1149
        MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 28 );
    }
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217

    p_box->data.p_sample_soun->p_drms =
        p_box->i_type == FOURCC_drms ? drms_alloc() : NULL;

    if( p_box->data.p_sample_soun->p_drms )
    {
        FILE *file;
        char *psz_homedir;
        char *psz_filename;
        uint32_t p_user_key[ 4 ];

        int i_ret = 0;
        vlc_bool_t b_key = VLC_FALSE;

        psz_filename = NULL;
        psz_homedir = p_stream->p_input->p_vlc->psz_homedir;

#define DRMS_FILENAME "drms"

        if( psz_homedir != NULL )
        {
            psz_filename = (char *)malloc( sizeof("/" CONFIG_DIR "/"
                                           DRMS_FILENAME) +
                                           strlen( psz_homedir ) );
            if( psz_filename != NULL )
            {
                sprintf( psz_filename, "%s/" CONFIG_DIR "/" DRMS_FILENAME,
                         psz_homedir );

                file = fopen( psz_filename, "r" );
                if( file != NULL )
                {
                    b_key = fread( p_user_key, sizeof(uint32_t),
                                   4, file ) == 4 ? VLC_TRUE : VLC_FALSE;
                    fclose( file );
                }
            }
        }

        if( b_key == VLC_FALSE )
        {
            i_ret = drms_get_user_key( NULL, p_user_key );
        }

        if( !i_ret )
        {
            if( b_key == VLC_FALSE && psz_filename != NULL )
            {
                file = fopen( psz_filename, "w" );
                if( file != NULL )
                {
                    fwrite( p_user_key, sizeof(uint32_t), 4, file );
                    fclose( file );
                }
            }

            i_ret = drms_init( p_box->data.p_sample_soun->p_drms,
                               DRMS_INIT_UKEY, (uint8_t *)p_user_key,
                               sizeof(p_user_key) );
        }

        if( psz_filename != NULL )
        {
            free( (void *)psz_filename );
        }

        if( i_ret )
        {
1218
1219
            msg_Dbg( p_stream->p_input, "drms_init( UKEY ) failed" );

1220
1221
1222
1223
1224
            drms_free( p_box->data.p_sample_soun->p_drms );
            p_box->data.p_sample_soun->p_drms = NULL;
        }
    }

1225
    MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds */
1226

1227
1228
1229
1230
#ifdef MP4_VERBOSE
    msg_Dbg( p_stream->p_input, "Read Box: \"soun\" in stsd channel %d sample size %d sampl rate %f",
                      p_box->data.p_sample_soun->i_channelcount,
                      p_box->data.p_sample_soun->i_samplesize,
1231
                      (float)p_box->data.p_sample_soun->i_sampleratehi +
1232
1233
1234
1235
1236
1237
1238
                    (float)p_box->data.p_sample_soun->i_sampleratelo / 65536 );

#endif
    MP4_READBOX_EXIT( 1 );
}


1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
static void MP4_FreeBox_sample_soun( MP4_Box_t *p_box )
{
    if( p_box->i_type == FOURCC_drms )
    {
        if( p_box->data.p_sample_soun->p_drms )
        {
            drms_free( p_box->data.p_sample_soun->p_drms );
        }
    }
}


1251
static int MP4_ReadBox_sample_vide( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1252
{
1253
    unsigned int i;
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263

    MP4_READBOX_ENTER( MP4_Box_data_sample_vide_t );

    for( i = 0; i < 6 ; i++ )
    {
        MP4_GET1BYTE( p_box->data.p_sample_vide->i_reserved1[i] );
    }

    MP4_GET2BYTES( p_box->data.p_sample_vide->i_data_reference_index );

1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
    /*
     * XXX hack -> produce a copy of the nearly complete chunk
     */
    if( i_read > 0 )
    {
        p_box->data.p_sample_vide->i_qt_image_description = i_read;
        p_box->data.p_sample_vide->p_qt_image_description = malloc( i_read );
        memcpy( p_box->data.p_sample_vide->p_qt_image_description,
                p_peek,
                i_read );
    }
    else
1276
    {
1277
1278
        p_box->data.p_sample_vide->i_qt_image_description = 0;
        p_box->data.p_sample_vide->p_qt_image_description = NULL;
1279
1280
    }

1281
1282
1283
1284
1285
1286
1287
    MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_version );
    MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_revision_level );
    MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_vendor );

    MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_temporal_quality );
    MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_spatial_quality );

1288
1289
    MP4_GET2BYTES( p_box->data.p_sample_vide->i_width );
    MP4_GET2BYTES( p_box->data.p_sample_vide->i_height );
1290

1291
1292
1293
    MP4_GET4BYTES( p_box->data.p_sample_vide->i_horizresolution );
    MP4_GET4BYTES( p_box->data.p_sample_vide->i_vertresolution );

1294
1295
    MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_data_size );
    MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_frame_count );
1296
1297
1298
1299
1300

    memcpy( &p_box->data.p_sample_vide->i_compressorname, p_peek, 32 );
    p_peek += 32; i_read -= 32;

    MP4_GET2BYTES( p_box->data.p_sample_vide->i_depth );
1301
    MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_color_table );
1302

1303
1304
    MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 78);
    MP4_ReadBoxContainerRaw( p_stream, p_box );
1305

1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
#ifdef MP4_VERBOSE
    msg_Dbg( p_stream->p_input, "Read Box: \"vide\" in stsd %dx%d depth %d",
                      p_box->data.p_sample_vide->i_width,
                      p_box->data.p_sample_vide->i_height,
                      p_box->data.p_sample_vide->i_depth );

#endif
    MP4_READBOX_EXIT( 1 );
}


1317
static int MP4_ReadBox_stsd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1318
1319
1320
1321
1322
1323
1324
1325
{

    MP4_READBOX_ENTER( MP4_Box_data_stsd_t );

    MP4_GETVERSIONFLAGS( p_box->data.p_stsd );

    MP4_GET4BYTES( p_box->data.p_stsd->i_entry_count );

1326
    MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 8 );