2 * routines for dissection of MP4 files
3 * Copyright 2013-2014, Martin Kaiser <martin@kaiser.cx>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
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)
16 * at the moment, it dissects the basic box structure and the payload of
17 * some simple boxes */
24 #include <epan/packet.h>
25 #include <epan/expert.h>
27 #define MAKE_TYPE_VAL(a, b, c, d) ((a)<<24 | (b)<<16 | (c)<<8 | (d))
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
35 void proto_register_mp4(void);
36 void proto_reg_handoff_mp4(void);
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);
41 static int proto_mp4 = -1;
43 static gint ett_mp4 = -1;
44 static gint ett_mp4_box = -1;
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;
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;
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
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 */
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', ' ')
126 /* the location for this URL box is the same as in the upper-level movie box */
127 #define ENTRY_FLAG_MOVIE 0x000001
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" },
166 /* convert a decimal number x into a double 0.x (e.g. 123 becomes 0.123) */
173 return (double)(x / exp(log(10.0)*(1+floor(log((double)x)/log(10.0)))));
177 dissect_mp4_mvhd_body(tvbuff_t *tvb, gint offset, gint len _U_,
178 packet_info *pinfo, guint depth _U_, proto_tree *tree)
186 proto_item *next_tid_it;
188 offset_start = offset;
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);
194 proto_tree_add_item(tree, hf_mp4_full_box_flags,
195 tvb, offset, 3, ENC_BIG_ENDIAN);
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);
202 proto_tree_add_item(tree, hf_mp4_mvhd_mod_time,
203 tvb, offset, time_len, ENC_BIG_ENDIAN);
205 proto_tree_add_item(tree, hf_mp4_mvhd_timescale,
206 tvb, offset, 4, ENC_BIG_ENDIAN);
208 proto_tree_add_item(tree, hf_mp4_mvhd_duration,
209 tvb, offset, time_len, ENC_BIG_ENDIAN);
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);
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);
224 offset += 2; /* 16 bits reserved */
225 offset += 2*4; /* 2 * uint32 reserved */
227 offset += 9*4; /* XXX - unity matrix */
228 offset += 6*4; /* 6 * 32 bits predefined = 0 */
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);
237 return offset-offset_start;
241 dissect_mp4_mfhd_body(tvbuff_t *tvb, gint offset, gint len _U_,
242 packet_info *pinfo _U_, guint depth _U_, proto_tree *tree)
246 offset_start = offset;
247 proto_tree_add_item(tree, hf_mp4_full_box_ver,
248 tvb, offset, 1, ENC_BIG_ENDIAN);
250 proto_tree_add_item(tree, hf_mp4_full_box_flags,
251 tvb, offset, 3, ENC_BIG_ENDIAN);
254 proto_tree_add_item(tree, hf_mp4_mfhd_seq_num,
255 tvb, offset, 4, ENC_BIG_ENDIAN);
258 return offset-offset_start;
263 dissect_mp4_tkhd_body(tvbuff_t *tvb, gint offset, gint len _U_,
264 packet_info *pinfo _U_, guint depth _U_, proto_tree *tree)
269 double width, height;
272 offset_start = offset;
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);
278 proto_tree_add_item(tree, hf_mp4_full_box_flags,
279 tvb, offset, 3, ENC_BIG_ENDIAN);
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);
286 proto_tree_add_item(tree, hf_mp4_tkhd_mod_time,
287 tvb, offset, time_len, ENC_BIG_ENDIAN);
290 proto_tree_add_item(tree, hf_mp4_tkhd_track_id,
291 tvb, offset, 4, ENC_BIG_ENDIAN);
294 offset += 4; /* 32bit reserved */
296 proto_tree_add_item(tree, hf_mp4_tkhd_duration,
297 tvb, offset, time_len, ENC_BIG_ENDIAN);
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 */
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);
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);
319 return offset-offset_start;
324 dissect_mp4_ftyp_body(tvbuff_t *tvb, gint offset, gint len,
325 packet_info *pinfo _U_, guint depth _U_, proto_tree *tree)
329 offset_start = offset;
330 proto_tree_add_item(tree, hf_mp4_ftyp_brand,
331 tvb, offset, 4, ENC_ASCII|ENC_NA);
333 proto_tree_add_item(tree, hf_mp4_ftyp_ver,
334 tvb, offset, 4, ENC_BIG_ENDIAN);
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);
343 return offset - offset_start;
348 dissect_mp4_stsz_body(tvbuff_t *tvb, gint offset, gint len _U_,
349 packet_info *pinfo _U_, guint depth _U_, proto_tree *tree)
352 guint32 sample_size, sample_count, i;
354 offset_start = offset;
355 sample_size = tvb_get_ntohl(tvb, offset);
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 */
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);
367 if (sample_size != 0)
368 return offset - offset_start;
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);
376 return offset - offset_start;
381 dissect_mp4_hdlr_body(tvbuff_t *tvb, gint offset, gint len _U_,
382 packet_info *pinfo _U_, guint depth _U_, proto_tree *tree)
387 offset_start = offset;
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 */
393 proto_tree_add_item(tree, hf_mp4_full_box_flags,
394 tvb, offset, 3, ENC_BIG_ENDIAN);
397 offset += 4; /* four reserved 0 bytes */
399 proto_tree_add_item(tree, hf_mp4_hdlr_type,
400 tvb, offset, 4, ENC_ASCII|ENC_NA);
403 offset += 12; /* 3x32bit reserved */
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;
411 return offset-offset_start;
416 dissect_mp4_dref_body(tvbuff_t *tvb, gint offset, gint len _U_,
417 packet_info *pinfo, guint depth, proto_tree *tree)
420 guint32 entry_cnt, i;
423 offset_start = offset;
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 */
429 proto_tree_add_item(tree, hf_mp4_full_box_flags,
430 tvb, offset, 3, ENC_BIG_ENDIAN);
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);
438 for(i=0; i<entry_cnt; i++) {
439 ret = dissect_mp4_box(BOX_TYPE_DREF, depth, tvb, offset, pinfo, tree);
446 return offset-offset_start;
451 dissect_mp4_url_body(tvbuff_t *tvb, gint offset, gint len,
452 packet_info *pinfo _U_, guint depth _U_, proto_tree *tree)
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 */
464 flags = tvb_get_ntoh24(tvb, offset);
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);
472 if (flags&ENTRY_FLAG_MOVIE) {
475 /* XXX - dissect location string */
484 dissect_mp4_stsd_body(tvbuff_t *tvb, gint offset, gint len,
485 packet_info *pinfo, guint depth, proto_tree *tree)
487 guint32 entry_cnt, i;
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 */
494 proto_tree_add_item(tree, hf_mp4_full_box_flags,
495 tvb, offset, 3, ENC_BIG_ENDIAN);
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);
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 */
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);
524 /* dissect a box, return its (standard or extended) length or 0 for error
525 depth is the recursion level of the parent box */
527 dissect_mp4_box(guint32 parent_box_type _U_, guint depth,
528 tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree)
533 guint8 *box_type_str;
534 proto_item *type_pi, *size_pi, *ext_size_pi = NULL;
535 proto_tree *box_tree;
540 offset_start = offset;
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 */
546 box_size = (guint64)tvb_get_ntohl(tvb, offset);
547 if ((box_size != BOX_SIZE_EXTENDED) && (box_size < MIN_BOX_SIZE))
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);
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);
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)");
563 proto_tree_add_item(box_tree, hf_mp4_box_type_str,
564 tvb, offset, 4, ENC_ASCII|ENC_NA);
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);
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);
579 proto_item_set_len(type_pi, (gint)box_size);
580 body_size = (gint)box_size - (offset-offset_start);
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);
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 */
593 /* XXX - check parent box if supplied */
596 dissect_mp4_ftyp_body(tvb, offset, body_size, pinfo, depth, box_tree);
599 dissect_mp4_mvhd_body(tvb, offset, body_size, pinfo, depth, box_tree);
602 dissect_mp4_mfhd_body(tvb, offset, body_size, pinfo, depth, box_tree);
605 dissect_mp4_tkhd_body(tvb, offset, body_size, pinfo, depth, box_tree);
608 dissect_mp4_stsz_body(tvb, offset, body_size, pinfo, depth, box_tree);
611 dissect_mp4_hdlr_body(tvb, offset, body_size, pinfo, depth, box_tree);
614 dissect_mp4_dref_body(tvb, offset, body_size, pinfo, depth, box_tree);
617 dissect_mp4_url_body(tvb, offset, body_size, pinfo, depth, box_tree);
620 dissect_mp4_stsd_body(tvb, offset, body_size, pinfo, depth, box_tree);
632 while (offset-offset_start < (gint)box_size) {
633 ret = dissect_mp4_box(box_type, depth,
634 tvb, offset, pinfo, box_tree);
644 return (gint)box_size;
649 dissect_mp4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
654 proto_tree *mp4_tree;
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)
665 box_type = tvb_get_ntohl(tvb, 4);
666 if (try_val_to_str(box_type, box_types) == NULL)
669 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MP4");
670 col_clear(pinfo->cinfo, COL_INFO);
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);
676 while (tvb_reported_length_remaining(tvb, offset) > 0) {
677 ret = dissect_mp4_box(BOX_TYPE_NONE, 0, tvb, offset, pinfo, mp4_tree);
687 proto_register_mp4(void)
689 static hf_register_info hf[] = {
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 } },
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 } },
739 { "Rate", "mp4.mvhd.rate", FT_DOUBLE,
740 BASE_NONE, NULL, 0, NULL, HFILL } },
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 } },
769 { "Handler type", "mp4.hdlr.type", FT_STRING,
770 BASE_NONE, NULL, 0, NULL, HFILL } },
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 } }
782 static gint *ett[] = {
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 }}
799 expert_module_t *expert_mp4;
801 proto_mp4 = proto_register_protocol("MP4 / ISOBMFF file format", "mp4", "mp4");
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));
810 proto_reg_handoff_mp4(void)
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);
819 * Editor modelines - http://www.wireshark.org/tools/modelines.html
824 * indent-tabs-mode: nil
827 * vi: set shiftwidth=4 tabstop=8 expandtab:
828 * :indentSize=4:tabSize=8:noTabs=true: