checkAPIs.pl: support for new-style dissectors in check_hf_entries
[metze/wireshark/wip.git] / epan / dissectors / file-mp4.c
1 /* file-mp4.c
2  * routines for dissection of MP4 files
3  * Copyright 2013-2014, Martin Kaiser <martin@kaiser.cx>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11
12 /* this dissector is based on
13  * ISO/IEC 14496-12 (ISO base media file format) and
14  * ISO/IEC 14496-14 (MP4 file format)
15  *
16  * at the moment, it dissects the basic box structure and the payload of
17  * some simple boxes */
18
19
20 #include "config.h"
21
22 #include <math.h>
23
24 #include <epan/packet.h>
25 #include <epan/expert.h>
26
27 #define MAKE_TYPE_VAL(a, b, c, d)   ((a)<<24 | (b)<<16 | (c)<<8 | (d))
28
29 /* Although the dissection of each box consumes a couple of bytes, it's
30    possible to craft a file whose boxes recurse so deeply that wireshark
31    crashes before we processed all data. Therefore, we limit the
32    recursion level for boxes to a reasonable depth. */
33 #define MP4_BOX_MAX_REC_LVL  20
34
35 void proto_register_mp4(void);
36 void proto_reg_handoff_mp4(void);
37
38 static gint dissect_mp4_box(guint32 parent_box_type _U_, guint depth,
39         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree);
40
41 static int proto_mp4 = -1;
42
43 static gint ett_mp4 = -1;
44 static gint ett_mp4_box = -1;
45
46 static int hf_mp4_box_size = -1;
47 static int hf_mp4_box_type_str = -1;
48 static int hf_mp4_box_largesize = -1;
49 static int hf_mp4_full_box_ver = -1;
50 static int hf_mp4_full_box_flags = -1;
51 static int hf_mp4_full_box_flags_media_data_location = -1;
52 static int hf_mp4_ftyp_brand = -1;
53 static int hf_mp4_ftyp_ver = -1;
54 static int hf_mp4_ftyp_add_brand = -1;
55 static int hf_mp4_stsz_sample_size = -1;
56 static int hf_mp4_stsz_sample_count = -1;
57 static int hf_mp4_stsz_entry_size = -1;
58 static int hf_mp4_mvhd_creat_time = -1;
59 static int hf_mp4_mvhd_mod_time = -1;
60 static int hf_mp4_mvhd_timescale = -1;
61 static int hf_mp4_mvhd_duration = -1;
62 static int hf_mp4_mvhd_rate = -1;
63 static int hf_mp4_mvhd_vol = -1;
64 static int hf_mp4_mvhd_next_tid = -1;
65 static int hf_mp4_mfhd_seq_num = -1;
66 static int hf_mp4_tkhd_creat_time = -1;
67 static int hf_mp4_tkhd_mod_time = -1;
68 static int hf_mp4_tkhd_track_id = -1;
69 static int hf_mp4_tkhd_duration = -1;
70 static int hf_mp4_tkhd_width = -1;
71 static int hf_mp4_tkhd_height = -1;
72 static int hf_mp4_hdlr_type = -1;
73 static int hf_mp4_hdlr_name = -1;
74 static int hf_mp4_dref_entry_cnt = -1;
75 static int hf_mp4_stsd_entry_cnt = -1;
76
77 static expert_field ei_mp4_box_too_large = EI_INIT;
78 static expert_field ei_mp4_too_many_rec_lvls = EI_INIT;
79 static expert_field ei_mp4_mvhd_next_tid_unknown = EI_INIT;
80
81 /* a box must at least have a 32bit len field and a 32bit type */
82 #define MIN_BOX_SIZE 8
83 /* an extended box has the first length field set to 1 */
84 #define BOX_SIZE_EXTENDED 1
85
86 /* the box type is stored as four text characters
87    it is in network byte order and contains only printable characters
88    for our internal handling, we convert this to a 32bit value */
89
90 #define BOX_TYPE_NONE  0x0 /* used for parent_box_type of a top-level box */
91 #define BOX_TYPE_FTYP  MAKE_TYPE_VAL('f', 't', 'y', 'p')
92 #define BOX_TYPE_MOOV  MAKE_TYPE_VAL('m', 'o', 'o', 'v')
93 #define BOX_TYPE_MVHD  MAKE_TYPE_VAL('m', 'v', 'h', 'd')
94 #define BOX_TYPE_TRAK  MAKE_TYPE_VAL('t', 'r', 'a', 'k')
95 #define BOX_TYPE_TKHD  MAKE_TYPE_VAL('t', 'k', 'h', 'd')
96 #define BOX_TYPE_MDIA  MAKE_TYPE_VAL('m', 'd', 'i', 'a')
97 #define BOX_TYPE_MDHD  MAKE_TYPE_VAL('m', 'd', 'h', 'd')
98 #define BOX_TYPE_HDLR  MAKE_TYPE_VAL('h', 'd', 'l', 'r')
99 #define BOX_TYPE_MINF  MAKE_TYPE_VAL('m', 'i', 'n', 'f')
100 #define BOX_TYPE_VMHD  MAKE_TYPE_VAL('v', 'm', 'h', 'd')
101 #define BOX_TYPE_SMHD  MAKE_TYPE_VAL('s', 'm', 'h', 'd')
102 #define BOX_TYPE_DINF  MAKE_TYPE_VAL('d', 'i', 'n', 'f')
103 #define BOX_TYPE_DREF  MAKE_TYPE_VAL('d', 'r', 'e', 'f')
104 #define BOX_TYPE_STBL  MAKE_TYPE_VAL('s', 't', 'b', 'l')
105 #define BOX_TYPE_STTS  MAKE_TYPE_VAL('s', 't', 't', 's')
106 #define BOX_TYPE_CTTS  MAKE_TYPE_VAL('c', 't', 't', 's')
107 #define BOX_TYPE_STSD  MAKE_TYPE_VAL('s', 't', 's', 'd')
108 #define BOX_TYPE_STSZ  MAKE_TYPE_VAL('s', 't', 's', 'z')
109 #define BOX_TYPE_STZ2  MAKE_TYPE_VAL('s', 't', 'z', '2')
110 #define BOX_TYPE_STSC  MAKE_TYPE_VAL('s', 't', 's', 'c')
111 #define BOX_TYPE_STCO  MAKE_TYPE_VAL('s', 't', 'c', 'o')
112 #define BOX_TYPE_STSS  MAKE_TYPE_VAL('s', 't', 's', 's')
113 #define BOX_TYPE_MVEX  MAKE_TYPE_VAL('m', 'v', 'e', 'x')
114 #define BOX_TYPE_MOOF  MAKE_TYPE_VAL('m', 'o', 'o', 'f')
115 #define BOX_TYPE_MEHD  MAKE_TYPE_VAL('m', 'e', 'h', 'd')
116 #define BOX_TYPE_TREX  MAKE_TYPE_VAL('t', 'r', 'e', 'x')
117 #define BOX_TYPE_MFHD  MAKE_TYPE_VAL('m', 'f', 'h', 'd')
118 #define BOX_TYPE_TRAF  MAKE_TYPE_VAL('t', 'r', 'a', 'f')
119 #define BOX_TYPE_TFHD  MAKE_TYPE_VAL('t', 'f', 'h', 'd')
120 #define BOX_TYPE_TRUN  MAKE_TYPE_VAL('t', 'r', 'u', 'n')
121 #define BOX_TYPE_MDAT  MAKE_TYPE_VAL('m', 'd', 'a', 't')
122 #define BOX_TYPE_UDTA  MAKE_TYPE_VAL('u', 'd', 't', 'a')
123 /* the box name is url + <space>, all names must be 4 characters long */
124 #define BOX_TYPE_URL_  MAKE_TYPE_VAL('u', 'r', 'l', ' ')
125
126 /* the location for this URL box is the same as in the upper-level movie box */
127 #define ENTRY_FLAG_MOVIE 0x000001
128
129 static const value_string box_types[] = {
130     { BOX_TYPE_FTYP, "File Type Box" },
131     { BOX_TYPE_MOOV, "Movie Box" },
132     { BOX_TYPE_MVHD, "Movie Header Box" },
133     { BOX_TYPE_TRAK, "Track Box" },
134     { BOX_TYPE_TKHD, "Track Header Box" },
135     { BOX_TYPE_MDIA, "Media Box" },
136     { BOX_TYPE_MDHD, "Media Header Box" },
137     { BOX_TYPE_HDLR, "Handler Reference Box" },
138     { BOX_TYPE_MINF, "Media Information Box" },
139     { BOX_TYPE_VMHD, "Video Media Header Box" },
140     { BOX_TYPE_SMHD, "Sound Media Header Box" },
141     { BOX_TYPE_DINF, "Data Information Box" },
142     { BOX_TYPE_DREF, "Data Reference Box" },
143     { BOX_TYPE_STBL, "Sample to Group Box" },
144     { BOX_TYPE_STTS, "Decoding Time To Sample Box" },
145     { BOX_TYPE_CTTS, "Composition Time To Sample Box" },
146     { BOX_TYPE_STSD, "Sample Description Box" },
147     { BOX_TYPE_STSZ, "Sample Size Box" },
148     { BOX_TYPE_STZ2, "Compact Sample Size Box" },
149     { BOX_TYPE_STSC, "Sample To Chunk Box" },
150     { BOX_TYPE_STCO, "Chunk Offset Box" },
151     { BOX_TYPE_STSS, "Sync Sample Table" },
152     { BOX_TYPE_MVEX, "Movie Extends Box" },
153     { BOX_TYPE_MOOF, "Movie Fragment Box" },
154     { BOX_TYPE_MEHD, "Movie Extends Header Box" },
155     { BOX_TYPE_TREX, "Track Extends Box" },
156     { BOX_TYPE_MFHD, "Movie Fragment Header Box" },
157     { BOX_TYPE_TRAF, "Track Fragment Box" },
158     { BOX_TYPE_TFHD, "Track Fragment Header Box" },
159     { BOX_TYPE_TRUN, "Track Fragment Run Box" },
160     { BOX_TYPE_MDAT, "Media Data Box" },
161     { BOX_TYPE_UDTA, "User Data Box" },
162     { BOX_TYPE_URL_, "URL Box" },
163     { 0, NULL }
164 };
165
166 /* convert a decimal number x into a double 0.x (e.g. 123 becomes 0.123) */
167 static inline double
168 make_fract(guint x)
169 {
170     if (x==0)
171         return 0.0;
172
173     return (double)(x / exp(log(10.0)*(1+floor(log((double)x)/log(10.0)))));
174 }
175
176 static gint
177 dissect_mp4_mvhd_body(tvbuff_t *tvb, gint offset, gint len _U_,
178         packet_info *pinfo, guint depth _U_, proto_tree *tree)
179 {
180     gint        offset_start;
181     guint8      version;
182     guint8      time_len;
183     double      rate, vol;
184     guint16     fract_dec;
185     guint32     next_tid;
186     proto_item *next_tid_it;
187
188     offset_start = offset;
189
190     version = tvb_get_guint8(tvb, offset);
191     proto_tree_add_item(tree, hf_mp4_full_box_ver,
192             tvb, offset, 1, ENC_BIG_ENDIAN);
193     offset += 1;
194     proto_tree_add_item(tree, hf_mp4_full_box_flags,
195             tvb, offset, 3, ENC_BIG_ENDIAN);
196     offset += 3;
197
198     time_len = (version==0) ? 4 : 8;
199     proto_tree_add_item(tree, hf_mp4_mvhd_creat_time,
200             tvb, offset, time_len, ENC_BIG_ENDIAN);
201     offset += time_len;
202     proto_tree_add_item(tree, hf_mp4_mvhd_mod_time,
203             tvb, offset, time_len, ENC_BIG_ENDIAN);
204     offset += time_len;
205     proto_tree_add_item(tree, hf_mp4_mvhd_timescale,
206             tvb, offset, 4, ENC_BIG_ENDIAN);
207     offset += 4;
208     proto_tree_add_item(tree, hf_mp4_mvhd_duration,
209             tvb, offset, time_len, ENC_BIG_ENDIAN);
210     offset += time_len;
211
212     rate = tvb_get_ntohs(tvb, offset);
213     fract_dec = tvb_get_ntohs(tvb, offset+2);
214     rate += make_fract(fract_dec);
215     proto_tree_add_double(tree, hf_mp4_mvhd_rate, tvb, offset, 4, rate);
216     offset += 4;
217
218     vol = tvb_get_guint8(tvb, offset);
219     fract_dec = tvb_get_guint8(tvb, offset+1);
220     vol += make_fract(fract_dec);
221     proto_tree_add_double(tree, hf_mp4_mvhd_vol, tvb, offset, 4, vol);
222     offset += 2;
223
224     offset += 2;   /* 16 bits reserved */
225     offset += 2*4; /* 2 * uint32 reserved */
226
227     offset += 9*4; /* XXX - unity matrix */
228     offset += 6*4; /* 6 * 32 bits predefined = 0 */
229
230     next_tid = tvb_get_ntohl(tvb, offset);
231     next_tid_it = proto_tree_add_item(tree, hf_mp4_mvhd_next_tid,
232             tvb, offset, 4, ENC_BIG_ENDIAN);
233     if (next_tid == G_MAXUINT32)
234         expert_add_info(pinfo, next_tid_it, &ei_mp4_mvhd_next_tid_unknown);
235     offset += 4;
236
237     return offset-offset_start;
238 }
239
240 static gint
241 dissect_mp4_mfhd_body(tvbuff_t *tvb, gint offset, gint len _U_,
242         packet_info *pinfo _U_, guint depth _U_, proto_tree *tree)
243 {
244     gint offset_start;
245
246     offset_start = offset;
247     proto_tree_add_item(tree, hf_mp4_full_box_ver,
248             tvb, offset, 1, ENC_BIG_ENDIAN);
249     offset += 1;
250     proto_tree_add_item(tree, hf_mp4_full_box_flags,
251             tvb, offset, 3, ENC_BIG_ENDIAN);
252     offset += 3;
253
254     proto_tree_add_item(tree, hf_mp4_mfhd_seq_num,
255             tvb, offset, 4, ENC_BIG_ENDIAN);
256     offset += 4;
257
258     return offset-offset_start;
259 }
260
261
262 static gint
263 dissect_mp4_tkhd_body(tvbuff_t *tvb, gint offset, gint len _U_,
264         packet_info *pinfo _U_, guint depth _U_, proto_tree *tree)
265 {
266     gint     offset_start;
267     guint8   version;
268     guint8   time_len;
269     double   width, height;
270     guint16  fract_dec;
271
272     offset_start = offset;
273
274     version = tvb_get_guint8(tvb, offset);
275     proto_tree_add_item(tree, hf_mp4_full_box_ver,
276             tvb, offset, 1, ENC_BIG_ENDIAN);
277     offset += 1;
278     proto_tree_add_item(tree, hf_mp4_full_box_flags,
279             tvb, offset, 3, ENC_BIG_ENDIAN);
280     offset += 3;
281
282     time_len = (version==0) ? 4 : 8;
283     proto_tree_add_item(tree, hf_mp4_tkhd_creat_time,
284             tvb, offset, time_len, ENC_BIG_ENDIAN);
285     offset += time_len;
286     proto_tree_add_item(tree, hf_mp4_tkhd_mod_time,
287             tvb, offset, time_len, ENC_BIG_ENDIAN);
288     offset += time_len;
289
290     proto_tree_add_item(tree, hf_mp4_tkhd_track_id,
291             tvb, offset, 4, ENC_BIG_ENDIAN);
292     offset += 4;
293
294     offset += 4;   /* 32bit reserved */
295
296     proto_tree_add_item(tree, hf_mp4_tkhd_duration,
297             tvb, offset, time_len, ENC_BIG_ENDIAN);
298     offset += time_len;
299
300     offset += 2*4; /* 2*32bit reserved */
301     offset += 2;   /* 16bit layer */
302     offset += 2;   /* 16bit alternate_group */
303     offset += 2;   /* 16bit volume */
304     offset += 2;   /* 16bit reserved */
305     offset += 9*4; /* 9*32bit matrix */
306
307     width = tvb_get_ntohs(tvb, offset);
308     fract_dec = tvb_get_ntohs(tvb, offset+2);
309     width += make_fract(fract_dec);
310     proto_tree_add_double(tree, hf_mp4_tkhd_width, tvb, offset, 4, width);
311     offset += 4;
312
313     height = tvb_get_ntohs(tvb, offset);
314     fract_dec = tvb_get_ntohs(tvb, offset+2);
315     height += make_fract(fract_dec);
316     proto_tree_add_double(tree, hf_mp4_tkhd_height, tvb, offset, 4, height);
317     offset += 4;
318
319     return offset-offset_start;
320 }
321
322
323 static gint
324 dissect_mp4_ftyp_body(tvbuff_t *tvb, gint offset, gint len,
325         packet_info *pinfo _U_, guint depth _U_, proto_tree *tree)
326 {
327     gint offset_start;
328
329     offset_start = offset;
330     proto_tree_add_item(tree, hf_mp4_ftyp_brand,
331             tvb, offset, 4, ENC_ASCII|ENC_NA);
332     offset += 4;
333     proto_tree_add_item(tree, hf_mp4_ftyp_ver,
334             tvb, offset, 4, ENC_BIG_ENDIAN);
335     offset += 4;
336
337     while ((offset-offset_start) < len) {
338         proto_tree_add_item(tree, hf_mp4_ftyp_add_brand,
339                 tvb, offset, 4, ENC_ASCII|ENC_NA);
340         offset += 4;
341     }
342
343     return offset - offset_start;
344 }
345
346
347 static gint
348 dissect_mp4_stsz_body(tvbuff_t *tvb, gint offset, gint len _U_,
349         packet_info *pinfo _U_, guint depth _U_, proto_tree *tree)
350 {
351     gint offset_start;
352     guint32  sample_size, sample_count, i;
353
354     offset_start = offset;
355     sample_size = tvb_get_ntohl(tvb, offset);
356
357     proto_tree_add_item(tree, hf_mp4_stsz_sample_size,
358             tvb, offset, 4, ENC_BIG_ENDIAN);
359     /* XXX - expert info for sample size == 0 */
360     offset += 4;
361
362     sample_count = tvb_get_ntohl(tvb, offset);
363     proto_tree_add_item(tree, hf_mp4_stsz_sample_count,
364             tvb, offset, 4, ENC_BIG_ENDIAN);
365     offset += 4;
366
367     if (sample_size != 0)
368         return offset - offset_start;
369
370     for (i=0; i<sample_count; i++) {
371         proto_tree_add_item(tree, hf_mp4_stsz_entry_size,
372                 tvb, offset, 4, ENC_BIG_ENDIAN);
373         offset += 4;
374     }
375
376     return offset - offset_start;
377 }
378
379  
380 static gint
381 dissect_mp4_hdlr_body(tvbuff_t *tvb, gint offset, gint len _U_,
382         packet_info *pinfo _U_, guint depth _U_, proto_tree *tree)
383 {
384     gint   offset_start;
385     guint  hdlr_name_len;
386
387     offset_start = offset;
388
389     proto_tree_add_item(tree, hf_mp4_full_box_ver,
390             tvb, offset, 1, ENC_BIG_ENDIAN);
391     /* XXX - put up an expert info if version!=0 */
392     offset += 1;
393     proto_tree_add_item(tree, hf_mp4_full_box_flags,
394             tvb, offset, 3, ENC_BIG_ENDIAN);
395     offset += 3;
396
397     offset += 4;   /* four reserved 0 bytes */
398
399     proto_tree_add_item(tree, hf_mp4_hdlr_type,
400             tvb, offset, 4, ENC_ASCII|ENC_NA);
401     offset += 4;
402
403     offset += 12;   /* 3x32bit reserved */
404
405     /* name is a 0-terminated UTF-8 string, len includes the final 0 */
406     hdlr_name_len = tvb_strsize(tvb, offset);
407     proto_tree_add_item(tree, hf_mp4_hdlr_name,
408             tvb, offset, hdlr_name_len, ENC_UTF_8|ENC_NA);
409     offset += hdlr_name_len;
410
411     return offset-offset_start;
412 }
413
414
415 static gint
416 dissect_mp4_dref_body(tvbuff_t *tvb, gint offset, gint len _U_,
417         packet_info *pinfo, guint depth, proto_tree *tree)
418 {
419     gint     offset_start;
420     guint32  entry_cnt, i;
421     gint     ret;
422
423     offset_start = offset;
424
425     proto_tree_add_item(tree, hf_mp4_full_box_ver,
426             tvb, offset, 1, ENC_BIG_ENDIAN);
427     /* XXX - put up an expert info if version!=0 */
428     offset += 1;
429     proto_tree_add_item(tree, hf_mp4_full_box_flags,
430             tvb, offset, 3, ENC_BIG_ENDIAN);
431     offset += 3;
432
433     entry_cnt = tvb_get_ntohl(tvb, offset);
434     proto_tree_add_item(tree, hf_mp4_dref_entry_cnt,
435             tvb, offset, 4, ENC_BIG_ENDIAN);
436     offset += 4;
437
438     for(i=0; i<entry_cnt; i++) {
439         ret = dissect_mp4_box(BOX_TYPE_DREF, depth, tvb, offset, pinfo, tree);
440         if (ret<=0)
441             break;
442
443         offset += ret;
444     }
445
446     return offset-offset_start;
447 }
448
449
450 static gint
451 dissect_mp4_url_body(tvbuff_t *tvb, gint offset, gint len,
452         packet_info *pinfo _U_, guint depth _U_, proto_tree *tree)
453 {
454 #if 0
455     guint32  flags;
456 #endif
457
458     proto_tree_add_item(tree, hf_mp4_full_box_ver,
459             tvb, offset, 1, ENC_BIG_ENDIAN);
460     /* XXX - put up an expert info if version!=0 */
461     offset += 1;
462
463 #if 0
464     flags = tvb_get_ntoh24(tvb, offset);
465 #endif
466     proto_tree_add_item(tree, hf_mp4_full_box_flags,
467             tvb, offset, 3, ENC_BIG_ENDIAN);
468     proto_tree_add_item(tree, hf_mp4_full_box_flags_media_data_location, tvb, offset, 3, ENC_BIG_ENDIAN);
469     /*offset += 3;*/
470
471 #if 0
472     if (flags&ENTRY_FLAG_MOVIE) {
473     }
474     else {
475         /* XXX - dissect location string */
476     }
477 #endif
478
479     return len;
480 }
481
482
483 static gint
484 dissect_mp4_stsd_body(tvbuff_t *tvb, gint offset, gint len,
485         packet_info *pinfo, guint depth, proto_tree *tree)
486 {
487     guint32  entry_cnt, i;
488     gint     ret;
489
490     proto_tree_add_item(tree, hf_mp4_full_box_ver,
491             tvb, offset, 1, ENC_BIG_ENDIAN);
492     /* XXX - put up an expert info if version!=0 */
493     offset += 1;
494     proto_tree_add_item(tree, hf_mp4_full_box_flags,
495             tvb, offset, 3, ENC_BIG_ENDIAN);
496     offset += 3;
497
498     entry_cnt = tvb_get_ntohl(tvb, offset);
499     proto_tree_add_item(tree, hf_mp4_stsd_entry_cnt,
500             tvb, offset, 4, ENC_BIG_ENDIAN);
501     offset += 4;
502
503     for(i=0; i<entry_cnt; i++) {
504         /* a sample entry has the same format as an mp4 box
505            we call dissect_mp4_box() to dissect it
506            alternatively, we could parse it ourselves, we'd then have to
507            handle the extended lengths etc */
508
509         /* XXX - dissect the content of each Sample Entry,
510            this depends on the handler_type, we could add an optional
511            void *data parameter to dissect_mp4_box() and handle sample
512            entry boxes based on parent box and data parameter */
513         ret = dissect_mp4_box(BOX_TYPE_STSD, depth, tvb, offset, pinfo, tree);
514         if (ret<=0)
515             break;
516
517         offset += ret;
518     }
519
520     return len;
521 }
522
523  
524 /* dissect a box, return its (standard or extended) length or 0 for error
525    depth is the recursion level of the parent box */
526 static gint
527 dissect_mp4_box(guint32 parent_box_type _U_, guint depth,
528         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree)
529 {
530     gint        offset_start;
531     guint64     box_size;
532     guint32     box_type;
533     guint8     *box_type_str;
534     proto_item *type_pi, *size_pi, *ext_size_pi = NULL;
535     proto_tree *box_tree;
536     gint        ret;
537     gint        body_size;
538
539
540     offset_start = offset;
541
542     /* the following mechanisms are not supported for now
543        - size==0, indicating that the box extends to the end of the file
544        - extended box types */
545
546     box_size = (guint64)tvb_get_ntohl(tvb, offset);
547     if ((box_size != BOX_SIZE_EXTENDED) && (box_size < MIN_BOX_SIZE))
548         return -1;
549
550     box_type = tvb_get_ntohl(tvb, offset+4);
551     box_type_str = tvb_get_string_enc(wmem_packet_scope(), tvb,
552             offset+4, 4, ENC_ASCII|ENC_NA);
553
554     box_tree = proto_tree_add_subtree_format(tree, tvb, offset, -1, ett_mp4_box, &type_pi, "%s (%s)",
555             val_to_str_const(box_type, box_types, "unknown"), box_type_str);
556
557     size_pi = proto_tree_add_item(box_tree, hf_mp4_box_size,
558             tvb, offset, 4, ENC_BIG_ENDIAN);
559     if (box_size == BOX_SIZE_EXTENDED)
560         proto_item_append_text(size_pi, " (actual size is in largesize)");
561
562     offset += 4;
563     proto_tree_add_item(box_tree, hf_mp4_box_type_str,
564             tvb, offset, 4, ENC_ASCII|ENC_NA);
565     offset += 4;
566
567     if (box_size == BOX_SIZE_EXTENDED) {
568         box_size = tvb_get_ntoh64(tvb, offset);
569         ext_size_pi = proto_tree_add_item(box_tree, hf_mp4_box_largesize,
570                 tvb, offset, 8, ENC_BIG_ENDIAN);
571         offset += 8;
572     }
573
574     if (box_size > G_MAXINT) {
575         /* this should be ok for ext_size_pi==NULL */
576         expert_add_info(pinfo, ext_size_pi, &ei_mp4_box_too_large);
577         return -1;
578     }
579     proto_item_set_len(type_pi, (gint)box_size);
580     body_size = (gint)box_size - (offset-offset_start);
581
582     depth++;
583     if (depth > MP4_BOX_MAX_REC_LVL) {
584         proto_tree_add_expert(tree, pinfo, &ei_mp4_too_many_rec_lvls,
585                 tvb, offset_start, (gint)box_size);
586         return -1;
587     }
588
589     /* we do not dissect full box version and flags here
590        these two components are required by the function dissecting the body
591        some fields of the body depend on the version and flags */
592
593     /* XXX - check parent box if supplied */
594     switch (box_type) {
595         case BOX_TYPE_FTYP:
596             dissect_mp4_ftyp_body(tvb, offset, body_size, pinfo, depth, box_tree);
597             break;
598         case BOX_TYPE_MVHD:
599             dissect_mp4_mvhd_body(tvb, offset, body_size, pinfo, depth, box_tree);
600             break;
601         case BOX_TYPE_MFHD:
602             dissect_mp4_mfhd_body(tvb, offset, body_size, pinfo, depth, box_tree);
603             break;
604         case BOX_TYPE_TKHD:
605             dissect_mp4_tkhd_body(tvb, offset, body_size, pinfo, depth, box_tree);
606             break;
607         case BOX_TYPE_STSZ:
608             dissect_mp4_stsz_body(tvb, offset, body_size, pinfo, depth, box_tree);
609             break;
610         case BOX_TYPE_HDLR:
611             dissect_mp4_hdlr_body(tvb, offset, body_size, pinfo, depth, box_tree);
612             break;
613         case BOX_TYPE_DREF:
614             dissect_mp4_dref_body(tvb, offset, body_size, pinfo, depth, box_tree);
615             break;
616         case BOX_TYPE_URL_:
617             dissect_mp4_url_body(tvb, offset, body_size, pinfo, depth, box_tree);
618             break;
619         case BOX_TYPE_STSD:
620             dissect_mp4_stsd_body(tvb, offset, body_size, pinfo, depth, box_tree);
621             break;
622         case BOX_TYPE_MOOV:
623         case BOX_TYPE_MOOF:
624         case BOX_TYPE_STBL:
625         case BOX_TYPE_MDIA:
626         case BOX_TYPE_TRAK:
627         case BOX_TYPE_TRAF:
628         case BOX_TYPE_MINF:
629         case BOX_TYPE_MVEX:
630         case BOX_TYPE_DINF:
631         case BOX_TYPE_UDTA:
632             while (offset-offset_start < (gint)box_size) {
633                 ret = dissect_mp4_box(box_type, depth,
634                         tvb, offset, pinfo, box_tree);
635                 if (ret <= 0)
636                     break;
637                 offset += ret;
638             }
639             break;
640         default:
641             break;
642     }
643
644     return (gint)box_size;
645 }
646
647
648 static int
649 dissect_mp4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
650 {
651     gint        offset = 0;
652     guint32     box_type;
653     proto_item *pi;
654     proto_tree *mp4_tree;
655     gint        ret;
656
657     /* to make sure that we have an mp4 file, we check that it starts with
658         a box of a known type
659        please note that we do not allow the first box to be an extended box
660        this detection should be safe as long as the dissector is only called for
661         the video/mp4 mime type
662        when we read mp4 files directly, we might need stricter checks here */
663     if (tvb_reported_length(tvb) < MIN_BOX_SIZE)
664         return 0;
665     box_type = tvb_get_ntohl(tvb, 4);
666     if (try_val_to_str(box_type, box_types) == NULL)
667         return 0;
668
669     col_set_str(pinfo->cinfo, COL_PROTOCOL, "MP4");
670     col_clear(pinfo->cinfo, COL_INFO);
671
672     pi = proto_tree_add_protocol_format(tree, proto_mp4,
673             tvb, 0, (gint)tvb_reported_length(tvb), "MP4");
674     mp4_tree = proto_item_add_subtree(pi, ett_mp4);
675
676     while (tvb_reported_length_remaining(tvb, offset) > 0) {
677         ret = dissect_mp4_box(BOX_TYPE_NONE, 0, tvb, offset, pinfo, mp4_tree);
678         if (ret <= 0)
679             break;
680         offset += ret;
681     }
682
683     return offset;
684 }
685
686 void
687 proto_register_mp4(void)
688 {
689     static hf_register_info hf[] = {
690         { &hf_mp4_box_size,
691             { "Box size", "mp4.box.size", FT_UINT32, BASE_DEC,
692                 NULL, 0, NULL, HFILL } },
693         { &hf_mp4_box_type_str,
694             { "Box type", "mp4.box.type_str", FT_STRING, BASE_NONE,
695                 NULL, 0, NULL, HFILL } },
696         { &hf_mp4_box_largesize,
697             { "Box size (largesize)", "mp4.box.largesize", FT_UINT64, BASE_DEC,
698                 NULL, 0, NULL, HFILL } },
699         { &hf_mp4_full_box_ver,
700             { "Box version", "mp4.full_box.version", FT_UINT8, BASE_DEC,
701                 NULL, 0, NULL, HFILL } },
702         { &hf_mp4_full_box_flags,
703             { "Flags", "mp4.full_box.flags", FT_UINT24, BASE_HEX,
704                 NULL, 0, NULL, HFILL } },
705         { &hf_mp4_full_box_flags_media_data_location,
706             { "Media data location is defined in the movie box", "mp4.full_box.flags.media_data_location", FT_BOOLEAN, 24,
707                 NULL, ENTRY_FLAG_MOVIE, NULL, HFILL } },
708         { &hf_mp4_ftyp_brand,
709             { "Brand", "mp4.ftyp.brand", FT_STRING, BASE_NONE,
710                 NULL, 0, NULL, HFILL } },
711         { &hf_mp4_ftyp_ver,
712             { "Version", "mp4.ftyp.version", FT_UINT32, BASE_DEC,
713                 NULL, 0, NULL, HFILL } },
714         { &hf_mp4_ftyp_add_brand,
715             { "Additional brand", "mp4.ftyp.additional_brand", FT_STRING,
716                 BASE_NONE, NULL, 0, NULL, HFILL } },
717         { &hf_mp4_stsz_sample_size,
718             { "Sample size", "mp4.stsz.sample_size", FT_UINT32,
719                 BASE_DEC, NULL, 0, NULL, HFILL } },
720         { &hf_mp4_stsz_sample_count,
721             { "Sample count", "mp4.stsz.sample_count", FT_UINT32,
722                 BASE_DEC, NULL, 0, NULL, HFILL } },
723         { &hf_mp4_stsz_entry_size,
724             { "Entry size", "mp4.stsz.entry_size", FT_UINT32,
725                 BASE_DEC, NULL, 0, NULL, HFILL } },
726         { &hf_mp4_mvhd_creat_time,
727             { "Creation time", "mp4.mvhd.creation_time", FT_UINT64,
728                 BASE_DEC, NULL, 0, NULL, HFILL } },
729         { &hf_mp4_mvhd_mod_time,
730             { "Modification time", "mp4.mvhd.modification_time", FT_UINT64,
731                 BASE_DEC, NULL, 0, NULL, HFILL } },
732         { &hf_mp4_mvhd_timescale,
733             { "Timescale", "mp4.mvhd.timescale", FT_UINT32,
734                 BASE_DEC, NULL, 0, NULL, HFILL } },
735         { &hf_mp4_mvhd_duration,
736             { "Duration", "mp4.mvhd.duration", FT_UINT64,
737                 BASE_DEC, NULL, 0, NULL, HFILL } },
738         { &hf_mp4_mvhd_rate,
739             { "Rate", "mp4.mvhd.rate", FT_DOUBLE,
740                 BASE_NONE, NULL, 0, NULL, HFILL } },
741         { &hf_mp4_mvhd_vol,
742             { "Volume", "mp4.mvhd.volume", FT_DOUBLE,
743                 BASE_NONE, NULL, 0, NULL, HFILL } },
744         { &hf_mp4_mvhd_next_tid,
745             { "Next Track ID", "mp4.mvhd.next_track_id", FT_UINT32,
746                 BASE_HEX, NULL, 0, NULL, HFILL } },
747         { &hf_mp4_mfhd_seq_num,
748             { "Sequence number", "mp4.mfhd.sequence_number", FT_UINT32,
749                 BASE_DEC, NULL, 0, NULL, HFILL } },
750         { &hf_mp4_tkhd_creat_time,
751             { "Creation time", "mp4.tkhd.creation_time", FT_UINT64,
752                 BASE_DEC, NULL, 0, NULL, HFILL } },
753         { &hf_mp4_tkhd_mod_time,
754             { "Modification time", "mp4.tkhd.modification_time", FT_UINT64,
755                 BASE_DEC, NULL, 0, NULL, HFILL } },
756         { &hf_mp4_tkhd_track_id,
757             { "Track ID", "mp4.tkhd.track_id", FT_UINT32,
758                 BASE_DEC, NULL, 0, NULL, HFILL } },
759         { &hf_mp4_tkhd_duration,
760             { "Duration", "mp4.tkhd.duration", FT_UINT64,
761                 BASE_DEC, NULL, 0, NULL, HFILL } },
762         { &hf_mp4_tkhd_width,
763             { "Width", "mp4.tkhd.width", FT_DOUBLE,
764                 BASE_NONE, NULL, 0, NULL, HFILL } },
765         { &hf_mp4_tkhd_height,
766             { "Height", "mp4.tkhd.height", FT_DOUBLE,
767                 BASE_NONE, NULL, 0, NULL, HFILL } },
768         { &hf_mp4_hdlr_type,
769             { "Handler type", "mp4.hdlr.type", FT_STRING,
770                 BASE_NONE, NULL, 0, NULL, HFILL } },
771         { &hf_mp4_hdlr_name,
772             { "Handler name", "mp4.hdlr.name", FT_STRINGZ,
773                 BASE_NONE, NULL, 0, NULL, HFILL } },
774         { &hf_mp4_dref_entry_cnt,
775             { "Number of entries", "mp4.dref.entry_count", FT_UINT32,
776                 BASE_DEC, NULL, 0, NULL, HFILL } },
777         { &hf_mp4_stsd_entry_cnt,
778             { "Number of entries", "mp4.stsd.entry_count", FT_UINT32,
779                 BASE_DEC, NULL, 0, NULL, HFILL } }
780     };
781
782     static gint *ett[] = {
783         &ett_mp4,
784         &ett_mp4_box
785     };
786
787     static ei_register_info ei[] = {
788         { &ei_mp4_box_too_large,
789             { "mp4.box_too_large", PI_PROTOCOL, PI_WARN,
790                 "box size too large, dissection of this box is not supported", EXPFILL }},
791         { &ei_mp4_too_many_rec_lvls,
792             { "mp4.too_many_levels", PI_UNDECODED, PI_WARN,
793                 "too many recursion levels", EXPFILL }},
794         { &ei_mp4_mvhd_next_tid_unknown,
795             { "mp4.mvhd.next_tid_unknown", PI_PROTOCOL, PI_CHAT,
796                 "Next track ID is unknown. Search for an unused track ID if you want to insert a new track.", EXPFILL }}
797     };
798
799     expert_module_t *expert_mp4;
800
801     proto_mp4 = proto_register_protocol("MP4 / ISOBMFF file format", "mp4", "mp4");
802
803     proto_register_field_array(proto_mp4, hf, array_length(hf));
804     proto_register_subtree_array(ett, array_length(ett));
805     expert_mp4 = expert_register_protocol(proto_mp4);
806     expert_register_field_array(expert_mp4, ei, array_length(ei));
807 }
808
809 void
810 proto_reg_handoff_mp4(void)
811 {
812     dissector_handle_t mp4_handle = create_dissector_handle(dissect_mp4, proto_mp4);
813     dissector_add_string("media_type", "video/mp4", mp4_handle);
814     dissector_add_string("media_type", "audio/mp4", mp4_handle);
815 }
816
817
818 /*
819  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
820  *
821  * Local variables:
822  * c-basic-offset: 4
823  * tab-width: 8
824  * indent-tabs-mode: nil
825  * End:
826  *
827  * vi: set shiftwidth=4 tabstop=8 expandtab:
828  * :indentSize=4:tabSize=8:noTabs=true:
829  */