Decode more of H264 info in SDP.

svn path=/trunk/; revision=23832
This commit is contained in:
Anders Broman 2007-12-10 21:25:32 +00:00
parent 9a3eeab4ee
commit 92e1ee3721
3 changed files with 352 additions and 23 deletions

View File

@ -44,7 +44,7 @@
/* Initialize the protocol and registered fields */
static int proto_h264 = -1;
static int hf_h264_nal_unit_type = -1;
static int hf_h264_type = -1;
static int hf_h264_nal_f_bit = -1;
static int hf_h264_nal_nri = -1;
static int hf_h264_profile = -1;
@ -55,12 +55,16 @@ static int hf_h264_constraint_set2_flag = -1;
static int hf_h264_constraint_set3_flag = -1;
static int hf_h264_reserved_zero_4bits = -1;
static int hf_h264_level_idc = -1;
static int hf_h264_nal_unit = -1;
static int hf_h264_forbidden_zero_bit = -1;
static int hf_h264_nal_ref_idc = -1;
static int hf_h264_nal_unit_type = -1;
/* Initialize the subtree pointers */
static int ett_h264 = -1;
static int ett_h264_profile = -1;
static int ett_h264_nal = -1;
static int ett_h264_nal_unit = -1;
/* The dynamic payload type which will be dissected as H.264 */
@ -73,7 +77,7 @@ static const true_false_string h264_f_bit_vals = {
};
static const value_string h264_nal_unit_type_values[] = {
static const value_string h264_type_values[] = {
{ 0, "Undefined" },
{ 1, "NAL unit" }, /* Single NAL unit packet per H.264 */
{ 2, "NAL unit" },
@ -85,7 +89,7 @@ static const value_string h264_nal_unit_type_values[] = {
{ 8, "NAL unit" },
{ 9, "NAL unit" },
{ 10, "NAL unit" },
{ 11, "NAL unit" }, /* Single NAL unit packet per H.264 */
{ 11, "NAL unit" },
{ 12, "NAL unit" },
{ 13, "NAL unit" },
{ 14, "NAL unit" },
@ -95,7 +99,7 @@ static const value_string h264_nal_unit_type_values[] = {
{ 18, "NAL unit" },
{ 19, "NAL unit" },
{ 20, "NAL unit" },
{ 21, "NAL unit" }, /* Single NAL unit packet per H.264 */
{ 21, "NAL unit" },
{ 22, "NAL unit" },
{ 23, "NAL unit" },
{ 24, "STAP-A" }, /* Single-time aggregation packet */
@ -121,6 +125,43 @@ static const value_string h264_profile_idc_values[] = {
{ 0, NULL }
};
static const value_string h264_nal_unit_type_vals[] = {
{ 0, "Unspecified" },
{ 1, "Coded slice of a non-IDR picture" },
{ 2, "Coded slice data partition A" },
{ 3, "Coded slice data partition B" },
{ 4, "Coded slice data partition C" },
{ 5, "Coded slice of an IDR picture" },
{ 6, "Supplemental enhancement information (SEI)" },
{ 7, "Sequence parameter set" },
{ 8, "Picture parameter set" },
{ 9, "Access unit delimiter" },
{ 10, "End of sequence" },
{ 11, "End of stream" },
{ 12, "Filler data" },
{ 13, "Sequence parameter set extension" },
{ 14, "Reserved" },
{ 15, "Reserved" },
{ 16, "Reserved" },
{ 17, "Reserved" },
{ 18, "Reserved" },
{ 19, "Coded slice of an auxiliary coded picture without partitioning" },
{ 20, "Reserved" },
{ 21, "Reserved" },
{ 22, "Reserved" },
{ 23, "Reserved" },
{ 24, "Unspecified" },
{ 25, "Unspecified" },
{ 26, "Unspecified" },
{ 27, "Unspecified" },
{ 28, "Unspecified" },
{ 29, "Unspecified" },
{ 30, "Unspecified" },
{ 31, "Unspecified" },
{ 0, NULL }
};
/* Used To dissect SDP parameter (H.264)profile */
void
dissect_h264_profile(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
@ -150,6 +191,201 @@ dissect_h264_profile(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
proto_tree_add_item(h264_profile_tree, hf_h264_level_idc, tvb, offset, 1, FALSE);
}
static void
dissect_h264_slice_layer_without_partitioning_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
proto_tree_add_text(tree, tvb, offset, -1, "Not decoded yet");
}
static void
dissect_h264_slice_data_partition_a_layer_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
proto_tree_add_text(tree, tvb, offset, -1, "Not decoded yet");
}
static void
dissect_h264_slice_data_partition_b_layer_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
proto_tree_add_text(tree, tvb, offset, -1, "Not decoded yet");
}
static void
dissect_h264_slice_data_partition_c_layer_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
proto_tree_add_text(tree, tvb, offset, -1, "Not decoded yet");
}
static void
dissect_h264_sei_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
proto_tree_add_text(tree, tvb, offset, -1, "Not decoded yet");
}
/* Ref 7.3.2.1 Sequence parameter set RBSP syntax */
static void
dissect_h264_seq_parameter_set_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
/* profile_idc 0 u(8) */
proto_tree_add_item(tree, hf_h264_profile_idc, tvb, offset, 1, FALSE);
offset++;
/* constraint_set0_flag 0 u(1) */
proto_tree_add_item(tree, hf_h264_constraint_set0_flag, tvb, offset, 1, FALSE);
/* constraint_set1_flag 0 u(1) */
proto_tree_add_item(tree, hf_h264_constraint_set1_flag, tvb, offset, 1, FALSE);
/* constraint_set2_flag 0 u(1) */
proto_tree_add_item(tree, hf_h264_constraint_set2_flag, tvb, offset, 1, FALSE);
/* constraint_set3_flag 0 u(1) */
proto_tree_add_item(tree, hf_h264_constraint_set3_flag, tvb, offset, 1, FALSE);
/* reserved_zero_4bits equal to 0 0 u(4)*/
proto_tree_add_item(tree, hf_h264_reserved_zero_4bits, tvb, offset, 1, FALSE);
offset++;
/* level_idc 0 u(8) */
proto_tree_add_item(tree, hf_h264_level_idc, tvb, offset, 1, FALSE);
offset;
/* seq_parameter_set_id 0 ue(v)
* ue(v): unsigned integer Exp-Golomb-coded syntax element with the left bit first.
* The parsing process for this descriptor is specified in subclause 9.1.
*/
proto_tree_add_text(tree, tvb, offset, -1, "Not decoded yet");
offset++;
}
static void
dissect_h264_pic_parameter_set_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
proto_tree_add_text(tree, tvb, offset, -1, "Not decoded yet");
}
static void
dissect_h264_access_unit_delimiter_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
proto_tree_add_text(tree, tvb, offset, -1, "Not decoded yet");
}
static void
dissect_h264_end_of_seq_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
proto_tree_add_text(tree, tvb, offset, -1, "Not decoded yet");
}
static void
dissect_h264_end_of_stream_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
proto_tree_add_text(tree, tvb, offset, -1, "Not decoded yet");
}
static void
dissect_h264_filler_data_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
proto_tree_add_text(tree, tvb, offset, -1, "Not decoded yet");
}
static void
dissect_h264_seq_parameter_set_extension_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
proto_tree_add_text(tree, tvb, offset, -1, "Not decoded yet");
}
/* Dissect NAL unit as recived in sprop-parameter-sets of SDP */
void
dissect_h264_nal_unit(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
proto_item *item;
proto_tree *h264_nal_tree;
gint offset = 0;
guint8 nal_unit_type;
item = proto_tree_add_item(tree, hf_h264_nal_unit, tvb, offset, -1, FALSE);
h264_nal_tree = proto_item_add_subtree(item, ett_h264_nal_unit);
/* Ref: 7.3.1 NAL unit syntax */
nal_unit_type = tvb_get_guint8(tvb,offset) & 0x1f;
/* forbidden_zero_bit All f(1) */
proto_tree_add_item(h264_nal_tree, hf_h264_forbidden_zero_bit, tvb, offset, 1, FALSE);
/* nal_ref_idc All u(2) */
proto_tree_add_item(h264_nal_tree, hf_h264_nal_ref_idc, tvb, offset, 1, FALSE);
/* nal_unit_type All u(5) */
proto_tree_add_item(h264_nal_tree, hf_h264_nal_unit_type, tvb, offset, 1, FALSE);
offset++;
switch(nal_unit_type){
case 0: /* Unspecified */
proto_tree_add_text(h264_nal_tree, tvb, offset, -1, "Unspecified NAL unit type");
break;
case 1: /* Coded slice of a non-IDR picture */
dissect_h264_slice_layer_without_partitioning_rbsp(tree, tvb, pinfo, offset);
break;
case 2: /* Coded slice data partition A */
dissect_h264_slice_data_partition_a_layer_rbsp(tree, tvb, pinfo, offset);
break;
case 3: /* Coded slice data partition B */
dissect_h264_slice_data_partition_b_layer_rbsp(tree, tvb, pinfo, offset);
break;
case 4: /* Coded slice data partition C */
dissect_h264_slice_data_partition_c_layer_rbsp(tree, tvb, pinfo, offset);
break;
case 5: /* Coded slice of an IDR picture */
dissect_h264_slice_layer_without_partitioning_rbsp(tree, tvb, pinfo, offset);
break;
case 6: /* Supplemental enhancement information (SEI) */
dissect_h264_sei_rbsp(tree, tvb, pinfo, offset);
break;
case 7: /* Sequence parameter set*/
dissect_h264_seq_parameter_set_rbsp(tree, tvb, pinfo, offset);
break;
case 8: /* Picture parameter set */
dissect_h264_pic_parameter_set_rbsp(tree, tvb, pinfo, offset);
break;
case 9: /* Access unit delimiter */
dissect_h264_access_unit_delimiter_rbsp(tree, tvb, pinfo, offset);
break;
case 10: /* End of sequence */
dissect_h264_end_of_seq_rbsp(tree, tvb, pinfo, offset);
break;
case 11: /* End of stream */
dissect_h264_end_of_stream_rbsp(tree, tvb, pinfo, offset);
break;
case 12: /* Filler data */
dissect_h264_filler_data_rbsp(tree, tvb, pinfo, offset);
break;
case 13: /* Sequence parameter set extension */
dissect_h264_seq_parameter_set_extension_rbsp(tree, tvb, pinfo, offset);
break;
case 14: /* Reserved */
case 15: /* Reserved */
case 16: /* Reserved */
case 17: /* Reserved */
case 18: /* Reserved */
proto_tree_add_text(h264_nal_tree, tvb, offset, -1, "Reserved NAL unit type");
break;
case 19: /* Coded slice of an auxiliary coded picture without partitioning */
dissect_h264_slice_layer_without_partitioning_rbsp(tree, tvb, pinfo, offset);
break;
default:
/* 24..31 Unspecified */
proto_tree_add_text(h264_nal_tree, tvb, offset, -1, "Unspecified NAL unit type");
break;
}
}
/* Code to actually dissect the packets */
static void
dissect_h264(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
@ -184,7 +420,7 @@ dissect_h264(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
*/
proto_tree_add_item(h264_nal_tree, hf_h264_nal_f_bit, tvb, offset, 1, FALSE);
proto_tree_add_item(h264_nal_tree, hf_h264_nal_nri, tvb, offset, 1, FALSE);
proto_tree_add_item(h264_nal_tree, hf_h264_nal_unit_type, tvb, offset, 1, FALSE);
proto_tree_add_item(h264_nal_tree, hf_h264_type, tvb, offset, 1, FALSE);
offset++;
proto_tree_add_text(h264_tree, tvb, offset, -1, "H264 bitstream");
}/* if tree */
@ -243,9 +479,9 @@ proto_register_h264(void)
FT_UINT8, BASE_DEC, NULL, 0x60,
"NRI", HFILL }
},
{ &hf_h264_nal_unit_type,
{ &hf_h264_type,
{ "NAL unit type", "h264.nal_unit_hdr",
FT_UINT8, BASE_DEC, VALS(h264_nal_unit_type_values), 0x1f,
FT_UINT8, BASE_DEC, VALS(h264_type_values), 0x1f,
"NAL unit type", HFILL }
},
{ &hf_h264_profile,
@ -260,27 +496,27 @@ proto_register_h264(void)
},
{ &hf_h264_constraint_set0_flag,
{ "Constraint_set0_flag", "h264.constraint_set0_flag",
FT_UINT8, BASE_DEC, NULL, 0x01,
FT_UINT8, BASE_DEC, NULL, 0x80,
"Constraint_set0_flag", HFILL }
},
{ &hf_h264_constraint_set1_flag,
{ "Constraint_set1_flag", "h264.constraint_set1_flag",
FT_UINT8, BASE_DEC, NULL, 0x02,
FT_UINT8, BASE_DEC, NULL, 0x40,
"Constraint_set1_flag", HFILL }
},
{ &hf_h264_constraint_set2_flag,
{ "Constraint_set1_flag", "h264.constraint_set2_flag",
FT_UINT8, BASE_DEC, NULL, 0x04,
FT_UINT8, BASE_DEC, NULL, 0x20,
"NRI", HFILL }
},
{ &hf_h264_constraint_set3_flag,
{ "Constraint_set3_flag", "h264.constraint_set3_flag",
FT_UINT8, BASE_DEC, NULL, 0x08,
FT_UINT8, BASE_DEC, NULL, 0x10,
"Constraint_set3_flag", HFILL }
},
{ &hf_h264_reserved_zero_4bits,
{ "Reserved_zero_4bits", "h264.reserved_zero_4bits",
FT_UINT8, BASE_DEC, NULL, 0xf0,
FT_UINT8, BASE_DEC, NULL, 0x0f,
"Reserved_zero_4bits", HFILL }
},
{ &hf_h264_level_idc,
@ -288,7 +524,26 @@ proto_register_h264(void)
FT_UINT8, BASE_DEC, NULL, 0x0,
"Level_id", HFILL }
},
{ &hf_h264_nal_unit,
{ "NAL unit", "h264.nal_unit",
FT_BYTES, BASE_NONE, NULL, 0x0,
"NAL unit", HFILL }
},
{ &hf_h264_forbidden_zero_bit,
{ "Forbidden_zero_bit", "h264.forbidden_zero_bit",
FT_UINT8, BASE_DEC, NULL, 0x80,
"forbidden_zero_bit", HFILL }
},
{ &hf_h264_nal_ref_idc,
{ "Nal_ref_idc", "h264.nal_ref_idc",
FT_UINT8, BASE_DEC, NULL, 0x60,
"nal_ref_idc", HFILL }
},
{&hf_h264_nal_unit_type,
{ "Nal_unit_type", "h264.nal_unit_type",
FT_UINT8, BASE_DEC, VALS(h264_nal_unit_type_vals), 0x1f,
"nal_unit_type", HFILL }
},
};
/* Setup protocol subtree array */
@ -296,6 +551,7 @@ proto_register_h264(void)
&ett_h264,
&ett_h264_profile,
&ett_h264_nal,
&ett_h264_nal_unit,
};
/* Register the protocol name and description */

View File

@ -29,5 +29,6 @@
#define __PACKET_H264_H__
void dissect_h264_profile(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
void dissect_h264_nal_unit(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
#endif /* __PACKET_H264_H__ */

View File

@ -162,8 +162,10 @@ static int hf_media_attribute_field = -1;
static int hf_media_attribute_value = -1;
static int hf_media_encoding_name = -1;
static int hf_media_format_specific_parameter = -1;
static int hf_sdp_fmtp_profile_level_id = -1;
static int hf_sdp_fmtp_mpeg4_profile_level_id = -1;
static int hf_sdp_fmtp_h263_profile = -1;
static int hf_sdp_h264_packetization_mode = -1;
static int hf_sdp_h264_sprop_parameter_sets = -1;
static int hf_SDPh223LogicalChannelParameters = -1;
/* hf_session_attribute hf_media_attribute subfields */
@ -1331,6 +1333,14 @@ static const value_string h263_profile_vals[] =
{ 0, NULL },
};
static const value_string h264_packetization_mode_vals[] =
{
{ 0, "Single NAL mode" },
{ 1, "Non-interleaved mode" },
{ 2, "Interleaved mode" },
{ 0, NULL },
};
/*
* TODO: Make this a more generic routine to dissect fmtp parameters depending on media types
*/
@ -1341,6 +1351,7 @@ decode_sdp_fmtp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset
guint8 *field_name;
gchar *format_specific_parameter;
proto_item *item;
tvbuff_t *data_tvb;
end_offset = offset + tokenlen;
@ -1365,7 +1376,7 @@ decode_sdp_fmtp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset
offset++;
tokenlen = end_offset - offset;
format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
item = proto_tree_add_uint(tree, hf_sdp_fmtp_profile_level_id, tvb, offset, tokenlen,
item = proto_tree_add_uint(tree, hf_sdp_fmtp_mpeg4_profile_level_id, tvb, offset, tokenlen,
atol((char*)format_specific_parameter));
PROTO_ITEM_SET_GENERATED(item);
}
@ -1387,15 +1398,64 @@ decode_sdp_fmtp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset
/* Dissect the H264 profile-level-id parameter */
if (mime_type != NULL && strcmp(mime_type, "H264") == 0) {
if (strcmp(field_name, "profile-level-id") == 0) {
tvbuff_t *h264_profile_tvb;
/* Length includes "=" */
tokenlen = end_offset - offset;
format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
h264_profile_tvb = ascii_bytes_to_tvb(tvb, pinfo, tokenlen, format_specific_parameter);
if(h264_handle && h264_profile_tvb){
dissect_h264_profile(h264_profile_tvb, pinfo, tree);
data_tvb = ascii_bytes_to_tvb(tvb, pinfo, tokenlen, format_specific_parameter);
if(h264_handle && data_tvb){
dissect_h264_profile(data_tvb, pinfo, tree);
}
}else if (strcmp(field_name, "packetization-mode") == 0) {
offset++;
tokenlen = end_offset - offset;
format_specific_parameter = tvb_get_ephemeral_string(tvb, offset, tokenlen);
item = proto_tree_add_uint(tree, hf_sdp_h264_packetization_mode, tvb, offset, tokenlen,
atol((char*)format_specific_parameter));
}else if (strcmp(field_name, "sprop-parameter-sets") == 0) {
/* The value of the parameter is the
base64 [6] representation of the initial
parameter set NAL units as specified in
sections 7.3.2.1 and 7.3.2.2 of [1]. The
parameter sets are conveyed in decoding order,
and no framing of the parameter set NAL units
takes place. A comma is used to separate any
pair of parameter sets in the list.
*/
gchar *data = NULL;
gint comma_offset;
/* Move past '=' */
offset++;
comma_offset = tvb_find_guint8(tvb,offset,-1,',');
if (comma_offset != -1){
tokenlen = comma_offset - offset;
}else{
tokenlen = end_offset - offset;
}
data = tvb_get_ephemeral_string(tvb, offset, tokenlen);
/* proto_tree_add_text(tree, tvb, offset, tokenlen, "String %s",data); */
data_tvb = base64_to_tvb(data);
tvb_set_child_real_data_tvbuff(tvb, data_tvb);
add_new_data_source(pinfo, data_tvb, "h264 prop-parameter-sets");
if(h264_handle && data_tvb){
dissect_h264_nal_unit(data_tvb, pinfo, tree);
if (comma_offset != -1){
/* Second NAL unit */
offset = comma_offset +1;
tokenlen = end_offset - offset;
data = tvb_get_ephemeral_string(tvb, offset, tokenlen);
data_tvb = base64_to_tvb(data);
tvb_set_child_real_data_tvbuff(tvb, data_tvb);
add_new_data_source(pinfo, data_tvb, "h264 prop-parameter-sets 2");
dissect_h264_nal_unit(data_tvb, pinfo, tree);
}
}
}
}
@ -1572,15 +1632,18 @@ static void dissect_sdp_media_attribute(tvbuff_t *tvb, packet_info *pinfo, proto
transport_info->encoding_name);
payload_type = tvb_get_ephemeral_string(tvb, offset, tokenlen);
/* Offset past space after ':' */
offset = next_offset + 1;
while(has_more_pars==TRUE){
next_offset = tvb_find_guint8(tvb,offset,-1,';');
offset = tvb_skip_wsp(tvb,offset,tvb_length_remaining(tvb,offset));
if(next_offset == -1){
has_more_pars = FALSE;
next_offset= tvb_length(tvb);
}else{
}
/* There are 2 - add the first parameter */
@ -1594,6 +1657,7 @@ static void dissect_sdp_media_attribute(tvbuff_t *tvb, packet_info *pinfo, proto
decode_sdp_fmtp(fmtp_tree, tvb, pinfo, offset, tokenlen,
(guint8 *)transport_info->encoding_name);
/* Move offset past "; " and onto firts char */
offset = next_offset + 1;
}
return;
@ -1873,7 +1937,7 @@ proto_register_sdp(void)
{ "IPBCP Command Type",
"ipbcp.command",FT_STRING, BASE_NONE, NULL, 0x0,
"IPBCP Command Type", HFILL }},
{&hf_sdp_fmtp_profile_level_id,
{&hf_sdp_fmtp_mpeg4_profile_level_id,
{ "Level Code",
"sdp.fmtp.profile_level_id",FT_UINT32, BASE_DEC,VALS(mpeg4es_level_indication_vals), 0x0,
"Level Code", HFILL }},
@ -1881,6 +1945,14 @@ proto_register_sdp(void)
{ "Profile",
"sdp.fmtp.h263profile",FT_UINT32, BASE_DEC,VALS(h263_profile_vals), 0x0,
"Profile", HFILL }},
{ &hf_sdp_h264_packetization_mode,
{ "Packetization mode",
"sdp.fmtp.h264_packetization_mode",FT_UINT32, BASE_DEC,VALS(h264_packetization_mode_vals), 0x0,
"Packetization mode", HFILL }},
{ &hf_sdp_h264_sprop_parameter_sets,
{ "Sprop_parameter_sets",
"sdp.h264.sprop_parameter_sets", FT_BYTES, BASE_NONE, NULL, 0x0,
"Sprop_parameter_sets", HFILL }},
{ &hf_SDPh223LogicalChannelParameters,
{ "h223LogicalChannelParameters", "sdp.h223LogicalChannelParameters",
FT_NONE, BASE_NONE, NULL, 0,