rename packet-mp4.c to file-mp4.c
[metze/wireshark/wip.git] / epan / dissectors / file-mp4.c
1 /* file-mp4.c
2  * routines for dissection of MP4 files
3  * Copyright 2013, Martin Kaiser <martin@kaiser.cx>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 /* this dissector is based on
27  * ISO/IEC 14496-12 (ISO base media file format) and
28  * ISO/IEC 14496-14 (MP4 file format)
29  *
30  * at the moment, it dissects the basic box structure and the payload of
31  * some simple boxes */
32
33
34 #include "config.h"
35
36 #include <glib.h>
37 #include <epan/expert.h>
38 #include <epan/packet.h>
39
40 #define MAKE_TYPE_VAL(a, b, c, d)   (a)<<24 | (b)<<16 | (c)<<8 | (d)
41
42 static int proto_mp4 = -1;
43
44 static gint ett_mp4 = -1;
45 static gint ett_mp4_box = -1;
46
47 static int hf_mp4_box_size = -1;
48 static int hf_mp4_box_type_str = -1;
49 static int hf_mp4_box_largesize = -1;
50 static int hf_mp4_full_box_ver = -1;
51 static int hf_mp4_ftyp_brand = -1;
52 static int hf_mp4_ftyp_ver = -1;
53 static int hf_mp4_ftyp_add_brand = -1;
54 static int hf_mp4_mfhd_seq_num = -1;
55
56 static expert_field ei_mp4_box_too_large = EI_INIT;
57
58 /* a box must at least have a 32bit len field and a 32bit type */
59 #define MIN_BOX_SIZE 8
60 /* an extended box has the first length field set to 1 */
61 #define BOX_SIZE_EXTENDED 1
62
63 /* the box type is stored as four text characters
64    it is in network byte order and contains only printable characters
65    for our internal handling, we convert this to a 32bit value */
66
67 #define BOX_TYPE_NONE  0x0 /* used for parent_box_type of a top-level box */
68 #define BOX_TYPE_FTYP  MAKE_TYPE_VAL('f', 't', 'y', 'p')
69 #define BOX_TYPE_MOOV  MAKE_TYPE_VAL('m', 'o', 'o', 'v')
70 #define BOX_TYPE_MVHD  MAKE_TYPE_VAL('m', 'v', 'h', 'd')
71 #define BOX_TYPE_TRAK  MAKE_TYPE_VAL('t', 'r', 'a', 'k')
72 #define BOX_TYPE_TKHD  MAKE_TYPE_VAL('t', 'k', 'h', 'd')
73 #define BOX_TYPE_MDIA  MAKE_TYPE_VAL('m', 'd', 'i', 'a')
74 #define BOX_TYPE_MDHD  MAKE_TYPE_VAL('m', 'd', 'h', 'd')
75 #define BOX_TYPE_HDLR  MAKE_TYPE_VAL('h', 'd', 'l', 'r')
76 #define BOX_TYPE_MINF  MAKE_TYPE_VAL('m', 'i', 'n', 'f')
77 #define BOX_TYPE_VMHD  MAKE_TYPE_VAL('v', 'm', 'h', 'd')
78 #define BOX_TYPE_DINF  MAKE_TYPE_VAL('d', 'i', 'n', 'f')
79 #define BOX_TYPE_DREF  MAKE_TYPE_VAL('d', 'r', 'e', 'f')
80 #define BOX_TYPE_STBL  MAKE_TYPE_VAL('s', 't', 'b', 'l')
81 #define BOX_TYPE_STTS  MAKE_TYPE_VAL('s', 't', 't', 's')
82 #define BOX_TYPE_STSD  MAKE_TYPE_VAL('s', 't', 's', 'd')
83 #define BOX_TYPE_STSZ  MAKE_TYPE_VAL('s', 't', 's', 'z')
84 #define BOX_TYPE_STSC  MAKE_TYPE_VAL('s', 't', 's', 'c')
85 #define BOX_TYPE_STCO  MAKE_TYPE_VAL('s', 't', 'c', 'o')
86 #define BOX_TYPE_MVEX  MAKE_TYPE_VAL('m', 'v', 'e', 'x')
87 #define BOX_TYPE_MOOF  MAKE_TYPE_VAL('m', 'o', 'o', 'f')
88 #define BOX_TYPE_MEHD  MAKE_TYPE_VAL('m', 'e', 'h', 'd')
89 #define BOX_TYPE_TREX  MAKE_TYPE_VAL('t', 'r', 'e', 'x')
90 #define BOX_TYPE_MFHD  MAKE_TYPE_VAL('m', 'f', 'h', 'd')
91 #define BOX_TYPE_TRAF  MAKE_TYPE_VAL('t', 'r', 'a', 'f')
92 #define BOX_TYPE_TFHD  MAKE_TYPE_VAL('t', 'f', 'h', 'd')
93 #define BOX_TYPE_TRUN  MAKE_TYPE_VAL('t', 'r', 'u', 'n')
94 #define BOX_TYPE_MDAT  MAKE_TYPE_VAL('m', 'd', 'a', 't')
95 #define BOX_TYPE_UDTA  MAKE_TYPE_VAL('u', 'd', 't', 'a')
96
97
98 static const value_string box_types[] = {
99     { BOX_TYPE_FTYP, "File Type Box" },
100     { BOX_TYPE_MOOV, "Movie Box" },
101     { BOX_TYPE_MVHD, "Movie Header Box" },
102     { BOX_TYPE_TRAK, "Track Box" },
103     { BOX_TYPE_TKHD, "Track Header Box" },
104     { BOX_TYPE_MDIA, "Media Box" },
105     { BOX_TYPE_MDHD, "Media Header Box" },
106     { BOX_TYPE_HDLR, "Handler Reference Box" },
107     { BOX_TYPE_MINF, "Media Information Box" },
108     { BOX_TYPE_VMHD, "Video Media Header Box" },
109     { BOX_TYPE_DINF, "Data Information Box" },
110     { BOX_TYPE_DREF, "Data Reference Box" },
111     { BOX_TYPE_STBL, "Sample to Group Box" },
112     { BOX_TYPE_STTS, "Decoding Time To Sample Box" },
113     { BOX_TYPE_STSD, "Sample Description Box" },
114     { BOX_TYPE_STSZ, "Sample Size Box" },
115     { BOX_TYPE_STSC, "Sample To Chunk Box" },
116     { BOX_TYPE_STCO, "Chunk Offset Box" },
117     { BOX_TYPE_MVEX, "Movie Extends Box" },
118     { BOX_TYPE_MOOF, "Movie Fragment Box" },
119     { BOX_TYPE_MEHD, "Movie Extends Header Box" },
120     { BOX_TYPE_TREX, "Track Extends Box" },
121     { BOX_TYPE_MFHD, "Movie Fragment Header Box" },
122     { BOX_TYPE_TRAF, "Track Fragment Box" },
123     { BOX_TYPE_TFHD, "Track Fragment Header Box" },
124     { BOX_TYPE_TRUN, "Track Fragment Run Box" },
125     { BOX_TYPE_MDAT, "Media Data Box" },
126     { BOX_TYPE_UDTA, "User Data Box" },
127     { 0, NULL }
128 };
129
130 static gint
131 dissect_mp4_mvhd_body(tvbuff_t *tvb, gint offset, gint len _U_,
132         packet_info *pinfo _U_, proto_tree *tree)
133 {
134     gint offset_start;
135
136     offset_start = offset;
137     proto_tree_add_item(tree, hf_mp4_full_box_ver,
138             tvb, offset, 1, ENC_BIG_ENDIAN);
139     offset++;
140     offset+=3;
141
142     return offset-offset_start;
143 }
144
145 static gint
146 dissect_mp4_mfhd_body(tvbuff_t *tvb, gint offset, gint len _U_,
147         packet_info *pinfo _U_, proto_tree *tree)
148 {
149     gint offset_start;
150
151     offset_start = offset;
152     proto_tree_add_item(tree, hf_mp4_full_box_ver,
153             tvb, offset, 1, ENC_BIG_ENDIAN);
154     offset++;
155     offset+=3;
156
157     proto_tree_add_item(tree, hf_mp4_mfhd_seq_num,
158             tvb, offset, 4, ENC_BIG_ENDIAN);
159     offset+=4;
160
161     return offset-offset_start;
162 }
163
164
165 static gint
166 dissect_mp4_ftyp_body(tvbuff_t *tvb, gint offset, gint len,
167         packet_info *pinfo _U_, proto_tree *tree)
168 {
169     gint offset_start;
170
171     offset_start = offset;
172     proto_tree_add_item(tree, hf_mp4_ftyp_brand,
173             tvb, offset, 4, ENC_ASCII|ENC_NA);
174     offset += 4;
175     proto_tree_add_item(tree, hf_mp4_ftyp_ver,
176             tvb, offset, 4, ENC_BIG_ENDIAN);
177     offset += 4;
178
179     while (offset-offset_start<len) {
180         proto_tree_add_item(tree, hf_mp4_ftyp_add_brand,
181                 tvb, offset, 4, ENC_ASCII|ENC_NA);
182         offset += 4;
183     }
184
185     return offset-offset_start;
186 }
187
188 /* dissect a box, return its (standard or extended) length or 0 for error */
189 static gint
190 dissect_mp4_box(guint32 parent_box_type _U_,
191         tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree)
192 {
193     gint        offset_start;
194     guint64     box_size;
195     guint32     box_type;
196     guint8     *box_type_str;
197     proto_item *type_pi, *size_pi, *ext_size_pi = NULL;
198     proto_tree *box_tree;
199     gint        ret;
200     gint        body_size;
201
202
203     offset_start = offset;
204
205     /* the following mechanisms are not supported for now
206        - size==0, indicating that the box extends to the end of the file
207        - extended box types */
208
209     box_size = (guint64)tvb_get_ntohl(tvb, offset);
210     if (box_size!=BOX_SIZE_EXTENDED && box_size<MIN_BOX_SIZE)
211         return -1;
212
213     box_type = tvb_get_ntohl(tvb, offset+4);
214     box_type_str = tvb_get_ephemeral_string(tvb, offset+4, 4);
215
216     type_pi = proto_tree_add_text(tree, tvb, offset, -1, "%s (%s)",
217             val_to_str_const(box_type, box_types, "unknown"), box_type_str);
218     box_tree = proto_item_add_subtree(type_pi, ett_mp4_box);
219
220     size_pi = proto_tree_add_item(box_tree, hf_mp4_box_size,
221             tvb, offset, 4, ENC_BIG_ENDIAN);
222     if (box_size==BOX_SIZE_EXTENDED)
223         proto_item_append_text(size_pi, " (actual size is in largesize)");
224
225     offset += 4;
226     proto_tree_add_item(box_tree, hf_mp4_box_type_str,
227             tvb, offset, 4, ENC_ASCII|ENC_NA);
228     offset += 4;
229
230     if (box_size==BOX_SIZE_EXTENDED) {
231         box_size = tvb_get_ntoh64(tvb, offset);
232         ext_size_pi = proto_tree_add_item(box_tree, hf_mp4_box_largesize,
233                 tvb, offset, 8, ENC_BIG_ENDIAN);
234         offset += 8;
235     }
236
237     if (box_size > G_MAXINT) {
238         /* this should be ok for ext_size_pi==NULL */
239         expert_add_info(pinfo, ext_size_pi, &ei_mp4_box_too_large);
240         return -1;
241     }
242     proto_item_set_len(type_pi, (gint)box_size);
243     body_size = (gint)box_size - (offset-offset_start);
244
245     /* XXX - check parent box if supplied */
246     switch (box_type) {
247         case BOX_TYPE_FTYP:
248             dissect_mp4_ftyp_body(tvb, offset, body_size, pinfo, box_tree);
249             break;
250         case BOX_TYPE_MVHD:
251             dissect_mp4_mvhd_body(tvb, offset, body_size, pinfo, box_tree);
252             break;
253         case BOX_TYPE_MFHD:
254             dissect_mp4_mfhd_body(tvb, offset, body_size, pinfo, box_tree);
255             break;
256         case BOX_TYPE_MOOV:
257         case BOX_TYPE_MOOF:
258         case BOX_TYPE_STBL:
259         case BOX_TYPE_MDIA:
260         case BOX_TYPE_TRAK:
261         case BOX_TYPE_TRAF:
262         case BOX_TYPE_MINF:
263         case BOX_TYPE_MVEX:
264         case BOX_TYPE_DINF:
265         case BOX_TYPE_UDTA:
266             while (offset-offset_start<(gint)box_size) {
267                 ret = dissect_mp4_box(box_type, tvb, offset, pinfo, box_tree);
268                 if (ret<=0)
269                     break;
270                 offset += ret;
271             }
272             break;
273         default:
274             break;
275     }
276
277     return (gint)box_size;
278 }
279
280
281 static int
282 dissect_mp4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
283 {
284     gint        offset = 0;
285     guint32     box_type;
286     proto_item *pi;
287     proto_tree *mp4_tree;
288     gint        ret;
289
290     /* to make sure that we have an mp4 file, we check that it starts with
291         a box of a known type
292        please note that we do not allow the first box to be an extended box
293        this detection should be safe as long as the dissector is only called for
294         the video/mp4 mime type
295        when we read mp4 files directly, we might need stricter checks here */
296     if (tvb_reported_length(tvb)<MIN_BOX_SIZE)
297         return 0;
298     box_type = tvb_get_ntohl(tvb, 4);
299     if (try_val_to_str(box_type, box_types) == NULL)
300         return 0;
301
302     col_set_str(pinfo->cinfo, COL_PROTOCOL, "MP4");
303     col_clear(pinfo->cinfo, COL_INFO);
304
305     pi = proto_tree_add_protocol_format(tree, proto_mp4,
306             tvb, 0, (gint)tvb_reported_length(tvb), "MP4");
307     mp4_tree = proto_item_add_subtree(pi, ett_mp4);
308
309     while (tvb_reported_length_remaining(tvb, offset) > 0) {
310         ret = dissect_mp4_box(BOX_TYPE_NONE, tvb, offset, pinfo, mp4_tree);
311         if (ret<=0)
312             break;
313         offset += ret;
314     }
315
316     return offset;
317 }
318
319 void
320 proto_register_mp4(void)
321 {
322     static hf_register_info hf[] = {
323         { &hf_mp4_box_size,
324             { "Box size", "mp4.box.size", FT_UINT32, BASE_DEC,
325                 NULL, 0, NULL, HFILL } },
326         { &hf_mp4_box_type_str,
327             { "Box type", "mp4.box.type_str", FT_STRING, BASE_NONE,
328                 NULL, 0, NULL, HFILL } },
329         { &hf_mp4_box_largesize,
330             { "Box size (largesize)", "mp4.box.largesize", FT_UINT64, BASE_DEC,
331                 NULL, 0, NULL, HFILL } },
332         { &hf_mp4_full_box_ver,
333             { "Box version", "mp4.full_box.version", FT_UINT8, BASE_DEC,
334                 NULL, 0, NULL, HFILL } },
335         { &hf_mp4_ftyp_brand,
336             { "Brand", "mp4.ftyp.brand", FT_STRING, BASE_NONE,
337                 NULL, 0, NULL, HFILL } },
338         { &hf_mp4_ftyp_ver,
339             { "Version", "mp4.ftyp.version", FT_UINT32, BASE_DEC,
340                 NULL, 0, NULL, HFILL } },
341         { &hf_mp4_ftyp_add_brand,
342             { "Additional brand", "mp4.ftyp.additional_brand", FT_STRING,
343                 BASE_NONE, NULL, 0, NULL, HFILL } },
344         { &hf_mp4_mfhd_seq_num,
345             { "Sequence number", "mp4.mfhd.sequence_number", FT_UINT32,
346                 BASE_DEC, NULL, 0, NULL, HFILL } }
347     };
348
349     static gint *ett[] = {
350         &ett_mp4,
351         &ett_mp4_box
352     };
353
354     static ei_register_info ei[] = {
355         { &ei_mp4_box_too_large,
356             { "mp4.box_too_large", PI_PROTOCOL, PI_WARN,
357                 "box size too large, dissection of this box is not supported", EXPFILL }}
358     };
359
360     expert_module_t* expert_mp4;
361     
362     proto_mp4 = proto_register_protocol("MP4 / ISOBMFF file format", "mp4", "mp4");
363
364     proto_register_field_array(proto_mp4, hf, array_length(hf));
365     proto_register_subtree_array(ett, array_length(ett));
366     expert_mp4 = expert_register_protocol(proto_mp4);
367     expert_register_field_array(expert_mp4, ei, array_length(ei));
368 }
369
370 void
371 proto_reg_handoff_mp4(void)
372 {
373     dissector_handle_t mp4_handle = new_create_dissector_handle(dissect_mp4, proto_mp4);
374     dissector_add_string("media_type", "video/mp4", mp4_handle);
375 }
376
377
378 /*
379  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
380  *
381  * Local variables:
382  * c-basic-offset: 4
383  * tab-width: 8
384  * indent-tabs-mode: nil
385  * End:
386  *
387  * vi: set shiftwidth=4 tabstop=8 expandtab:
388  * :indentSize=4:tabSize=8:noTabs=true:
389  */