Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / file-mp4.c
blob62a09268e43e002b2bf89e696ae0243c09226317
1 /* file-mp4.c
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)
15 * 3GPP TS 26.244 (Adaptive-Streaming profile)
17 * at the moment, it dissects the basic box structure and the payload of
18 * some simple boxes */
21 #include "config.h"
23 #include <math.h>
25 #include <epan/packet.h>
26 #include <epan/to_str.h>
27 #include <epan/expert.h>
28 #include <wsutil/array.h>
29 #include <wiretap/wtap.h>
31 #define MAKE_TYPE_VAL(a, b, c, d) ((a)<<24 | (b)<<16 | (c)<<8 | (d))
33 /* Although the dissection of each box consumes a couple of bytes, it's
34 possible to craft a file whose boxes recurse so deeply that wireshark
35 crashes before we processed all data. Therefore, we limit the
36 recursion level for boxes to a reasonable depth. */
37 #define MP4_BOX_MAX_REC_LVL 20
39 void proto_register_mp4(void);
40 void proto_reg_handoff_mp4(void);
42 static dissector_handle_t mp4_handle;
44 static int dissect_mp4_box(uint32_t parent_box_type _U_, unsigned depth,
45 tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
47 static int proto_mp4;
49 static int ett_mp4;
50 static int ett_mp4_box;
51 static int ett_mp4_full_box_flags;
52 static int ett_mp4_entry;
54 static int hf_mp4_box_size;
55 static int hf_mp4_box_type_str;
56 static int hf_mp4_box_largesize;
57 static int hf_mp4_full_box_ver;
58 static int hf_mp4_full_box_flags;
59 static int hf_mp4_ftyp_brand;
60 static int hf_mp4_ftyp_ver;
61 static int hf_mp4_ftyp_add_brand;
62 static int hf_mp4_stsz_sample_size;
63 static int hf_mp4_stsz_sample_count;
64 static int hf_mp4_stsz_entry_size;
65 static int hf_mp4_stsc_entry_count;
66 static int hf_mp4_stsc_first_chunk;
67 static int hf_mp4_stsc_samples_per_chunk;
68 static int hf_mp4_stsc_sample_description_index;
69 static int hf_mp4_stco_entry_cnt;
70 static int hf_mp4_stco_chunk_offset;
71 static int hf_mp4_mvhd_creat_time;
72 static int hf_mp4_mvhd_mod_time;
73 static int hf_mp4_mvhd_timescale;
74 static int hf_mp4_mvhd_duration;
75 static int hf_mp4_mvhd_rate;
76 static int hf_mp4_mvhd_vol;
77 static int hf_mp4_mvhd_next_tid;
78 static int hf_mp4_mfhd_seq_num;
79 static int hf_mp4_tkhd_flags_enabled;
80 static int hf_mp4_tkhd_flags_in_movie;
81 static int hf_mp4_tkhd_flags_in_preview;
82 static int hf_mp4_tkhd_flags_size_is_aspect_ratio;
83 static int hf_mp4_tkhd_creat_time;
84 static int hf_mp4_tkhd_mod_time;
85 static int hf_mp4_tkhd_track_id;
86 static int hf_mp4_tkhd_duration;
87 static int hf_mp4_tkhd_width;
88 static int hf_mp4_tkhd_height;
89 static int hf_mp4_hdlr_type;
90 static int hf_mp4_hdlr_name;
91 static int hf_mp4_dref_entry_cnt;
92 static int hf_mp4_stsd_entry_cnt;
93 static int hf_mp4_url_flags_media_data_location;
94 static int hf_mp4_stts_entry_cnt;
95 static int hf_mp4_stts_sample_count;
96 static int hf_mp4_stts_sample_delta;
97 static int hf_mp4_ctts_sample_count;
98 static int hf_mp4_ctts_sample_offset_signed;
99 static int hf_mp4_ctts_sample_offset_unsigned;
100 static int hf_mp4_elst_entry_cnt;
101 static int hf_mp4_elst_segment_duration;
102 static int hf_mp4_elst_media_time;
103 static int hf_mp4_elst_media_rate_integer;
104 static int hf_mp4_elst_media_rate_fraction;
105 static int hf_mp4_sidx_reference_id;
106 static int hf_mp4_sidx_timescale;
107 static int hf_mp4_sidx_earliest_presentation_time_v0;
108 static int hf_mp4_sidx_first_offset_v0;
109 static int hf_mp4_sidx_earliest_presentation_time;
110 static int hf_mp4_sidx_first_offset;
111 static int hf_mp4_sidx_reserved;
112 static int hf_mp4_sidx_entry_cnt;
113 static int hf_mp4_sidx_reference_type;
114 static int hf_mp4_sidx_reference_size;
115 static int hf_mp4_sidx_subsegment_duration;
116 static int hf_mp4_sidx_starts_with_sap;
117 static int hf_mp4_sidx_sap_type;
118 static int hf_mp4_sidx_sap_delta_time;
120 static const value_string mp4_sidx_reference_type_vals[] = {
121 { 0, "Movie" },
122 { 1, "Index" },
124 { 0, NULL }
127 static expert_field ei_mp4_box_too_large;
128 static expert_field ei_mp4_too_many_rec_lvls;
129 static expert_field ei_mp4_mvhd_next_tid_unknown;
131 static uint32_t mvhd_timescale;
133 /* a box must at least have a 32bit len field and a 32bit type */
134 #define MIN_BOX_SIZE 8
135 /* an extended box has the first length field set to 1 */
136 #define BOX_SIZE_EXTENDED 1
138 /* the box type is stored as four text characters
139 it is in network byte order and contains only printable characters
140 for our internal handling, we convert this to a 32bit value */
142 #define BOX_TYPE_NONE 0x0 /* used for parent_box_type of a top-level box */
143 #define BOX_TYPE_FTYP MAKE_TYPE_VAL('f', 't', 'y', 'p')
144 #define BOX_TYPE_MOOV MAKE_TYPE_VAL('m', 'o', 'o', 'v')
145 #define BOX_TYPE_MVHD MAKE_TYPE_VAL('m', 'v', 'h', 'd')
146 #define BOX_TYPE_TRAK MAKE_TYPE_VAL('t', 'r', 'a', 'k')
147 #define BOX_TYPE_TKHD MAKE_TYPE_VAL('t', 'k', 'h', 'd')
148 #define BOX_TYPE_MDIA MAKE_TYPE_VAL('m', 'd', 'i', 'a')
149 #define BOX_TYPE_MDHD MAKE_TYPE_VAL('m', 'd', 'h', 'd')
150 #define BOX_TYPE_HDLR MAKE_TYPE_VAL('h', 'd', 'l', 'r')
151 #define BOX_TYPE_MINF MAKE_TYPE_VAL('m', 'i', 'n', 'f')
152 #define BOX_TYPE_VMHD MAKE_TYPE_VAL('v', 'm', 'h', 'd')
153 #define BOX_TYPE_SMHD MAKE_TYPE_VAL('s', 'm', 'h', 'd')
154 #define BOX_TYPE_DINF MAKE_TYPE_VAL('d', 'i', 'n', 'f')
155 #define BOX_TYPE_DREF MAKE_TYPE_VAL('d', 'r', 'e', 'f')
156 #define BOX_TYPE_STBL MAKE_TYPE_VAL('s', 't', 'b', 'l')
157 #define BOX_TYPE_STTS MAKE_TYPE_VAL('s', 't', 't', 's')
158 #define BOX_TYPE_CTTS MAKE_TYPE_VAL('c', 't', 't', 's')
159 #define BOX_TYPE_STSD MAKE_TYPE_VAL('s', 't', 's', 'd')
160 #define BOX_TYPE_STSZ MAKE_TYPE_VAL('s', 't', 's', 'z')
161 #define BOX_TYPE_STZ2 MAKE_TYPE_VAL('s', 't', 'z', '2')
162 #define BOX_TYPE_STSC MAKE_TYPE_VAL('s', 't', 's', 'c')
163 #define BOX_TYPE_STCO MAKE_TYPE_VAL('s', 't', 'c', 'o')
164 #define BOX_TYPE_STSS MAKE_TYPE_VAL('s', 't', 's', 's')
165 #define BOX_TYPE_MVEX MAKE_TYPE_VAL('m', 'v', 'e', 'x')
166 #define BOX_TYPE_MOOF MAKE_TYPE_VAL('m', 'o', 'o', 'f')
167 #define BOX_TYPE_MEHD MAKE_TYPE_VAL('m', 'e', 'h', 'd')
168 #define BOX_TYPE_TREX MAKE_TYPE_VAL('t', 'r', 'e', 'x')
169 #define BOX_TYPE_MFHD MAKE_TYPE_VAL('m', 'f', 'h', 'd')
170 #define BOX_TYPE_TRAF MAKE_TYPE_VAL('t', 'r', 'a', 'f')
171 #define BOX_TYPE_TFHD MAKE_TYPE_VAL('t', 'f', 'h', 'd')
172 #define BOX_TYPE_TRUN MAKE_TYPE_VAL('t', 'r', 'u', 'n')
173 #define BOX_TYPE_MDAT MAKE_TYPE_VAL('m', 'd', 'a', 't')
174 #define BOX_TYPE_UDTA MAKE_TYPE_VAL('u', 'd', 't', 'a')
175 /* the box name is url + <space>, all names must be 4 characters long */
176 #define BOX_TYPE_URL_ MAKE_TYPE_VAL('u', 'r', 'l', ' ')
177 #define BOX_TYPE_EDTS MAKE_TYPE_VAL('e', 'd', 't', 's')
178 #define BOX_TYPE_ELST MAKE_TYPE_VAL('e', 'l', 's', 't')
179 #define BOX_TYPE_SIDX MAKE_TYPE_VAL('s', 'i', 'd', 'x')
180 #define BOX_TYPE_STYP MAKE_TYPE_VAL('s', 't', 'y', 'p')
182 #define TKHD_FLAG_ENABLED 0x000001
183 #define TKHD_FLAG_IN_MOVIE 0x000002
184 #define TKHD_FLAG_IN_PREVIEW 0x000004
185 #define TKHD_FLAG_SIZE_IS_ASPECT_RATIO 0x000008
187 /* the location for this URL box is the same as in the upper-level movie box */
188 #define ENTRY_FLAG_MOVIE 0x000001
190 static const value_string box_types[] = {
191 { BOX_TYPE_FTYP, "File Type Box" },
192 { BOX_TYPE_MOOV, "Movie Box" },
193 { BOX_TYPE_MVHD, "Movie Header Box" },
194 { BOX_TYPE_TRAK, "Track Box" },
195 { BOX_TYPE_TKHD, "Track Header Box" },
196 { BOX_TYPE_MDIA, "Media Box" },
197 { BOX_TYPE_MDHD, "Media Header Box" },
198 { BOX_TYPE_HDLR, "Handler Reference Box" },
199 { BOX_TYPE_MINF, "Media Information Box" },
200 { BOX_TYPE_VMHD, "Video Media Header Box" },
201 { BOX_TYPE_SMHD, "Sound Media Header Box" },
202 { BOX_TYPE_DINF, "Data Information Box" },
203 { BOX_TYPE_DREF, "Data Reference Box" },
204 { BOX_TYPE_STBL, "Sample to Group Box" },
205 { BOX_TYPE_STTS, "Decoding Time To Sample Box" },
206 { BOX_TYPE_CTTS, "Composition Time To Sample Box" },
207 { BOX_TYPE_STSD, "Sample Description Box" },
208 { BOX_TYPE_STSZ, "Sample Size Box" },
209 { BOX_TYPE_STZ2, "Compact Sample Size Box" },
210 { BOX_TYPE_STSC, "Sample To Chunk Box" },
211 { BOX_TYPE_STCO, "Chunk Offset Box" },
212 { BOX_TYPE_STSS, "Sync Sample Table" },
213 { BOX_TYPE_MVEX, "Movie Extends Box" },
214 { BOX_TYPE_MOOF, "Movie Fragment Box" },
215 { BOX_TYPE_MEHD, "Movie Extends Header Box" },
216 { BOX_TYPE_TREX, "Track Extends Box" },
217 { BOX_TYPE_MFHD, "Movie Fragment Header Box" },
218 { BOX_TYPE_TRAF, "Track Fragment Box" },
219 { BOX_TYPE_TFHD, "Track Fragment Header Box" },
220 { BOX_TYPE_TRUN, "Track Fragment Run Box" },
221 { BOX_TYPE_MDAT, "Media Data Box" },
222 { BOX_TYPE_UDTA, "User Data Box" },
223 { BOX_TYPE_URL_, "URL Box" },
224 { BOX_TYPE_EDTS, "Edit Box" },
225 { BOX_TYPE_ELST, "Edit List Box" },
226 { BOX_TYPE_SIDX, "Segment Index Box"},
227 { BOX_TYPE_STYP, "Segment Type Box" },
228 { 0, NULL }
231 /* convert a decimal number x into a double 0.x (e.g. 123 becomes 0.123) */
232 static inline double
233 make_fract(unsigned x)
235 if (x==0)
236 return 0.0;
238 return (double)(x / exp(log(10.0)*(1+floor(log((double)x)/log(10.0)))));
241 static inline char *
242 timescaled_val_to_str(wmem_allocator_t *pool, uint64_t val)
244 nstime_t nstime;
246 if (mvhd_timescale == 0) {
247 return wmem_strdup(pool, "no timescale");
250 nstime.secs = val / mvhd_timescale;
251 nstime.nsecs = (val % mvhd_timescale) * (1000000000UL / mvhd_timescale);
252 return rel_time_to_str(pool, &nstime);
255 static int
256 dissect_mp4_full_box(tvbuff_t *tvb, int offset, proto_tree *tree,
257 int * const *flags_fields, uint8_t *version, uint32_t *flags)
259 if (version) {
260 *version = tvb_get_uint8(tvb, offset);
262 proto_tree_add_item(tree, hf_mp4_full_box_ver,
263 tvb, offset, 1, ENC_BIG_ENDIAN);
264 offset += 1;
266 if (flags) {
267 *flags = tvb_get_ntoh24(tvb, offset);
269 if (flags_fields) {
270 proto_tree_add_bitmask(tree, tvb, offset, hf_mp4_full_box_flags,
271 ett_mp4_full_box_flags, flags_fields, ENC_BIG_ENDIAN);
272 } else {
273 proto_tree_add_item(tree, hf_mp4_full_box_flags,
274 tvb, offset, 3, ENC_BIG_ENDIAN);
277 return 1 + 3;
280 static int
281 dissect_mp4_mvhd_body(tvbuff_t *tvb, int offset, int len _U_,
282 packet_info *pinfo, unsigned depth _U_, proto_tree *tree)
284 int offset_start;
285 uint8_t version;
286 uint8_t time_len;
287 uint64_t duration;
288 double rate, vol;
289 uint16_t fract_dec;
290 uint32_t next_tid;
291 proto_item *next_tid_it;
293 offset_start = offset;
295 offset += dissect_mp4_full_box (tvb, offset, tree, NULL, &version, NULL);
298 * MPEG-4 Part 14 (MP4) is based on QuickTime, so it uses the
299 * classic Mac OS time format.
301 time_len = (version==0) ? 4 : 8;
302 proto_tree_add_item(tree, hf_mp4_mvhd_creat_time,
303 tvb, offset, time_len, ENC_TIME_MP4_FILE_SECS|ENC_BIG_ENDIAN);
304 offset += time_len;
305 proto_tree_add_item(tree, hf_mp4_mvhd_mod_time,
306 tvb, offset, time_len, ENC_TIME_MP4_FILE_SECS|ENC_BIG_ENDIAN);
307 offset += time_len;
309 mvhd_timescale = tvb_get_ntohl (tvb, offset);
310 proto_tree_add_uint_format(tree, hf_mp4_mvhd_timescale,
311 tvb, offset, 4, mvhd_timescale, "Timescale: %d units in one second",
312 mvhd_timescale);
313 offset += 4;
315 if (time_len==4) {
316 duration = tvb_get_ntohl(tvb, offset);
317 } else {
318 duration = tvb_get_ntoh64(tvb , offset);
320 if (mvhd_timescale == 0) {
321 proto_tree_add_uint64_format(tree, hf_mp4_mvhd_duration,
322 tvb, offset, time_len, duration,
323 "Duration: no timescale (%" PRIu64 ")",
324 duration);
325 } else {
326 proto_tree_add_uint64_format(tree, hf_mp4_mvhd_duration,
327 tvb, offset, time_len, duration,
328 "Duration: %f seconds (%" PRIu64 ")",
329 (double) duration / mvhd_timescale, duration);
331 offset += time_len;
333 rate = tvb_get_ntohs(tvb, offset);
334 fract_dec = tvb_get_ntohs(tvb, offset+2);
335 rate += make_fract(fract_dec);
336 proto_tree_add_double(tree, hf_mp4_mvhd_rate, tvb, offset, 4, rate);
337 offset += 4;
339 vol = tvb_get_uint8(tvb, offset);
340 fract_dec = tvb_get_uint8(tvb, offset+1);
341 vol += make_fract(fract_dec);
342 proto_tree_add_double(tree, hf_mp4_mvhd_vol, tvb, offset, 4, vol);
343 offset += 2;
345 offset += 2; /* 16 bits reserved */
346 offset += 2*4; /* 2 * uint32 reserved */
348 offset += 9*4; /* XXX - unity matrix */
349 offset += 6*4; /* 6 * 32 bits predefined = 0 */
351 next_tid = tvb_get_ntohl(tvb, offset);
352 next_tid_it = proto_tree_add_item(tree, hf_mp4_mvhd_next_tid,
353 tvb, offset, 4, ENC_BIG_ENDIAN);
354 if (next_tid == UINT32_MAX)
355 expert_add_info(pinfo, next_tid_it, &ei_mp4_mvhd_next_tid_unknown);
356 offset += 4;
358 return offset-offset_start;
361 static int
362 dissect_mp4_mfhd_body(tvbuff_t *tvb, int offset, int len _U_,
363 packet_info *pinfo _U_, unsigned depth _U_, proto_tree *tree)
365 int offset_start;
367 offset_start = offset;
369 offset += dissect_mp4_full_box (tvb, offset, tree, NULL, NULL, NULL);
371 proto_tree_add_item(tree, hf_mp4_mfhd_seq_num,
372 tvb, offset, 4, ENC_BIG_ENDIAN);
373 offset += 4;
375 return offset-offset_start;
379 static int
380 dissect_mp4_tkhd_body(tvbuff_t *tvb, int offset, int len _U_,
381 packet_info *pinfo _U_, unsigned depth _U_, proto_tree *tree)
383 int offset_start;
384 uint8_t version;
385 uint8_t time_len;
386 double width, height;
387 uint16_t fract_dec;
388 static int * const flags[] = {
389 &hf_mp4_tkhd_flags_enabled,
390 &hf_mp4_tkhd_flags_in_movie,
391 &hf_mp4_tkhd_flags_in_preview,
392 &hf_mp4_tkhd_flags_size_is_aspect_ratio,
393 NULL
396 offset_start = offset;
398 offset += dissect_mp4_full_box (tvb, offset, tree, flags, &version, NULL);
400 time_len = (version==0) ? 4 : 8;
401 proto_tree_add_item(tree, hf_mp4_tkhd_creat_time,
402 tvb, offset, time_len, ENC_TIME_MP4_FILE_SECS|ENC_BIG_ENDIAN);
403 offset += time_len;
404 proto_tree_add_item(tree, hf_mp4_tkhd_mod_time,
405 tvb, offset, time_len, ENC_TIME_MP4_FILE_SECS|ENC_BIG_ENDIAN);
406 offset += time_len;
408 proto_tree_add_item(tree, hf_mp4_tkhd_track_id,
409 tvb, offset, 4, ENC_BIG_ENDIAN);
410 offset += 4;
412 offset += 4; /* 32bit reserved */
414 proto_tree_add_item(tree, hf_mp4_tkhd_duration,
415 tvb, offset, time_len, ENC_BIG_ENDIAN);
416 offset += time_len;
418 offset += 2*4; /* 2*32bit reserved */
419 offset += 2; /* 16bit layer */
420 offset += 2; /* 16bit alternate_group */
421 offset += 2; /* 16bit volume */
422 offset += 2; /* 16bit reserved */
423 offset += 9*4; /* 9*32bit matrix */
425 width = tvb_get_ntohs(tvb, offset);
426 fract_dec = tvb_get_ntohs(tvb, offset+2);
427 width += make_fract(fract_dec);
428 proto_tree_add_double(tree, hf_mp4_tkhd_width, tvb, offset, 4, width);
429 offset += 4;
431 height = tvb_get_ntohs(tvb, offset);
432 fract_dec = tvb_get_ntohs(tvb, offset+2);
433 height += make_fract(fract_dec);
434 proto_tree_add_double(tree, hf_mp4_tkhd_height, tvb, offset, 4, height);
435 offset += 4;
437 return offset-offset_start;
441 static int
442 dissect_mp4_ftyp_body(tvbuff_t *tvb, int offset, int len,
443 packet_info *pinfo _U_, unsigned depth _U_, proto_tree *tree)
445 int offset_start;
447 offset_start = offset;
448 proto_tree_add_item(tree, hf_mp4_ftyp_brand,
449 tvb, offset, 4, ENC_ASCII);
450 offset += 4;
451 proto_tree_add_item(tree, hf_mp4_ftyp_ver,
452 tvb, offset, 4, ENC_BIG_ENDIAN);
453 offset += 4;
455 while ((offset-offset_start) < len) {
456 proto_tree_add_item(tree, hf_mp4_ftyp_add_brand,
457 tvb, offset, 4, ENC_ASCII);
458 offset += 4;
461 return offset - offset_start;
465 static int
466 dissect_mp4_stsz_body(tvbuff_t *tvb, int offset, int len _U_,
467 packet_info *pinfo _U_, unsigned depth _U_, proto_tree *tree)
469 int offset_start;
470 uint32_t sample_size, sample_count, i;
472 offset_start = offset;
474 offset += dissect_mp4_full_box (tvb, offset, tree, NULL, NULL, NULL);
476 sample_size = tvb_get_ntohl(tvb, offset);
478 proto_tree_add_uint_format(tree, hf_mp4_stsz_sample_size,
479 tvb, offset, 4, sample_size, "Sample size: %u%s", sample_size,
480 sample_size == 0 ? " (samples have different sizes)" : "");
481 /* XXX - expert info for sample size == 0 */
482 offset += 4;
484 sample_count = tvb_get_ntohl(tvb, offset);
485 proto_tree_add_item(tree, hf_mp4_stsz_sample_count,
486 tvb, offset, 4, ENC_BIG_ENDIAN);
487 offset += 4;
489 if (sample_size != 0)
490 return offset - offset_start;
492 for (i=1; i<=sample_count; i++) {
493 uint32_t entry_size;
495 entry_size = tvb_get_ntohl(tvb, offset);
496 proto_tree_add_uint_format(tree, hf_mp4_stsz_entry_size,
497 tvb, offset, 4, entry_size, "Entry %u: Entry size: %u", i,
498 entry_size);
499 offset += 4;
502 return offset - offset_start;
506 static int
507 dissect_mp4_stsc_body(tvbuff_t *tvb, int offset, int len,
508 packet_info *pinfo _U_, unsigned depth _U_, proto_tree *tree)
510 uint32_t entry_count;
511 uint32_t i;
513 offset += dissect_mp4_full_box (tvb, offset, tree, NULL, NULL, NULL);
515 proto_tree_add_item_ret_uint(tree, hf_mp4_stsc_entry_count, tvb, offset, 4,
516 ENC_BIG_ENDIAN, &entry_count);
517 offset += 4;
519 for (i=1; i<=entry_count; i++) {
520 proto_tree *subtree;
521 proto_item *subtree_item;
522 uint32_t first_chunk;
523 uint32_t samples_per_chunk;
524 uint32_t sample_description_index;
526 subtree = proto_tree_add_subtree_format (tree, tvb, offset, 3 * 4,
527 ett_mp4_entry, &subtree_item, "Entry %u:", i);
529 proto_tree_add_item_ret_uint(subtree, hf_mp4_stsc_first_chunk,
530 tvb, offset, 4, ENC_BIG_ENDIAN, &first_chunk);
531 offset += 4;
533 proto_tree_add_item_ret_uint(subtree, hf_mp4_stsc_samples_per_chunk,
534 tvb, offset, 4, ENC_BIG_ENDIAN, &samples_per_chunk);
535 offset += 4;
537 proto_tree_add_item_ret_uint(subtree, hf_mp4_stsc_sample_description_index,
538 tvb, offset, 4, ENC_BIG_ENDIAN, &sample_description_index);
539 offset += 4;
541 proto_item_append_text (subtree_item,
542 " First chunk: %u; Samples per chunk: %u; Sample description index: %u",
543 first_chunk, samples_per_chunk, sample_description_index);
546 return len;
550 static int
551 dissect_mp4_hdlr_body(tvbuff_t *tvb, int offset, int len _U_,
552 packet_info *pinfo _U_, unsigned depth _U_, proto_tree *tree)
554 int offset_start;
555 unsigned hdlr_name_len;
557 offset_start = offset;
559 offset += dissect_mp4_full_box (tvb, offset, tree, NULL, NULL, NULL);
560 /* XXX - put up an expert info if version!=0 */
562 offset += 4; /* four reserved 0 bytes */
564 proto_tree_add_item(tree, hf_mp4_hdlr_type,
565 tvb, offset, 4, ENC_ASCII);
566 offset += 4;
568 offset += 12; /* 3x32bit reserved */
570 /* name is a 0-terminated UTF-8 string, len includes the final 0 */
571 hdlr_name_len = tvb_strsize(tvb, offset);
572 proto_tree_add_item(tree, hf_mp4_hdlr_name,
573 tvb, offset, hdlr_name_len, ENC_UTF_8);
574 offset += hdlr_name_len;
576 return offset-offset_start;
580 static int
581 // NOLINTNEXTLINE(misc-no-recursion)
582 dissect_mp4_dref_body(tvbuff_t *tvb, int offset, int len _U_,
583 packet_info *pinfo, unsigned depth, proto_tree *tree)
585 int offset_start;
586 uint32_t entry_cnt, i;
587 int ret;
589 offset_start = offset;
591 offset += dissect_mp4_full_box (tvb, offset, tree, NULL, NULL, NULL);
592 /* XXX - put up an expert info if version!=0 */
594 entry_cnt = tvb_get_ntohl(tvb, offset);
595 proto_tree_add_item(tree, hf_mp4_dref_entry_cnt,
596 tvb, offset, 4, ENC_BIG_ENDIAN);
597 offset += 4;
599 for(i=0; i<entry_cnt; i++) {
600 ret = dissect_mp4_box(BOX_TYPE_DREF, depth, tvb, offset, pinfo, tree);
601 if (ret<=0)
602 break;
604 offset += ret;
607 return offset-offset_start;
611 static int
612 dissect_mp4_url_body(tvbuff_t *tvb, int offset, int len,
613 packet_info *pinfo _U_, unsigned depth _U_, proto_tree *tree)
615 uint32_t flags;
616 static int * const flags_fields[] = {
617 &hf_mp4_url_flags_media_data_location,
618 NULL
621 dissect_mp4_full_box (tvb, offset, tree, flags_fields, NULL,
622 &flags);
623 /* XXX - put up an expert info if version!=0 */
625 #if 0
626 if (flags&ENTRY_FLAG_MOVIE) {
628 else {
629 /* XXX - dissect location string */
631 #endif
633 return len;
637 static int
638 // NOLINTNEXTLINE(misc-no-recursion)
639 dissect_mp4_stsd_body(tvbuff_t *tvb, int offset, int len,
640 packet_info *pinfo, unsigned depth, proto_tree *tree)
642 uint32_t entry_cnt, i;
643 int ret;
645 offset += dissect_mp4_full_box (tvb, offset, tree, NULL, NULL, NULL);
646 /* XXX - put up an expert info if version!=0 */
648 entry_cnt = tvb_get_ntohl(tvb, offset);
649 proto_tree_add_item(tree, hf_mp4_stsd_entry_cnt,
650 tvb, offset, 4, ENC_BIG_ENDIAN);
651 offset += 4;
653 for(i=0; i<entry_cnt; i++) {
654 /* a sample entry has the same format as an mp4 box
655 we call dissect_mp4_box() to dissect it
656 alternatively, we could parse it ourselves, we'd then have to
657 handle the extended lengths etc */
659 /* XXX - dissect the content of each Sample Entry,
660 this depends on the handler_type, we could add an optional
661 void *data parameter to dissect_mp4_box() and handle sample
662 entry boxes based on parent box and data parameter */
663 ret = dissect_mp4_box(BOX_TYPE_STSD, depth, tvb, offset, pinfo, tree);
664 if (ret<=0)
665 break;
667 offset += ret;
670 return len;
673 static int
674 dissect_mp4_stts_body(tvbuff_t *tvb, int offset, int len,
675 packet_info *pinfo _U_, unsigned depth _U_, proto_tree *tree)
677 uint32_t entry_cnt;
678 unsigned i;
680 offset += dissect_mp4_full_box (tvb, offset, tree, NULL, NULL, NULL);
682 proto_tree_add_item_ret_uint(tree, hf_mp4_stts_entry_cnt,
683 tvb, offset, 4, ENC_BIG_ENDIAN, &entry_cnt);
684 offset += 4;
686 for(i=0; i<entry_cnt; i++) {
687 proto_tree *subtree;
688 proto_item *subtree_item;
689 uint32_t sample_count;
690 uint32_t sample_delta;
692 subtree = proto_tree_add_subtree_format (tree, tvb, offset, 2 * 4,
693 ett_mp4_entry, &subtree_item, "Entry %u:", i + 1);
695 proto_tree_add_item_ret_uint(subtree, hf_mp4_stts_sample_count,
696 tvb, offset, 4, ENC_BIG_ENDIAN, &sample_count);
697 offset += 4;
699 proto_tree_add_item_ret_uint(subtree, hf_mp4_stts_sample_delta,
700 tvb, offset, 4, ENC_BIG_ENDIAN, &sample_delta);
701 offset += 4;
703 proto_item_append_text (subtree_item,
704 " Sample count: %u, Sample delta: %d",
705 sample_count, sample_delta);
708 return len;
712 static int
713 dissect_mp4_stco_body(tvbuff_t *tvb, int offset, int len,
714 packet_info *pinfo _U_, unsigned depth _U_, proto_tree *tree)
716 uint32_t entry_cnt;
717 uint32_t i;
719 offset += dissect_mp4_full_box (tvb, offset, tree, NULL, NULL, NULL);
721 proto_tree_add_item_ret_uint(tree, hf_mp4_stco_entry_cnt,
722 tvb, offset, 4, ENC_BIG_ENDIAN, &entry_cnt);
723 offset += 4;
725 for(i=1; i<=entry_cnt; i++) {
726 uint32_t chunk_offset;
728 chunk_offset = tvb_get_ntohl(tvb, offset);
729 proto_tree_add_uint_format(tree, hf_mp4_stco_chunk_offset,
730 tvb, offset, 4, chunk_offset, "Entry %u: Chunk offset %u", i,
731 chunk_offset);
732 offset += 4;
735 return len;
739 static int
740 dissect_mp4_ctts_body(tvbuff_t *tvb, int offset, int len,
741 packet_info *pinfo _U_, unsigned depth _U_, proto_tree *tree)
743 uint8_t version;
744 uint32_t entry_cnt;
745 int sample_offset_hf;
746 unsigned i;
748 offset += dissect_mp4_full_box (tvb, offset, tree, NULL, &version, NULL);
750 proto_tree_add_item_ret_uint(tree, hf_mp4_stts_entry_cnt,
751 tvb, offset, 4, ENC_BIG_ENDIAN, &entry_cnt);
752 offset += 4;
754 sample_offset_hf = (version==1) ? hf_mp4_ctts_sample_offset_signed :
755 hf_mp4_ctts_sample_offset_unsigned;
757 for (i=0; i<entry_cnt; i++) {
758 proto_tree *subtree;
759 proto_item *subtree_item;
760 uint32_t sample_count;
761 uint32_t sample_delta;
763 subtree = proto_tree_add_subtree_format(tree, tvb, offset, 2 * 4,
764 ett_mp4_entry, &subtree_item, "Entry %u:", i + 1);
766 proto_tree_add_item_ret_uint(subtree, hf_mp4_ctts_sample_count,
767 tvb, offset, 4, ENC_BIG_ENDIAN, &sample_count);
768 offset += 4;
770 proto_tree_add_item_ret_uint(subtree, sample_offset_hf,
771 tvb, offset, 4, ENC_BIG_ENDIAN, &sample_delta);
772 offset += 4;
774 proto_item_append_text(subtree_item,
775 " Sample count: %u, Sample offset: %d",
776 sample_count, sample_delta);
779 return len;
782 static int
783 dissect_mp4_elst_body(tvbuff_t *tvb, int offset, int len,
784 packet_info *pinfo, unsigned depth _U_, proto_tree *tree)
786 uint8_t version;
787 uint32_t entry_cnt;
788 unsigned i;
790 offset += dissect_mp4_full_box (tvb, offset, tree, NULL, &version, NULL);
792 proto_tree_add_item_ret_uint(tree, hf_mp4_elst_entry_cnt,
793 tvb, offset, 4, ENC_BIG_ENDIAN, &entry_cnt);
794 offset += 4;
796 for(i=0; i<entry_cnt; i++) {
797 proto_tree *subtree;
798 proto_item *subtree_item;
799 int field_length;
800 uint64_t segment_duration;
801 char *segment_duration_str;
802 int64_t media_time;
803 char *media_time_str;
804 int32_t rate_int;
805 int32_t rate_fraction;
807 subtree = proto_tree_add_subtree_format (tree, tvb, offset, 2 * 4,
808 ett_mp4_entry, &subtree_item, "Entry %u:", i + 1);
810 field_length = (version==1) ? 8 : 4;
812 if (version==1) {
813 segment_duration = tvb_get_ntoh64(tvb, offset);
814 } else {
815 segment_duration = tvb_get_ntohl(tvb, offset);
817 segment_duration_str = timescaled_val_to_str(pinfo->pool, segment_duration);
818 proto_tree_add_uint64_format(subtree, hf_mp4_elst_segment_duration,
819 tvb, offset, field_length, segment_duration,
820 "Segment duration: %s (%" PRIu64 ")",
821 segment_duration_str, segment_duration);
822 offset += field_length;
824 if (version==1) {
825 media_time = tvb_get_ntoh64(tvb, offset);
826 } else {
827 media_time = tvb_get_ntohl(tvb, offset);
829 media_time_str = timescaled_val_to_str(pinfo->pool, media_time);
830 proto_tree_add_int64_format(subtree, hf_mp4_elst_media_time,
831 tvb, offset, field_length, media_time,
832 "Media time: %s (%" PRId64 ")",
833 media_time_str, media_time);
834 offset += field_length;
836 proto_tree_add_item_ret_int(subtree, hf_mp4_elst_media_rate_integer,
837 tvb, offset, 2, ENC_BIG_ENDIAN, &rate_int);
838 offset += 2;
840 proto_tree_add_item_ret_int(subtree, hf_mp4_elst_media_rate_fraction,
841 tvb, offset, 2, ENC_BIG_ENDIAN, &rate_fraction);
842 offset += 2;
844 proto_item_append_text (subtree_item,
845 " Segment duration: %s; Media time: %s; Media rate: %d.%d",
846 segment_duration_str, media_time_str, rate_int, rate_fraction);
849 return len;
852 /* 3GPP TS 26.244 version 16.1.0 Release 16: 13.4 Segment Index Box */
853 static int
854 dissect_mp4_sidx_body(tvbuff_t *tvb, int offset, int len _U_,
855 packet_info *pinfo _U_, unsigned depth _U_, proto_tree *tree)
857 uint8_t version;
858 int offset_start;
859 uint16_t entry_cnt, i;
861 offset_start = offset;
863 offset += dissect_mp4_full_box (tvb, offset, tree, NULL, &version, NULL);
865 proto_tree_add_item(tree, hf_mp4_sidx_reference_id,
866 tvb, offset, 4, ENC_BIG_ENDIAN);
867 offset += 4;
869 proto_tree_add_item(tree, hf_mp4_sidx_timescale,
870 tvb, offset, 4, ENC_BIG_ENDIAN);
871 offset += 4;
873 if (version == 0) {
874 proto_tree_add_item(tree, hf_mp4_sidx_earliest_presentation_time_v0,
875 tvb, offset, 4, ENC_BIG_ENDIAN);
876 offset += 4;
878 proto_tree_add_item(tree, hf_mp4_sidx_first_offset_v0,
879 tvb, offset, 4, ENC_BIG_ENDIAN);
880 offset += 4;
881 } else {
882 proto_tree_add_item(tree, hf_mp4_sidx_earliest_presentation_time,
883 tvb, offset, 8, ENC_BIG_ENDIAN);
884 offset += 8;
886 proto_tree_add_item(tree, hf_mp4_sidx_first_offset,
887 tvb, offset, 8, ENC_BIG_ENDIAN);
888 offset += 8;
891 proto_tree_add_item(tree, hf_mp4_sidx_reserved,
892 tvb, offset, 2, ENC_BIG_ENDIAN);
893 offset += 2;
895 entry_cnt = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
896 proto_tree_add_item(tree, hf_mp4_sidx_entry_cnt,
897 tvb, offset, 2, ENC_BIG_ENDIAN);
898 offset += 2;
900 for(i=1; i<=entry_cnt; i++) {
901 proto_tree *subtree;
902 proto_item *subtree_item;
904 subtree = proto_tree_add_subtree_format (tree, tvb, offset, 8,
905 ett_mp4_entry, &subtree_item, "Entry %u:", i);
907 proto_tree_add_item(subtree, hf_mp4_sidx_reference_type,
908 tvb, offset, 4, ENC_BIG_ENDIAN);
909 proto_tree_add_item(subtree, hf_mp4_sidx_reference_size,
910 tvb, offset, 4, ENC_BIG_ENDIAN);
911 offset += 4;
913 proto_tree_add_item(subtree, hf_mp4_sidx_subsegment_duration,
914 tvb, offset, 4, ENC_BIG_ENDIAN);
915 offset += 4;
917 proto_tree_add_item(subtree, hf_mp4_sidx_starts_with_sap,
918 tvb, offset, 4, ENC_BIG_ENDIAN);
919 proto_tree_add_item(subtree, hf_mp4_sidx_sap_type,
920 tvb, offset, 4, ENC_BIG_ENDIAN);
921 proto_tree_add_item(subtree, hf_mp4_sidx_sap_delta_time,
922 tvb, offset, 4, ENC_BIG_ENDIAN);
923 offset += 4;
926 return offset-offset_start;
929 /* dissect a box, return its (standard or extended) length or 0 for error
930 depth is the recursion level of the parent box */
931 static int
932 // NOLINTNEXTLINE(misc-no-recursion)
933 dissect_mp4_box(uint32_t parent_box_type _U_, unsigned depth,
934 tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
936 int offset_start;
937 uint64_t box_size;
938 uint32_t box_type;
939 uint8_t *box_type_str;
940 proto_item *type_pi, *size_pi, *ext_size_pi = NULL;
941 proto_tree *box_tree;
942 int ret;
943 int body_size;
946 offset_start = offset;
948 /* the following mechanisms are not supported for now
949 - size==0, indicating that the box extends to the end of the file
950 - extended box types */
952 box_size = (uint64_t)tvb_get_ntohl(tvb, offset);
953 if ((box_size != BOX_SIZE_EXTENDED) && (box_size < MIN_BOX_SIZE))
954 return -1;
956 box_type = tvb_get_ntohl(tvb, offset+4);
957 box_type_str = tvb_get_string_enc(pinfo->pool, tvb,
958 offset+4, 4, ENC_ASCII|ENC_NA);
960 box_tree = proto_tree_add_subtree_format(tree, tvb, offset, -1, ett_mp4_box, &type_pi, "%s (%s)",
961 val_to_str_const(box_type, box_types, "unknown"), box_type_str);
963 size_pi = proto_tree_add_item(box_tree, hf_mp4_box_size,
964 tvb, offset, 4, ENC_BIG_ENDIAN);
965 if (box_size == BOX_SIZE_EXTENDED)
966 proto_item_append_text(size_pi, " (actual size is in largesize)");
968 offset += 4;
969 proto_tree_add_item(box_tree, hf_mp4_box_type_str,
970 tvb, offset, 4, ENC_ASCII);
971 offset += 4;
973 if (box_size == BOX_SIZE_EXTENDED) {
974 box_size = tvb_get_ntoh64(tvb, offset);
975 ext_size_pi = proto_tree_add_item(box_tree, hf_mp4_box_largesize,
976 tvb, offset, 8, ENC_BIG_ENDIAN);
977 offset += 8;
980 if (box_size > INT_MAX) {
981 /* this should be ok for ext_size_pi==NULL */
982 expert_add_info(pinfo, ext_size_pi, &ei_mp4_box_too_large);
983 return -1;
985 proto_item_set_len(type_pi, (int)box_size);
986 body_size = (int)box_size - (offset-offset_start);
988 depth++;
989 if (depth > MP4_BOX_MAX_REC_LVL) {
990 proto_tree_add_expert(tree, pinfo, &ei_mp4_too_many_rec_lvls,
991 tvb, offset_start, (int)box_size);
992 return -1;
995 /* we do not dissect full box version and flags here
996 these two components are required by the function dissecting the body
997 some fields of the body depend on the version and flags */
999 /* XXX - check parent box if supplied */
1000 switch (box_type) {
1001 /* As per 3GPP TS 26.244 styp and ftyp boxes have the same format*/
1002 case BOX_TYPE_FTYP:
1003 case BOX_TYPE_STYP:
1004 dissect_mp4_ftyp_body(tvb, offset, body_size, pinfo, depth, box_tree);
1005 break;
1006 case BOX_TYPE_MVHD:
1007 dissect_mp4_mvhd_body(tvb, offset, body_size, pinfo, depth, box_tree);
1008 break;
1009 case BOX_TYPE_MFHD:
1010 dissect_mp4_mfhd_body(tvb, offset, body_size, pinfo, depth, box_tree);
1011 break;
1012 case BOX_TYPE_TKHD:
1013 dissect_mp4_tkhd_body(tvb, offset, body_size, pinfo, depth, box_tree);
1014 break;
1015 case BOX_TYPE_STSZ:
1016 dissect_mp4_stsz_body(tvb, offset, body_size, pinfo, depth, box_tree);
1017 break;
1018 case BOX_TYPE_STSC:
1019 dissect_mp4_stsc_body(tvb, offset, body_size, pinfo, depth, box_tree);
1020 break;
1021 case BOX_TYPE_HDLR:
1022 dissect_mp4_hdlr_body(tvb, offset, body_size, pinfo, depth, box_tree);
1023 break;
1024 case BOX_TYPE_DREF:
1025 dissect_mp4_dref_body(tvb, offset, body_size, pinfo, depth, box_tree);
1026 break;
1027 case BOX_TYPE_URL_:
1028 dissect_mp4_url_body(tvb, offset, body_size, pinfo, depth, box_tree);
1029 break;
1030 case BOX_TYPE_STSD:
1031 dissect_mp4_stsd_body(tvb, offset, body_size, pinfo, depth, box_tree);
1032 break;
1033 case BOX_TYPE_STTS:
1034 dissect_mp4_stts_body(tvb, offset, body_size, pinfo, depth, box_tree);
1035 break;
1036 case BOX_TYPE_STCO:
1037 dissect_mp4_stco_body(tvb, offset, body_size, pinfo, depth, box_tree);
1038 break;
1039 case BOX_TYPE_CTTS:
1040 dissect_mp4_ctts_body(tvb, offset, body_size, pinfo, depth, box_tree);
1041 break;
1042 case BOX_TYPE_ELST:
1043 dissect_mp4_elst_body(tvb, offset, body_size, pinfo, depth, box_tree);
1044 break;
1045 case BOX_TYPE_SIDX:
1046 dissect_mp4_sidx_body(tvb, offset, body_size, pinfo, depth, box_tree);
1047 break;
1048 case BOX_TYPE_MOOV:
1049 case BOX_TYPE_MOOF:
1050 case BOX_TYPE_STBL:
1051 case BOX_TYPE_MDIA:
1052 case BOX_TYPE_TRAK:
1053 case BOX_TYPE_TRAF:
1054 case BOX_TYPE_MINF:
1055 case BOX_TYPE_MVEX:
1056 case BOX_TYPE_DINF:
1057 case BOX_TYPE_UDTA:
1058 case BOX_TYPE_EDTS:
1059 while (offset-offset_start < (int)box_size) {
1060 ret = dissect_mp4_box(box_type, depth,
1061 tvb, offset, pinfo, box_tree);
1062 if (ret <= 0)
1063 break;
1064 offset += ret;
1066 break;
1067 default:
1068 break;
1071 return (int)box_size;
1075 static int
1076 dissect_mp4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1078 int offset = 0;
1079 uint32_t box_type;
1080 proto_item *pi;
1081 proto_tree *mp4_tree;
1082 int ret;
1084 /* to make sure that we have an mp4 file, we check that it starts with
1085 a box of a known type
1086 please note that we do not allow the first box to be an extended box
1087 this detection should be safe as long as the dissector is only called for
1088 the video/mp4 mime type
1089 when we read mp4 files directly, we might need stricter checks here */
1090 if (tvb_reported_length(tvb) < MIN_BOX_SIZE)
1091 return 0;
1092 box_type = tvb_get_ntohl(tvb, 4);
1093 if (try_val_to_str(box_type, box_types) == NULL)
1094 return 0;
1096 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MP4");
1097 col_clear(pinfo->cinfo, COL_INFO);
1099 pi = proto_tree_add_protocol_format(tree, proto_mp4,
1100 tvb, 0, (int)tvb_reported_length(tvb), "MP4");
1101 mp4_tree = proto_item_add_subtree(pi, ett_mp4);
1103 while (tvb_reported_length_remaining(tvb, offset) > 0) {
1104 ret = dissect_mp4_box(BOX_TYPE_NONE, 0, tvb, offset, pinfo, mp4_tree);
1105 if (ret <= 0)
1106 break;
1107 offset += ret;
1110 return offset;
1113 void
1114 proto_register_mp4(void)
1116 static hf_register_info hf[] = {
1117 { &hf_mp4_box_size,
1118 { "Box size", "mp4.box.size", FT_UINT32, BASE_DEC,
1119 NULL, 0, NULL, HFILL } },
1120 { &hf_mp4_box_type_str,
1121 { "Box type", "mp4.box.type_str", FT_STRING, BASE_NONE,
1122 NULL, 0, NULL, HFILL } },
1123 { &hf_mp4_box_largesize,
1124 { "Box size (largesize)", "mp4.box.largesize", FT_UINT64, BASE_DEC,
1125 NULL, 0, NULL, HFILL } },
1126 { &hf_mp4_full_box_ver,
1127 { "Box version", "mp4.full_box.version", FT_UINT8, BASE_DEC,
1128 NULL, 0, NULL, HFILL } },
1129 { &hf_mp4_full_box_flags,
1130 { "Flags", "mp4.full_box.flags", FT_UINT24, BASE_HEX,
1131 NULL, 0, NULL, HFILL } },
1132 { &hf_mp4_ftyp_brand,
1133 { "Brand", "mp4.ftyp.brand", FT_STRING, BASE_NONE,
1134 NULL, 0, NULL, HFILL } },
1135 { &hf_mp4_ftyp_ver,
1136 { "Version", "mp4.ftyp.version", FT_UINT32, BASE_DEC,
1137 NULL, 0, NULL, HFILL } },
1138 { &hf_mp4_ftyp_add_brand,
1139 { "Additional brand", "mp4.ftyp.additional_brand", FT_STRING,
1140 BASE_NONE, NULL, 0, NULL, HFILL } },
1141 { &hf_mp4_stsz_sample_size,
1142 { "Sample size", "mp4.stsz.sample_size", FT_UINT32,
1143 BASE_DEC, NULL, 0, NULL, HFILL } },
1144 { &hf_mp4_stsz_sample_count,
1145 { "Sample count", "mp4.stsz.sample_count", FT_UINT32,
1146 BASE_DEC, NULL, 0, NULL, HFILL } },
1147 { &hf_mp4_stsz_entry_size,
1148 { "Entry size", "mp4.stsz.entry_size", FT_UINT32,
1149 BASE_DEC, NULL, 0, NULL, HFILL } },
1150 { &hf_mp4_stsc_entry_count,
1151 { "Entry size", "mp4.stsc.entry_count", FT_UINT32,
1152 BASE_DEC, NULL, 0, NULL, HFILL } },
1153 { &hf_mp4_stsc_first_chunk,
1154 { "First chunk", "mp4.stsc.first_chunk", FT_UINT32,
1155 BASE_DEC, NULL, 0, NULL, HFILL } },
1156 { &hf_mp4_stsc_samples_per_chunk,
1157 { "Samples per chunk", "mp4.stsc.samples_per_chunk", FT_UINT32,
1158 BASE_DEC, NULL, 0, NULL, HFILL } },
1159 { &hf_mp4_stsc_sample_description_index,
1160 { "Sample description index", "mp4.stsc.sample_description_index", FT_UINT32,
1161 BASE_DEC, NULL, 0, NULL, HFILL } },
1162 { &hf_mp4_stco_entry_cnt,
1163 { "Entry count", "mp4.stco.entry_count", FT_UINT32,
1164 BASE_DEC, NULL, 0, NULL, HFILL } },
1165 { &hf_mp4_stco_chunk_offset,
1166 { "Entry count", "mp4.stco.chunk_offset", FT_UINT32,
1167 BASE_DEC, NULL, 0, NULL, HFILL } },
1168 { &hf_mp4_mvhd_creat_time,
1169 { "Creation time", "mp4.mvhd.creation_time", FT_ABSOLUTE_TIME,
1170 ABSOLUTE_TIME_UTC, NULL, 0, NULL, HFILL } },
1171 { &hf_mp4_mvhd_mod_time,
1172 { "Modification time", "mp4.mvhd.modification_time", FT_ABSOLUTE_TIME,
1173 ABSOLUTE_TIME_UTC, NULL, 0, NULL, HFILL } },
1174 { &hf_mp4_mvhd_timescale,
1175 { "Timescale", "mp4.mvhd.timescale", FT_UINT32,
1176 BASE_DEC, NULL, 0, NULL, HFILL } },
1177 { &hf_mp4_mvhd_duration,
1178 { "Duration", "mp4.mvhd.duration", FT_UINT64,
1179 BASE_DEC, NULL, 0, NULL, HFILL } },
1180 { &hf_mp4_mvhd_rate,
1181 { "Rate", "mp4.mvhd.rate", FT_DOUBLE,
1182 BASE_NONE, NULL, 0, NULL, HFILL } },
1183 { &hf_mp4_mvhd_vol,
1184 { "Volume", "mp4.mvhd.volume", FT_DOUBLE,
1185 BASE_NONE, NULL, 0, NULL, HFILL } },
1186 { &hf_mp4_mvhd_next_tid,
1187 { "Next Track ID", "mp4.mvhd.next_track_id", FT_UINT32,
1188 BASE_HEX, NULL, 0, NULL, HFILL } },
1189 { &hf_mp4_mfhd_seq_num,
1190 { "Sequence number", "mp4.mfhd.sequence_number", FT_UINT32,
1191 BASE_DEC, NULL, 0, NULL, HFILL } },
1192 { &hf_mp4_tkhd_flags_enabled,
1193 { "Enabled", "mp4.tkhd.flags.enabled", FT_BOOLEAN,
1194 24, NULL, TKHD_FLAG_ENABLED, NULL, HFILL } },
1195 { &hf_mp4_tkhd_flags_in_movie,
1196 { "In movie", "mp4.tkhd.flags.in_movie", FT_BOOLEAN,
1197 24, NULL, TKHD_FLAG_IN_MOVIE, NULL, HFILL } },
1198 { &hf_mp4_tkhd_flags_in_preview,
1199 { "In preview", "mp4.tkhd.flags.in_preview", FT_BOOLEAN,
1200 24, NULL, TKHD_FLAG_IN_PREVIEW, NULL, HFILL } },
1201 { &hf_mp4_tkhd_flags_size_is_aspect_ratio,
1202 { "Size is aspect ratio", "mp4.tkhd.flags.size_is_aspect_ratio", FT_BOOLEAN,
1203 24, NULL, TKHD_FLAG_SIZE_IS_ASPECT_RATIO, NULL, HFILL } },
1204 { &hf_mp4_tkhd_creat_time,
1205 { "Creation time", "mp4.tkhd.creation_time", FT_ABSOLUTE_TIME,
1206 ABSOLUTE_TIME_UTC, NULL, 0, NULL, HFILL } },
1207 { &hf_mp4_tkhd_mod_time,
1208 { "Modification time", "mp4.tkhd.modification_time", FT_ABSOLUTE_TIME,
1209 ABSOLUTE_TIME_UTC, NULL, 0, NULL, HFILL } },
1210 { &hf_mp4_tkhd_track_id,
1211 { "Track ID", "mp4.tkhd.track_id", FT_UINT32,
1212 BASE_DEC, NULL, 0, NULL, HFILL } },
1213 { &hf_mp4_tkhd_duration,
1214 { "Duration", "mp4.tkhd.duration", FT_UINT64,
1215 BASE_DEC, NULL, 0, NULL, HFILL } },
1216 { &hf_mp4_tkhd_width,
1217 { "Width", "mp4.tkhd.width", FT_DOUBLE,
1218 BASE_NONE, NULL, 0, NULL, HFILL } },
1219 { &hf_mp4_tkhd_height,
1220 { "Height", "mp4.tkhd.height", FT_DOUBLE,
1221 BASE_NONE, NULL, 0, NULL, HFILL } },
1222 { &hf_mp4_hdlr_type,
1223 { "Handler type", "mp4.hdlr.type", FT_STRING,
1224 BASE_NONE, NULL, 0, NULL, HFILL } },
1225 { &hf_mp4_hdlr_name,
1226 { "Handler name", "mp4.hdlr.name", FT_STRINGZ,
1227 BASE_NONE, NULL, 0, NULL, HFILL } },
1228 { &hf_mp4_dref_entry_cnt,
1229 { "Number of entries", "mp4.dref.entry_count", FT_UINT32,
1230 BASE_DEC, NULL, 0, NULL, HFILL } },
1231 { &hf_mp4_stsd_entry_cnt,
1232 { "Number of entries", "mp4.stsd.entry_count", FT_UINT32,
1233 BASE_DEC, NULL, 0, NULL, HFILL } },
1234 { &hf_mp4_url_flags_media_data_location,
1235 { "Media data location is defined in the movie box", "mp4.url.flags.media_data_location", FT_BOOLEAN,
1236 24, NULL, ENTRY_FLAG_MOVIE, NULL, HFILL } },
1237 { &hf_mp4_stts_entry_cnt,
1238 { "Number of entries", "mp4.stts.entry_count", FT_UINT32,
1239 BASE_DEC, NULL, 0, NULL, HFILL } },
1240 { &hf_mp4_stts_sample_count,
1241 { "Sample count", "mp4.stts.sample_count", FT_UINT32,
1242 BASE_DEC, NULL, 0, NULL, HFILL } },
1243 { &hf_mp4_stts_sample_delta,
1244 { "Sample delta", "mp4.stts.sample_delta", FT_UINT32,
1245 BASE_DEC, NULL, 0, NULL, HFILL } },
1246 { &hf_mp4_ctts_sample_count,
1247 { "Sample count", "mp4.ctts.sample_count", FT_UINT32,
1248 BASE_DEC, NULL, 0, NULL, HFILL } },
1249 { &hf_mp4_ctts_sample_offset_signed,
1250 { "Sample count", "mp4.ctts.sample_offset", FT_INT32,
1251 BASE_DEC, NULL, 0, NULL, HFILL } },
1252 { &hf_mp4_ctts_sample_offset_unsigned,
1253 { "Sample count", "mp4.ctts.sample_offset", FT_UINT32,
1254 BASE_DEC, NULL, 0, NULL, HFILL } },
1255 { &hf_mp4_elst_entry_cnt,
1256 { "Number of entries", "mp4.elst.entry_count", FT_UINT32,
1257 BASE_DEC, NULL, 0, NULL, HFILL } },
1258 { &hf_mp4_elst_segment_duration,
1259 { "Segment duration", "mp4.elst.segment_duration", FT_UINT64,
1260 BASE_DEC, NULL, 0, NULL, HFILL } },
1261 { &hf_mp4_elst_media_time,
1262 { "Media time", "mp4.elst.media_time", FT_INT64,
1263 BASE_DEC, NULL, 0, NULL, HFILL } },
1264 { &hf_mp4_elst_media_rate_integer,
1265 { "Media rate integer", "mp4.elst.media_rate_integer", FT_INT16,
1266 BASE_DEC, NULL, 0, NULL, HFILL } },
1267 { &hf_mp4_elst_media_rate_fraction,
1268 { "Media rate fraction", "mp4.elst.media_rate_fraction", FT_INT16,
1269 BASE_DEC, NULL, 0, NULL, HFILL } },
1270 { &hf_mp4_sidx_reference_id,
1271 { "Reference ID", "mp4.sidx.reference_id", FT_UINT32,
1272 BASE_DEC, NULL, 0, NULL, HFILL } },
1273 { &hf_mp4_sidx_timescale,
1274 { "Timescale", "mp4.sidx.timescale", FT_UINT32,
1275 BASE_DEC, NULL, 0, NULL, HFILL } },
1276 { &hf_mp4_sidx_earliest_presentation_time_v0,
1277 { "Earliest Presentation Time", "mp4.sidx.earliest_presentation_time", FT_UINT32,
1278 BASE_DEC, NULL, 0, NULL, HFILL } },
1279 { &hf_mp4_sidx_first_offset_v0,
1280 { "First Offset", "mp4.sidx.first_offset", FT_UINT32,
1281 BASE_DEC, NULL, 0, NULL, HFILL } },
1282 { &hf_mp4_sidx_earliest_presentation_time,
1283 { "Earliest Presentation Time", "mp4.sidx.earliest_presentation_time", FT_UINT64,
1284 BASE_DEC, NULL, 0, NULL, HFILL } },
1285 { &hf_mp4_sidx_first_offset,
1286 { "First Offset", "mp4.sidx.first_offset", FT_UINT64,
1287 BASE_DEC, NULL, 0, NULL, HFILL } },
1288 { &hf_mp4_sidx_reserved,
1289 { "Reserved", "mp4.sidx.reserved", FT_UINT16,
1290 BASE_HEX, NULL, 0, NULL, HFILL } },
1291 { &hf_mp4_sidx_entry_cnt,
1292 { "Number of entries", "mp4.sidx.entry_count", FT_UINT16,
1293 BASE_DEC, NULL, 0, NULL, HFILL } },
1294 { &hf_mp4_sidx_reference_type,
1295 { "Reference Type", "mp4.sidx.reference_type", FT_UINT32,
1296 BASE_DEC, VALS(mp4_sidx_reference_type_vals), 0x80000000, NULL, HFILL } },
1297 { &hf_mp4_sidx_reference_size,
1298 { "Reference size", "mp4.sidx.reference_size", FT_UINT32,
1299 BASE_DEC, NULL, 0x7FFFFFFF, NULL, HFILL } },
1300 { &hf_mp4_sidx_subsegment_duration,
1301 { "Segment duration", "mp4.sidx.subsegment_duration", FT_UINT32,
1302 BASE_DEC, NULL, 0, NULL, HFILL } },
1303 { &hf_mp4_sidx_starts_with_sap,
1304 { "Starts With SAP", "mp4.sidx.starts_with_sap", FT_BOOLEAN,
1305 32, NULL, 0x80000000, NULL, HFILL } },
1306 { &hf_mp4_sidx_sap_type,
1307 { "SAP Type", "mp4.sidx.sap_type", FT_UINT32,
1308 BASE_DEC, NULL, 0x70000000, NULL, HFILL } },
1309 { &hf_mp4_sidx_sap_delta_time,
1310 { "SAP Delta Time", "mp4.sidx.sap_delta_time", FT_UINT32,
1311 BASE_DEC, NULL, 0x0FFFFFFF, NULL, HFILL } },
1314 static int *ett[] = {
1315 &ett_mp4,
1316 &ett_mp4_box,
1317 &ett_mp4_full_box_flags,
1318 &ett_mp4_entry,
1321 static ei_register_info ei[] = {
1322 { &ei_mp4_box_too_large,
1323 { "mp4.box_too_large", PI_PROTOCOL, PI_WARN,
1324 "box size too large, dissection of this box is not supported", EXPFILL }},
1325 { &ei_mp4_too_many_rec_lvls,
1326 { "mp4.too_many_levels", PI_UNDECODED, PI_WARN,
1327 "too many recursion levels", EXPFILL }},
1328 { &ei_mp4_mvhd_next_tid_unknown,
1329 { "mp4.mvhd.next_tid_unknown", PI_PROTOCOL, PI_CHAT,
1330 "Next track ID is unknown. Search for an unused track ID if you want to insert a new track.", EXPFILL }}
1333 expert_module_t *expert_mp4;
1335 proto_mp4 = proto_register_protocol("MP4 / ISOBMFF file format", "mp4", "mp4");
1337 proto_register_field_array(proto_mp4, hf, array_length(hf));
1338 proto_register_subtree_array(ett, array_length(ett));
1339 expert_mp4 = expert_register_protocol(proto_mp4);
1340 expert_register_field_array(expert_mp4, ei, array_length(ei));
1342 mp4_handle = register_dissector("mp4", dissect_mp4, proto_mp4);
1345 void
1346 proto_reg_handoff_mp4(void)
1348 dissector_add_string("media_type", "video/mp4", mp4_handle);
1349 dissector_add_string("media_type", "audio/mp4", mp4_handle);
1350 dissector_add_uint("wtap_encap", WTAP_ENCAP_MP4, mp4_handle);
1355 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1357 * Local variables:
1358 * c-basic-offset: 4
1359 * tab-width: 8
1360 * indent-tabs-mode: nil
1361 * End:
1363 * vi: set shiftwidth=4 tabstop=8 expandtab:
1364 * :indentSize=4:tabSize=8:noTabs=true: