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