diff --git a/epan/dissectors/file-mp4.c b/epan/dissectors/file-mp4.c index 71dc47d6a0..966f8ee32f 100644 --- a/epan/dissectors/file-mp4.c +++ b/epan/dissectors/file-mp4.c @@ -12,6 +12,7 @@ /* this dissector is based on * ISO/IEC 14496-12 (ISO base media file format) and * ISO/IEC 14496-14 (MP4 file format) + * 3GPP TS 26.244 (Adaptive-Streaming profile) * * at the moment, it dissects the basic box structure and the payload of * some simple boxes */ @@ -97,6 +98,27 @@ static int hf_mp4_elst_segment_duration = -1; static int hf_mp4_elst_media_time = -1; static int hf_mp4_elst_media_rate_integer = -1; static int hf_mp4_elst_media_rate_fraction = -1; +static int hf_mp4_sidx_reference_id = -1; +static int hf_mp4_sidx_timescale = -1; +static int hf_mp4_sidx_earliest_presentation_time_v0 = -1; +static int hf_mp4_sidx_first_offset_v0 = -1; +static int hf_mp4_sidx_earliest_presentation_time = -1; +static int hf_mp4_sidx_first_offset = -1; +static int hf_mp4_sidx_reserved = -1; +static int hf_mp4_sidx_entry_cnt = -1; +static int hf_mp4_sidx_reference_type = -1; +static int hf_mp4_sidx_reference_size = -1; +static int hf_mp4_sidx_subsegment_duration = -1; +static int hf_mp4_sidx_starts_with_sap = -1; +static int hf_mp4_sidx_sap_type = -1; +static int hf_mp4_sidx_sap_delta_time = -1; + +static const value_string mp4_sidx_reference_type_vals[] = { + { 0, "Movie" }, + { 1, "Index" }, + + { 0, NULL } +}; static expert_field ei_mp4_box_too_large = EI_INIT; static expert_field ei_mp4_too_many_rec_lvls = EI_INIT; @@ -150,6 +172,8 @@ static guint32 mvhd_timescale = 0; #define BOX_TYPE_URL_ MAKE_TYPE_VAL('u', 'r', 'l', ' ') #define BOX_TYPE_EDTS MAKE_TYPE_VAL('e', 'd', 't', 's') #define BOX_TYPE_ELST MAKE_TYPE_VAL('e', 'l', 's', 't') +#define BOX_TYPE_SIDX MAKE_TYPE_VAL('s', 'i', 'd', 'x') +#define BOX_TYPE_STYP MAKE_TYPE_VAL('s', 't', 'y', 'p') #define TKHD_FLAG_ENABLED 0x000001 #define TKHD_FLAG_IN_MOVIE 0x000002 @@ -195,6 +219,8 @@ static const value_string box_types[] = { { BOX_TYPE_URL_, "URL Box" }, { BOX_TYPE_EDTS, "Edit Box" }, { BOX_TYPE_ELST, "Edit List Box" }, + { BOX_TYPE_SIDX, "Segment Index Box"}, + { BOX_TYPE_STYP, "Segment Type Box" }, { 0, NULL } }; @@ -817,6 +843,83 @@ dissect_mp4_elst_body(tvbuff_t *tvb, gint offset, gint len, return len; } +/* 3GPP TS 26.244 version 16.1.0 Release 16: 13.4 Segment Index Box */ +static gint +dissect_mp4_sidx_body(tvbuff_t *tvb, gint offset, gint len _U_, + packet_info *pinfo _U_, guint depth _U_, proto_tree *tree) +{ + guint8 version; + gint offset_start; + guint16 entry_cnt, i; + + offset_start = offset; + + offset += dissect_mp4_full_box (tvb, offset, tree, NULL, &version, NULL); + + proto_tree_add_item(tree, hf_mp4_sidx_reference_id, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + proto_tree_add_item(tree, hf_mp4_sidx_timescale, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + if (version == 0) { + proto_tree_add_item(tree, hf_mp4_sidx_earliest_presentation_time_v0, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + proto_tree_add_item(tree, hf_mp4_sidx_first_offset_v0, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + } else { + proto_tree_add_item(tree, hf_mp4_sidx_earliest_presentation_time, + tvb, offset, 8, ENC_BIG_ENDIAN); + offset += 8; + + proto_tree_add_item(tree, hf_mp4_sidx_first_offset, + tvb, offset, 8, ENC_BIG_ENDIAN); + offset += 8; + } + + proto_tree_add_item(tree, hf_mp4_sidx_reserved, + tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + entry_cnt = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + proto_tree_add_item(tree, hf_mp4_sidx_entry_cnt, + tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + for(i=1; i<=entry_cnt; i++) { + proto_tree *subtree; + proto_item *subtree_item; + + subtree = proto_tree_add_subtree_format (tree, tvb, offset, 8, + ett_mp4_entry, &subtree_item, "Entry %u:", i); + + proto_tree_add_item(subtree, hf_mp4_sidx_reference_type, + tvb, offset, 4, ENC_BIG_ENDIAN); + proto_tree_add_item(subtree, hf_mp4_sidx_reference_size, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + proto_tree_add_item(subtree, hf_mp4_sidx_subsegment_duration, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + proto_tree_add_item(subtree, hf_mp4_sidx_starts_with_sap, + tvb, offset, 4, ENC_BIG_ENDIAN); + proto_tree_add_item(subtree, hf_mp4_sidx_sap_type, + tvb, offset, 4, ENC_BIG_ENDIAN); + proto_tree_add_item(subtree, hf_mp4_sidx_sap_delta_time, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + } + + return offset-offset_start; +} + /* dissect a box, return its (standard or extended) length or 0 for error depth is the recursion level of the parent box */ static gint @@ -888,7 +991,9 @@ dissect_mp4_box(guint32 parent_box_type _U_, guint depth, /* XXX - check parent box if supplied */ switch (box_type) { + /* As per 3GPP TS 26.244 styp and ftyp boxes have the same format*/ case BOX_TYPE_FTYP: + case BOX_TYPE_STYP: dissect_mp4_ftyp_body(tvb, offset, body_size, pinfo, depth, box_tree); break; case BOX_TYPE_MVHD: @@ -930,6 +1035,9 @@ dissect_mp4_box(guint32 parent_box_type _U_, guint depth, case BOX_TYPE_ELST: dissect_mp4_elst_body(tvb, offset, body_size, pinfo, depth, box_tree); break; + case BOX_TYPE_SIDX: + dissect_mp4_sidx_body(tvb, offset, body_size, pinfo, depth, box_tree); + break; case BOX_TYPE_MOOV: case BOX_TYPE_MOOF: case BOX_TYPE_STBL: @@ -1152,6 +1260,48 @@ proto_register_mp4(void) { &hf_mp4_elst_media_rate_fraction, { "Media rate fraction", "mp4.elst.media_rate_fraction", FT_INT16, BASE_DEC, NULL, 0, NULL, HFILL } }, + { &hf_mp4_sidx_reference_id, + { "Reference ID", "mp4.sidx.reference_id", FT_UINT32, + BASE_DEC, NULL, 0, NULL, HFILL } }, + { &hf_mp4_sidx_timescale, + { "Timescale", "mp4.sidx.timescale", FT_UINT32, + BASE_DEC, NULL, 0, NULL, HFILL } }, + { &hf_mp4_sidx_earliest_presentation_time_v0, + { "Earliest Presentation Time", "mp4.sidx.earliest_presentation_time", FT_UINT32, + BASE_DEC, NULL, 0, NULL, HFILL } }, + { &hf_mp4_sidx_first_offset_v0, + { "First Offset", "mp4.sidx.first_offset", FT_UINT32, + BASE_DEC, NULL, 0, NULL, HFILL } }, + { &hf_mp4_sidx_earliest_presentation_time, + { "Earliest Presentation Time", "mp4.sidx.earliest_presentation_time", FT_UINT64, + BASE_DEC, NULL, 0, NULL, HFILL } }, + { &hf_mp4_sidx_first_offset, + { "First Offset", "mp4.sidx.first_offset", FT_UINT64, + BASE_DEC, NULL, 0, NULL, HFILL } }, + { &hf_mp4_sidx_reserved, + { "Reserved", "mp4.sidx.reserved", FT_UINT16, + BASE_HEX, NULL, 0, NULL, HFILL } }, + { &hf_mp4_sidx_entry_cnt, + { "Number of entries", "mp4.sidx.entry_count", FT_UINT16, + BASE_DEC, NULL, 0, NULL, HFILL } }, + { &hf_mp4_sidx_reference_type, + { "Reference Type", "mp4.sidx.reference_type", FT_UINT32, + BASE_DEC, VALS(mp4_sidx_reference_type_vals), 0x80000000, NULL, HFILL } }, + { &hf_mp4_sidx_reference_size, + { "Reference size", "mp4.sidx.reference_size", FT_UINT32, + BASE_DEC, NULL, 0x7FFFFFFF, NULL, HFILL } }, + { &hf_mp4_sidx_subsegment_duration, + { "Segment duration", "mp4.sidx.subsegment_duration", FT_UINT32, + BASE_DEC, NULL, 0, NULL, HFILL } }, + { &hf_mp4_sidx_starts_with_sap, + { "Starts With SAP", "mp4.sidx.starts_with_sap", FT_BOOLEAN, + 32, NULL, 0x80000000, NULL, HFILL } }, + { &hf_mp4_sidx_sap_type, + { "SAP Type", "mp4.sidx.sap_type", FT_UINT32, + BASE_DEC, NULL, 0x70000000, NULL, HFILL } }, + { &hf_mp4_sidx_sap_delta_time, + { "SAP Delta Time", "mp4.sidx.sap_delta_time", FT_UINT32, + BASE_DEC, NULL, 0x0FFFFFFF, NULL, HFILL } }, }; static gint *ett[] = { diff --git a/wiretap/mp4.c b/wiretap/mp4.c index 1ad140dc71..36a43a71b6 100644 --- a/wiretap/mp4.c +++ b/wiretap/mp4.c @@ -15,6 +15,8 @@ #include "wtap-int.h" static const guint8 mp4_magic[] = { 'f', 't', 'y', 'p' }; +static const guint8 mp4_magic_sidx[] = { 's', 'i', 'd', 'x' }; +static const guint8 mp4_magic_styp[] = { 's', 't', 'y', 'p' }; static int mp4_file_type_subtype = -1; @@ -36,7 +38,9 @@ mp4_open(wtap *wth, int *err, gchar **err_info) return WTAP_OPEN_NOT_MINE; if (bytes_read == sizeof (magic_buf) && - memcmp(magic_buf + 4, mp4_magic, sizeof (mp4_magic))) + memcmp(magic_buf + 4, mp4_magic, sizeof (mp4_magic)) && + memcmp(magic_buf + 4, mp4_magic_sidx, sizeof (mp4_magic_sidx)) && + memcmp(magic_buf + 4, mp4_magic_styp, sizeof (mp4_magic_styp))) return WTAP_OPEN_NOT_MINE; if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)