/* packet-h264.c
 * Routines for H.264 dissection
 * Copyright 2007 - 2009, Anders Broman <anders.broman[at]ericsson.com>
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 *
 * References:
 * https://tools.ietf.org/html/rfc3984      Obsolete
 * https://tools.ietf.org/html/rfc6184
 * https://tools.ietf.org/html/rfc6190
 * https://www.itu.int/rec/T-REC-H.264/en
 * MS-H264PF https://docs.microsoft.com/en-us/openspecs/office_protocols/ms-h264pf
 */

#include "config.h"


#include <epan/packet.h>
#include <epan/asn1.h>
#include <epan/expert.h>
#include <epan/prefs.h>
#include "packet-h264.h"

void proto_register_h264(void);
void proto_reg_handoff_h264(void);

/* Initialize the protocol and registered fields */
static int proto_h264                                      = -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_start_bit                               = -1;
static int hf_h264_forbidden_bit                           = -1;
static int hf_h264_end_bit                                 = -1;
static int hf_h264_profile                                 = -1;
static int hf_h264_profile_idc                             = -1;
static int hf_h264_rbsp_stop_bit                           = -1;
static int hf_h264_rbsp_trailing_bits                      = -1;
static int hf_h264_constraint_set0_flag                    = -1;
static int hf_h264_constraint_set1_flag                    = -1;
static int hf_h264_constraint_set2_flag                    = -1;
static int hf_h264_constraint_set3_flag                    = -1;
static int hf_h264_constraint_set4_flag                    = -1;
static int hf_h264_constraint_set5_flag                    = -1;
static int hf_h264_reserved_zero_2bits                     = -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;
static int hf_h264_seq_parameter_set_id                    = -1;
static int hf_h264_chroma_format_idc                       = -1;
static int hf_h264_residual_colour_transform_flag          = -1;
static int hf_h264_bit_depth_luma_minus8                   = -1;
static int hf_h264_bit_depth_chroma_minus8                 = -1;
static int hf_h264_qpprime_y_zero_transform_bypass_flag    = -1;
static int hf_h264_seq_scaling_matrix_present_flag         = -1;
static int hf_h264_seq_scaling_list_present_flag           = -1;
static int hf_h264_delta_scale                             = -1;
static int hf_h264_log2_max_frame_num_minus4               = -1;
static int hf_h264_pic_order_cnt_type                      = -1;
static int hf_h264_log2_max_pic_order_cnt_lsb_minus4       = -1;
static int hf_h264_delta_pic_order_always_zero_flag        = -1;
static int hf_h264_offset_for_non_ref_pic                  = -1;
static int hf_h264_offset_for_top_to_bottom_field          = -1;
static int hf_h264_num_ref_frames_in_pic_order_cnt_cycle   = -1;
static int hf_h264_offset_for_ref_frame                    = -1;
static int hf_h264_num_ref_frames                          = -1;
static int hf_h264_gaps_in_frame_num_value_allowed_flag    = -1;
static int hf_h264_pic_width_in_mbs_minus1                 = -1;
static int hf_h264_pic_height_in_map_units_minus1          = -1;
static int hf_h264_frame_mbs_only_flag                     = -1;
static int hf_h264_mb_adaptive_frame_field_flag            = -1;
static int hf_h264_direct_8x8_inference_flag               = -1;
static int hf_h264_frame_cropping_flag                     = -1;
static int hf_h264_frame_crop_left_offset                  = -1;
static int hf_h264_frame_crop_right_offset                 = -1;
static int hf_h264_frame_crop_top_offset                   = -1;
static int hf_h264_frame_crop_bottom_offset                = -1;
static int hf_h264_vui_parameters_present_flag             = -1;
static int hf_h264_pic_parameter_set_id                    = -1;
static int hf_h264_entropy_coding_mode_flag                = -1;
static int hf_h264_pic_order_present_flag                  = -1;
static int hf_h264_num_slice_groups_minus1                 = -1;
static int hf_h264_slice_group_map_type                    = -1;
static int hf_h264_num_ref_idx_l0_active_minus1            = -1;
static int hf_h264_num_ref_idx_l1_active_minus1            = -1;
static int hf_h264_weighted_pred_flag                      = -1;
static int hf_h264_weighted_bipred_idc                     = -1;
static int hf_h264_pic_init_qp_minus26                     = -1;
static int hf_h264_pic_init_qs_minus26                     = -1;
static int hf_h264_chroma_qp_index_offset                  = -1;
static int hf_h264_deblocking_filter_control_present_flag  = -1;
static int hf_h264_constrained_intra_pred_flag             = -1;
static int hf_h264_redundant_pic_cnt_present_flag          = -1;
static int hf_h264_transform_8x8_mode_flag                 = -1;
static int hf_h264_pic_scaling_matrix_present_flag         = -1;
static int hf_h264_second_chroma_qp_index_offset           = -1;
static int hf_h264_primary_pic_type                        = -1;
static int hf_h264_par_profile                             = -1;
static int hf_h264_par_profile_b                           = -1;
static int hf_h264_par_profile_m                           = -1;
static int hf_h264_par_profile_e                           = -1;
static int hf_h264_par_profile_h                           = -1;
static int hf_h264_par_profile_h10                         = -1;
static int hf_h264_par_profile_h4_2_2                      = -1;
static int hf_h264_par_profile_h4_4_4                      = -1;
/* static int hf_h264_par_add_mode_sup                        = -1; */
static int hf_h264_par_AdditionalModesSupported            = -1;
static int hf_h264_par_add_mode_sup_rcdo                   = -1;
static int hf_h264_par_ProfileIOP                          = -1;
static int hf_h264_par_constraint_set0_flag                = -1;
static int hf_h264_par_constraint_set1_flag                = -1;
static int hf_h264_par_constraint_set2_flag                = -1;
/* Packetization Values */
static int hf_h264_nalu_size                               = -1;
static int hf_h264_don                                     = -1;
static int hf_h264_dond                                    = -1;
static int hf_h264_ts_offset16                             = -1;
static int hf_h264_ts_offset24                             = -1;
/* Extension Header */
static int hf_h264_nal_extension_subtype                   = -1;
static int hf_h264_nal_extension_j                         = -1;
static int hf_h264_nal_extension_k                         = -1;
static int hf_h264_nal_extension_l                         = -1;

/* SEI Decoding Information */
static int hf_h264_sei_uuid                                = -1;
/* Microsoft Layout SEI */
static int hf_h264_sei_ms_lpb                              = -1;
static int hf_h264_sei_ms_layout_p                         = -1;
static int hf_h264_sei_ms_layout_ldsize                    = -1;
static int hf_h264_sei_ms_layer_desc_coded_width           = -1;
static int hf_h264_sei_ms_layer_desc_coded_height          = -1;
static int hf_h264_sei_ms_layer_desc_display_width         = -1;
static int hf_h264_sei_ms_layer_desc_display_height        = -1;
static int hf_h264_sei_ms_layer_desc_bitrate               = -1;
static int hf_h264_sei_ms_layer_desc_frame_rate            = -1;
static int hf_h264_sei_ms_layer_desc_layer_type            = -1;
static int hf_h264_sei_ms_layer_desc_prid                  = -1;
static int hf_h264_sei_ms_layer_desc_cb                    = -1;
/* Microsoft Bitstream SEI */
static int hf_h264_sei_ms_bitstream_ref_frame_cnt          = -1;
static int hf_h264_sei_ms_bitstream_num_nalus              = -1;
static int hf_h264_sei_iso_sec_info                        = -1;
/* Microsoft Crop SEI */
static int hf_h264_sei_ms_crop_num_data                    = -1;
static int hf_h264_sei_ms_crop_info_type                   = -1;
static int hf_h264_sei_ms_crop_confidence_level            = -1;
static int hf_h264_sei_ms_crop_frame_left_offset           = -1;
static int hf_h264_sei_ms_crop_frame_right_offset          = -1;
static int hf_h264_sei_ms_crop_frame_top_offset            = -1;
static int hf_h264_sei_ms_crop_frame_bottom_offset         = -1;
/* SVC NAL Header Extension Values Annex G.7.3.1.1 */
static int hf_h264_nal_hdr_ext_svc                         = -1;
static int hf_h264_nal_hdr_ext_i                           = -1;
static int hf_h264_nal_hdr_ext_prid                        = -1;
static int hf_h264_nal_hdr_ext_n                           = -1;
static int hf_h264_nal_hdr_ext_did                         = -1;
static int hf_h264_nal_hdr_ext_qid                         = -1;
static int hf_h264_nal_hdr_ext_tid                         = -1;
static int hf_h264_nal_hdr_ext_u                           = -1;
static int hf_h264_nal_hdr_ext_d                           = -1;
static int hf_h264_nal_hdr_ext_o                           = -1;
static int hf_h264_nal_hdr_ext_rr                          = -1;
/* PACSI Values */
static int hf_h264_pacsi_x                                 = -1;
static int hf_h264_pacsi_y                                 = -1;
static int hf_h264_pacsi_t                                 = -1;
static int hf_h264_pacsi_a                                 = -1;
static int hf_h264_pacsi_p                                 = -1;
static int hf_h264_pacsi_c                                 = -1;
static int hf_h264_pacsi_s                                 = -1;
static int hf_h264_pacsi_e                                 = -1;
static int hf_h264_pacsi_tl0picidx                         = -1;
static int hf_h264_pacsi_idrpicid                          = -1;
static int hf_h264_pacsi_donc                              = -1;

/* VUI parameters */
static int hf_h264_aspect_ratio_info_present_flag          = -1;
static int hf_h264_aspect_ratio_idc                        = -1;
static int hf_h264_sar_width                               = -1;
static int hf_h264_sar_height                              = -1;
static int hf_h264_overscan_info_present_flag              = -1;
static int hf_h264_overscan_appropriate_flag               = -1;
static int hf_h264_video_signal_type_present_flag          = -1;
static int hf_h264_video_format                            = -1;
static int hf_h264_video_full_range_flag                   = -1;
static int hf_h264_colour_description_present_flag         = -1;
static int hf_h264_colour_primaries                        = -1;
static int hf_h264_transfer_characteristics                = -1;
static int hf_h264_matrix_coefficients                     = -1;
static int hf_h264_chroma_loc_info_present_flag            = -1;
static int hf_h264_chroma_sample_loc_type_top_field        = -1;
static int hf_h264_chroma_sample_loc_type_bottom_field     = -1;
static int hf_h264_timing_info_present_flag                = -1;
static int hf_h264_num_units_in_tick                       = -1;
static int hf_h264_time_scale                              = -1;
static int hf_h264_fixed_frame_rate_flag                   = -1;
static int hf_h264_nal_hrd_parameters_present_flag         = -1;
static int hf_h264_vcl_hrd_parameters_present_flag         = -1;
static int hf_h264_low_delay_hrd_flag                      = -1;
static int hf_h264_pic_struct_present_flag                 = -1;
static int hf_h264_bitstream_restriction_flag              = -1;
static int hf_h264_motion_vectors_over_pic_boundaries_flag = -1;
static int hf_h264_max_bytes_per_pic_denom                 = -1;
static int hf_h264_max_bits_per_mb_denom                   = -1;
static int hf_h264_log2_max_mv_length_horizontal           = -1;
static int hf_h264_log2_max_mv_length_vertical             = -1;
static int hf_h264_num_reorder_frames                      = -1;
static int hf_h264_max_dec_frame_buffering                 = -1;
static int hf_h264_cpb_cnt_minus1                          = -1;
static int hf_h264_bit_rate_scale                          = -1;
static int hf_h264_cpb_size_scale                          = -1;
static int hf_h264_bit_rate_value_minus1                   = -1;
static int hf_h264_cpb_size_value_minus1                   = -1;
static int hf_h264_cbr_flag                                = -1;
static int hf_h264_initial_cpb_removal_delay_length_minus1 = -1;
static int hf_h264_cpb_removal_delay_length_minus1         = -1;
static int hf_h264_dpb_output_delay_length_minus11         = -1;
static int hf_h264_time_offset_length                      = -1;

static int hf_h264_first_mb_in_slice                       = -1;
static int hf_h264_slice_type                              = -1;
static int hf_h264_slice_id                                = -1;
static int hf_h264_payloadsize                             = -1;
static int hf_h264_payloadtype                             = -1;
/* static int hf_h264_frame_num                               = -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_fua                                    = -1;
static int ett_h264_stream                                 = -1;
static int ett_h264_nal_unit                               = -1;
static int ett_h264_par_profile                            = -1;
static int ett_h264_par_AdditionalModesSupported           = -1;
static int ett_h264_par_ProfileIOP                         = -1;
static int ett_h264_ms_layer_description                   = -1;
static int ett_h264_ms_crop_data                           = -1;
static int ett_h264_ni_mtap                                = -1;

static expert_field ei_h264_undecoded = EI_INIT;
static expert_field ei_h264_ms_layout_wrong_length = EI_INIT;
static expert_field ei_h264_oversized_exp_golomb_code = EI_INIT;
static expert_field ei_h264_bad_nal_length = EI_INIT;
static expert_field ei_h264_nal_unit_type_reserved = EI_INIT;
static expert_field ei_h264_nal_unit_type_unspecified = EI_INIT;

static dissector_handle_t h264_name_handle;

static dissector_handle_t h264_handle;

/* syntax tables in subclause 7.3 is equal to
 * ue(v), me(v), se(v), or te(v).
 */
typedef enum {
    H264_UE_V = 0,
    H264_ME_V = 1,
    H264_SE_V = 2,
    H264_TE_V = 3
} h264_golomb_descriptors;


static const true_false_string h264_f_bit_vals = {
  "Bit errors or other syntax violations",
  "No bit errors or other syntax violations"
};

static const true_false_string h264_start_bit_vals = {
  "the first packet of FU-A picture",
  "Not the first packet of FU-A picture"
};

static const true_false_string h264_end_bit_vals = {
  "the last packet of FU-A picture",
  "Not the last packet of FU-A picture"
};

#if 0
static const true_false_string h264_forbidden_bit_vals = {
  "Forbidden Bit of FU-A",
  "Not Forbidden Bit of FU-A"
};
#endif

#define H264_SEQ_PAR_SET        7
#define H264_PIC_PAR_SET        8
#define H264_PREFIX             14
#define H264_STAP_A             24
#define H264_STAP_B             25
#define H264_MTAP16             26
#define H264_MTAP24             27
#define H264_PACSI              30
#define H264_EXTENSION          31


static const value_string h264_type_values[] = {
    {  0,   "Undefined" },
    {  1,   "NAL unit - Coded slice of a non-IDR picture" },    /* Single NAL unit packet per H.264 */
    {  2,   "NAL unit - Coded slice data partition A" },
    {  3,   "NAL unit - Coded slice data partition B" },
    {  4,   "NAL unit - Coded slice data partition C" },
    {  5,   "NAL unit - Coded slice of an IDR picture" },
    {  6,   "NAL unit - Supplemental enhancement information (SEI)" },
    { H264_SEQ_PAR_SET, "NAL unit - Sequence parameter set" },              /* 7 */
    { H264_PIC_PAR_SET, "NAL unit - Picture parameter set" },               /* 8 */
    {  9,   "NAL unit - Access unit delimiter" },
    { 10,   "NAL unit - End of sequence" },
    { 11,   "NAL unit - End of stream" },
    { 12,   "NAL unit - Filler data" },
    { 13,   "NAL unit - Sequence parameter set extension" },
    { H264_PREFIX,   "NAL unit - Prefix" },
    { 15,   "NAL unit - Subset sequence parameter set" },
    { 16,   "NAL unit - Reserved" },
    { 17,   "NAL unit - Reserved" },
    { 18,   "NAL unit - Reserved" },
    { 19,   "NAL unit - Coded slice of an auxiliary coded picture without partitioning" },
    { 20,   "NAL unit - Coded slice extension" },
    { 21,   "NAL unit - Coded slice extension for depth view components" },
    { 22,   "NAL unit - Reserved" },
    { 23,   "NAL unit - Reserved" },
    { 24,   "Single-time aggregation packet A (STAP-A)" },
    { 25,   "Single-time aggregation packet B (STAP-B)" },
    { 26,   "Multi-time aggregation packet 16 (MTAP16)" },
    { 27,   "Multi-time aggregation packet 24 (MTAP24)" },
    { 28,   "Fragmentation unit A (FU-A)" },
    { 29,   "Fragmentation unit B (FU-B)" },
    { 30,   "NAL unit - Payload Content Scalability Information (PACSI)" },
    { 31,   "NAL unit - Extended NAL Header" },
    { 0,    NULL }
};

static const value_string h264_type_summary_values[] = {
    {  0,   "Undefined" },
    {  1,   "non-IDR-Slice" },    /* Single NAL unit packet per H.264 */
    {  2,   "Slice-A" },
    {  3,   "Slice-B" },
    {  4,   "Slice-C" },
    {  5,   "IDR-Slice" },
    {  6,   "SEI" },
    { H264_SEQ_PAR_SET, "SPS" },              /* 7 */
    { H264_PIC_PAR_SET, "PPS" },               /* 8 */
    {  9,   "Access-Delimiter" },
    { 10,   "End-of-Seq" },
    { 11,   "End-of-Stream" },
    { 12,   "Filler" },
    { 13,   "SPS-Ext" },
    { H264_PREFIX,   "Prefix" },
    { 15,   "Reserved" },
    { 16,   "Reserved" },
    { 17,   "Reserved" },
    { 18,   "Reserved" },
    { 19,   "Slice-Aux" },
    { 20,   "Slice-Ext" },
    { 21,   "Slice-Ext-Depth" },
    { 22,   "Reserved" },
    { 23,   "Reserved" },
    { 24,   "STAP-A" },
    { 25,   "STAP-B" },
    { 26,   "MTAP16" },
    { 27,   "MTAP24" },
    { 28,   "FU-A" },
    { 29,   "FU-B" },
    { 30,   "PACSI" },
    { 31,   "EXT" },
    { 0,    NULL }
};

/* Extension Subtype Strings RFC 6190 4.3 */
static const value_string h264_subtype_values[] = {
    {  0,   "Reserved" },
    {  1,   "NAL Unit - Empty" },
    {  2,   "Non-interleaved Multi-Time Aggregation Packet (NI-MTAP)" },
    { 0,    NULL }
};
static const value_string h264_subtype_summary_values[] = {
    {  0,   "Reserved" },
    {  1,   "Empty" },
    {  2,   "NI-MTAP" },
    { 0,    NULL }
};

/* A.2 Profiles */
static const value_string h264_profile_idc_values[] = {
    {  66,  "Baseline profile" },
    {  77,  "Main profile" },
    {  83,  "Scalable Baseline" },
    {  86,  "Scalable High" },
    {  88,  "Extended profile" },
    { 100,  "High profile" },
    { 110,  "High 10 profile" },
    { 118,  "Multi-view High" },
    { 122,  "High 4:2:2 profile" },
    { 128,  "Stereo High" },
    { 144,  "High 4:4:4 profile" },
    { 0,    NULL }
};

/* Table A-1 - Level limits */
static const value_string h264_level_bitrate_values[] = {
    { 10,   "64 kb/s" },
    { 11,   "192 kb/s" },
    { 12,   "384 kb/s" },
    { 13,   "768 kb/s" },
    { 20,   "2 Mb/s" },
    { 21,   "4 Mb/s" },
    { 22,   "4 Mb/s" },
    { 30,   "10 Mb/s" },
    { 31,   "14 Mb/s" },
    { 32,   "20 Mb/s" },
    { 40,   "20 Mb/s" },
    { 41,   "50 Mb/s" },
    { 42,   "50 Mb/s" },
    { 50,   "135 Mb/s" },
    { 51,   "240 Mb/s" },
    { 52,   "240 Mb/s" },
    { 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,   "Prefix" },
    { 15,   "Subset sequence parameter set" },
    { 16,   "Reserved" },
    { 17,   "Reserved" },
    { 18,   "Reserved" },
    { 19,   "Coded slice of an auxiliary coded picture without partitioning" },
    { 20,   "Coded slice extension" },
    { 21,   "Coded slice extension for depth view components" },
    { 22,   "Reserved" },
    { 23,   "Reserved" },
    { 24,   "Unspecified" },
    { 25,   "Unspecified" },
    { 26,   "Unspecified" },
    { 27,   "Unspecified" },
    { 28,   "FU-A" },
    { 29,   "Unspecified" },
    { 30,   "Unspecified" },
    { 31,   "Unspecified" },
    { 0,    NULL }
};

static const value_string h264_slice_group_map_type_vals[] = {
    { 0,    "Interleaved slice groups" },
    { 1,    "Dispersed slice group mapping" },
    { 2,    "One or more foreground slice groups and a leftover slice group" },
    { 3,    "Changing slice groups" },
    { 4,    "Changing slice groups" },
    { 5,    "Changing slice groups" },
    { 6,    "Explicit assignment of a slice group to each slice group map unit" },
    { 0,    NULL }
};

/* Table 7-5 Meaning of primary_pic_type */
static const value_string h264_primary_pic_type_vals[] = {
    { 0,    "2, 7" },
    { 1,    "0, 2, 5, 7" },
    { 2,    "0, 1, 2, 5, 6, 7" },
    { 3,    "4, 9" },
    { 4,    "3, 4, 8, 9" },
    { 5,    "2, 4, 7, 9" },
    { 6,    "0, 2, 3, 4, 5, 7, 8, 9" },
    { 7,    "0, 1, 2, 3, 4, 5, 6, 7, 8, 9" },
    { 0,    NULL }
};

/* Table 7-6 Name association to slice_type */
static const value_string h264_slice_type_vals[] = {
    { 0,    "P (P slice)" },
    { 1,    "B (B slice)" },
    { 2,    "I (I slice)" },
    { 3,    "SP (SP slice)" },
    { 4,    "SI (SI slice)" },
    { 5,    "P (P slice)" },
    { 6,    "B (B slice)" },
    { 7,    "I (I slice)" },
    { 8,    "SP (SP slice)" },
    { 9,    "SI (SI slice)" },
    { 0,    NULL }
};

/* Microsoft Frame per second index */
static const value_string h264_sei_ms_frame_values[] = {
    { 0,   "7.5 fps" },
    { 1,   "12.5 fps" },
    { 2,   "15 fps" },
    { 3,   "25 fps" },
    { 4,   "30 fps" },
    { 5,   "50 fps" },
    { 6,   "60 fps" },
    { 0,    NULL }
};

/* Microsoft UUIDs from MS-H264-PF */
#define MS_LAYOUT       0
#define MS_CROPPING     1
#define MS_BITSTREAM    2
static const e_guid_t ms_guids[3] = {
    { 0x139FB1A9, 0x446A, 0x4DEC, {0x8C, 0xBF, 0x65, 0xB1, 0xE1, 0x2D, 0x2C, 0xFD}},    /* Stream Layout */
    { 0xBB7FC1A0, 0x6986, 0x4052, {0x90, 0xF0, 0x09, 0x29, 0x21, 0x75, 0x39, 0xCF}},    /* Cropping Information*/
    { 0x05FBC6B9, 0x5A80, 0x40E5, {0xA2, 0x2A, 0xAB, 0x40, 0x20, 0x26, 0x7E, 0x26}}     /* Bitstream Information */
};

static int
dissect_h264(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_);

/* byte_aligned( ) is specified as follows.
 * - If the current position in the bitstream is on a byte boundary, i.e.,
 *   the next bit in the bitstream is the first bit in a byte,
 *   the return value of byte_aligned( ) is equal to TRUE.
 * - Otherwise, the return value of byte_aligned( ) is equal to FALSE.
 */
static gboolean
h264_byte_aligned(int bit_offset)
{
    if (bit_offset&0x3)
        return FALSE;

    return TRUE;
}

/* Expect a tvb and a bit offset into the tvb
 * returns the value and bit_offset
 */
#define cVALS(x) (const value_string*)(x)

static guint32
dissect_h264_exp_golomb_code(proto_tree *tree, int hf_index, tvbuff_t *tvb, gint *start_bit_offset, h264_golomb_descriptors descriptor)
/*(tvbuff_t *tvb, gint *start_bit_offset) */
{
    proto_item *ti;

    gint     leading_zero_bits, bit_offset, start_offset;
    guint32  codenum, mask, value, tmp;
    gint32   se_value = 0;
    gint     b;
    char    *str;
    int      bit;
    int      i;
    gboolean overflow = FALSE;
    header_field_info *hf_field = NULL;

    start_offset = *start_bit_offset>>3;

    if (hf_index > -1) {
        hf_field = proto_registrar_get_nth(hf_index);
    }

    if (hf_field) {
        switch (descriptor) {
        case H264_SE_V:
            DISSECTOR_ASSERT_FIELD_TYPE(hf_field, FT_INT32);
            break;

        default:
            DISSECTOR_ASSERT_FIELD_TYPE(hf_field, FT_UINT32);
            break;
        }
    }

    bit_offset = *start_bit_offset;

    /* prepare the string */
    str = (char *)wmem_alloc(wmem_packet_scope(), 256);
    str[0] = '\0';
    for (bit=0; bit<((int)(bit_offset&0x07)); bit++) {
        if (bit && (!(bit%4))) {
            (void) g_strlcat(str, " ", 256);
        }
        (void) g_strlcat(str,".", 256);
    }


    leading_zero_bits = -1;
    for (b = 0; !b; leading_zero_bits++) {
        if (bit && (!(bit%4))) {
            (void) g_strlcat(str, " ", 256);
        }
        if (bit && (!(bit%8))) {
            (void) g_strlcat(str, " ", 256);
        }
        b = tvb_get_bits8(tvb, bit_offset, 1);
        if (b != 0) {
            (void) g_strlcat(str, "1", 256);
        } else {
            (void) g_strlcat(str, "0", 256);
        }
        bit++;
        bit_offset++;
    }

    /* XXX: This could be handled in the general case and reduce code
     * duplication. */
    if (leading_zero_bits == 0) {
        codenum = 0;
        *start_bit_offset = bit_offset;
        for (; bit%8; bit++) {
            if (bit && (!(bit%4))) {
                (void) g_strlcat(str, " ", 256);
            }
        (void) g_strlcat(str,".", 256);
        }
        if (hf_field) {
            (void) g_strlcat(str," = ", 256);
            (void) g_strlcat(str, hf_field->name, 256);
            switch (descriptor) {
            case H264_SE_V:
                /* if the syntax element is coded as se(v),
                 * the value of the syntax element is derived by invoking the
                 * mapping process for signed Exp-Golomb codes as specified in
                 * subclause 9.1.1 with codeNum as the input.
                 */
                if (hf_field->type == FT_INT32) {
                    if (hf_field->strings) {
                        proto_tree_add_int_format(tree, hf_index, tvb, start_offset, 1, codenum,
                              "%s: %s (%d)",
                              str,
                              val_to_str_const(codenum, cVALS(hf_field->strings), "Unknown "),
                              codenum);
                    } else {
                        switch (hf_field->display) {
                            case BASE_DEC:
                                proto_tree_add_int_format(tree, hf_index, tvb, start_offset, 1, codenum,
                                     "%s: %d",
                                      str,
                                      codenum);
                                break;
                            default:
                                DISSECTOR_ASSERT_NOT_REACHED();
                                break;
                        }
                    }
                }
                return codenum;
            default:
                break;
            }
            if (hf_field->type == FT_UINT32) {
                if (hf_field->strings) {
                    proto_tree_add_uint_format(tree, hf_index, tvb, start_offset, 1, codenum,
                          "%s: %s (%u)",
                          str,
                          val_to_str_const(codenum, cVALS(hf_field->strings), "Unknown "),
                          codenum);
                } else {
                    switch (hf_field->display) {
                        case BASE_DEC:
                            proto_tree_add_uint_format(tree, hf_index, tvb, start_offset, 1, codenum,
                                 "%s: %u",
                                  str,
                                  codenum);
                            break;
                        case BASE_HEX:
                            proto_tree_add_uint_format(tree, hf_index, tvb, start_offset, 1, codenum,
                                 "%s: 0x%x",
                                  str,
                                  codenum);
                            break;
                        default:
                            DISSECTOR_ASSERT_NOT_REACHED();
                            break;
                    }
                }
            } else {
                /* Only allow guint32 */
                DISSECTOR_ASSERT_NOT_REACHED();
            }
        }
        return codenum;
    }

    /*
    Syntax elements coded as ue(v), me(v), or se(v) are Exp-Golomb-coded. Syntax elements coded as te(v) are truncated
    Exp-Golomb-coded. The parsing process for these syntax elements begins with reading the bits starting at the current
    location in the bitstream up to and including the first non-zero bit, and counting the number of leading bits that are
    equal to 0. This process is specified as follows:
    leadingZeroBits = -1;
    for (b = 0; !b; leadingZeroBits++)
    b = read_bits( 1 )
    The variable codeNum is then assigned as follows:
    codeNum = 2leadingZeroBits - 1 + read_bits( leadingZeroBits )
    where the value returned from read_bits( leadingZeroBits ) is interpreted as a binary representation of an unsigned
    integer with most significant bit written first.
    */
    if (leading_zero_bits > 32) {
        overflow = TRUE;
        codenum = G_MAXUINT32;
        if (descriptor == H264_SE_V) {
            value = tvb_get_bits32(tvb, bit_offset + 32*(leading_zero_bits / 32), leading_zero_bits % 32, ENC_BIG_ENDIAN);
            if (value % 2) {
                se_value = G_MININT32;
            } else {
                se_value = G_MAXINT32;
            }
        }
    } else if (leading_zero_bits == 32) {
        value = tvb_get_bits32(tvb, bit_offset, leading_zero_bits, ENC_BIG_ENDIAN);
        codenum = G_MAXUINT32;
        /* Only one value doesn't overflow a 32 bit integer, but they're
         * different for unsigned and signed (because codenum G_MAXUINT32 maps
         * to G_MAXINT32 + 1 and G_MAXUINT32 + 1 maps to G_MININT32.) */
        if (descriptor == H264_SE_V) {
            if (value != 1) {
                overflow = TRUE;
            }
            if (value % 2) {
                se_value = G_MININT32;
            } else {
                se_value = G_MAXINT32;
            }
        } else {
            if (value != 0) {
                overflow = TRUE;
            }
        }
        mask = 1U << 31;
    } else {
        if (leading_zero_bits > 16)
            value = tvb_get_bits32(tvb, bit_offset, leading_zero_bits, ENC_BIG_ENDIAN);
        else if (leading_zero_bits > 8)
            value = tvb_get_bits16(tvb, bit_offset, leading_zero_bits, ENC_BIG_ENDIAN);
        else
            value = tvb_get_bits8(tvb, bit_offset, leading_zero_bits);

        codenum = 1;
        codenum = codenum << leading_zero_bits;
        mask = codenum>>1;
        codenum = (codenum-1) + value;

        if (descriptor == H264_SE_V) {
            /* if the syntax element is coded as se(v),
             * the value of the syntax element is derived by invoking the
             * mapping process for signed Exp-Golomb codes as specified in
             * subclause 9.1.1 with codeNum as the input.
             *      k+1
             * (-1)    Ceil( k/2 )
             */
            if (codenum & 1) {
                se_value = (codenum + 1) >> 1;
            } else {
                se_value = 0 - (codenum >> 1);
            }
        }
    }

    bit_offset = bit_offset + leading_zero_bits;

    if (overflow) {
        *start_bit_offset = bit_offset;
        /* We will probably get a BoundsError later in the packet. */
        if (descriptor == H264_SE_V) {
            ti = proto_tree_add_int_format_value(tree, hf_index, tvb, start_offset, (bit_offset >> 3) - start_offset + 1, codenum, "Invalid value (%d leading zero bits), clamped to %" PRId32, leading_zero_bits, se_value);
            expert_add_info(NULL, ti, &ei_h264_oversized_exp_golomb_code);
            return se_value;
        } else {
            ti = proto_tree_add_uint_format_value(tree, hf_index, tvb, start_offset, (bit_offset >> 3) - start_offset + 1, codenum, "Invalid value (%d leading zero bits), clamped to %" PRIu32, leading_zero_bits, codenum);
            expert_add_info(NULL, ti, &ei_h264_oversized_exp_golomb_code);
            return codenum;
        }
    }

    /* read the bits for the int */
    for (i=0; i<leading_zero_bits; i++) {
        if (bit && (!(bit%4))) {
            (void) g_strlcat(str, " ", 256);
        }
        if (bit && (!(bit%8))) {
            (void) g_strlcat(str, " ", 256);
        }
        bit++;
        tmp = value & mask;
        if (tmp != 0) {
            (void) g_strlcat(str, "1", 256);
        } else {
            (void) g_strlcat(str, "0", 256);
        }
        mask = mask>>1;
    }
    for ( ; bit%8; bit++) {
        if (bit && (!(bit%4))) {
            (void) g_strlcat(str, " ", 256);
        }
        (void) g_strlcat(str,".", 256);
    }

    if (hf_field) {
        (void) g_strlcat(str," = ", 256);
        (void) g_strlcat(str, hf_field->name, 256);
        switch (descriptor) {
        case H264_SE_V:
            (void) g_strlcat(str,"(se(v))", 256);
            /* if the syntax element is coded as se(v),
             * the value of the syntax element is derived by invoking the
             * mapping process for signed Exp-Golomb codes as specified in
             * subclause 9.1.1 with codeNum as the input.
             */
            break;
        default:
        break;
        }
        if (descriptor == H264_UE_V) {
            if (hf_field->strings) {
                proto_tree_add_uint_format(tree, hf_index, tvb, start_offset, 1, codenum,
                          "%s: %s (%u)",
                          str,
                          val_to_str_const(codenum, cVALS(hf_field->strings), "Unknown "),
                          codenum);
            } else {
                switch (hf_field->display) {
                    case BASE_DEC:
                        proto_tree_add_uint_format(tree, hf_index, tvb, start_offset, 1, codenum,
                             "%s: %u",
                              str,
                              codenum);
                        break;
                    case BASE_HEX:
                        proto_tree_add_uint_format(tree, hf_index, tvb, start_offset, 1, codenum,
                             "%s: 0x%x",
                              str,
                              codenum);
                        break;
                    default:
                        DISSECTOR_ASSERT_NOT_REACHED();
                        break;
                }
            }
        } else if (descriptor == H264_SE_V) {
            if (hf_field->strings) {
                proto_tree_add_int_format(tree, hf_index, tvb, start_offset, 1, codenum,
                          "%s: %s (%d)",
                          str,
                          val_to_str_const(codenum, cVALS(hf_field->strings), "Unknown "),
                          se_value);
            } else {
                switch (hf_field->display) {
                    case BASE_DEC:
                        proto_tree_add_int_format(tree, hf_index, tvb, start_offset, 1, codenum,
                             "%s: %d",
                              str,
                              se_value);
                        break;
                    default:
                        DISSECTOR_ASSERT_NOT_REACHED();
                        break;
                }
            }
            *start_bit_offset = bit_offset;
            return se_value;

        } else {
            DISSECTOR_ASSERT_NOT_REACHED();
        }
    }

    *start_bit_offset = bit_offset;
    return codenum;
}

/* This function is adapted to parsing NAL units from SDP data where the
 * base64 coding may add extra padding
 * Returns TRUE if there is a non-zero bit in remaining of tvb (skipping the current bit)
 *         FALSE if the rest of the tvb is zeros
 */

static gboolean
more_rbsp_data(proto_tree *tree _U_, tvbuff_t *tvb, packet_info *pinfo _U_, gint bit_offset)
{
    int    current_bit_offset;
    int    byte_offset;
    int    tvb_length;
    int    significant_bits_mask;
    int    i;
    guint8 current_byte;

    /* XXX might not be the best way of doing things but:
     * Search in the tvb for the first '1' bit
     * assuming that it's the RTBSP stop bit or
     * some data representation
     */

    /*Skip current treating bit*/
    current_bit_offset = bit_offset + 1;

    /*Mask for non processed bits of the current byte*/
    significant_bits_mask = (1 << (8 - (current_bit_offset & 0x07))) - 1;

    /* Set offset to the byte we are treating */
    byte_offset = current_bit_offset >> 3;

    tvb_length = tvb_reported_length(tvb);

    for (i = byte_offset; i < tvb_length; i++) {
        current_byte = tvb_get_guint8(tvb, i);

        if ((current_byte & significant_bits_mask) != 0) {
            return TRUE;
        }

        /* For the rest of bytes every bits are significant*/
        significant_bits_mask = 0xFF;
    }

    return FALSE;
}

static int
dissect_h264_rbsp_trailing_bits(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint bit_offset)
{
    gint remaining_bits=0;

    proto_tree_add_bits_item(tree, hf_h264_rbsp_stop_bit, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    if ((bit_offset&0x7) != 0) {
        remaining_bits = 8 - (bit_offset&0x7);
        proto_tree_add_bits_item(tree, hf_h264_rbsp_trailing_bits, tvb, bit_offset, remaining_bits, ENC_BIG_ENDIAN);
    }

    return bit_offset+remaining_bits;
}

/*
 * 7.3.3 Slice header syntax
 * slice_header( )
 * XXX Just parse a few bytes
 */
static int
dissect_h264_slice_header(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint bit_offset)
{
    /* first_mb_in_slice 2 ue(v) */
    dissect_h264_exp_golomb_code(tree, hf_h264_first_mb_in_slice, tvb, &bit_offset, H264_UE_V);

    /* slice_type 2 ue(v) */
    dissect_h264_exp_golomb_code(tree, hf_h264_slice_type, tvb, &bit_offset, H264_UE_V);

    /* pic_parameter_set_id 2 ue(v) */
    dissect_h264_exp_golomb_code(tree, hf_h264_pic_parameter_set_id, tvb, &bit_offset, H264_UE_V);

    /* frame_num 2 u(v) */
    /*
     * represented by log2_max_frame_num_minus4 + 4 bits in
     * the bitstream
     * proto_tree_add_bits_item(tree, hf_h264_frame_num, tvb, bit_offset, 4, ENC_BIG_ENDIAN);
     */

    return bit_offset;
}

/* 7.3.2.1.1 Scaling list syntax
 *
 * scaling_list( scalingList, sizeOfScalingList, useDefaultScalingMatrixFlag )
 */
static int
dissect_h264_scaling_list(proto_tree *tree, tvbuff_t *tvb, gint bit_offset, int* hf_index_scalinglist,
                          guint8 sizeOfScalingList)
{
    guint8 j;
    gint32 lastScale = 8;
    gint32 nextScale = 8;
    gint32 delta_scale;

    for (j = 0; j < sizeOfScalingList; j++) {
      if (nextScale != 0) {
          /* delta_scale 0 | 1 se(v) */
          delta_scale = dissect_h264_exp_golomb_code(tree, hf_h264_delta_scale, tvb, &bit_offset, H264_SE_V);
          nextScale = ( lastScale + delta_scale + 256 ) % 256;
          /* hf_index_usedefaultscalingmatrixflag = ( j == 0 && nextScale == 0 ); */
      }
      hf_index_scalinglist[ j ] = ( nextScale == 0 ) ? lastScale : nextScale;
      lastScale = hf_index_scalinglist[ j ];
    }

    return bit_offset;
}

/* E.1.2 HRD parameters syntax */
static int
dissect_h264_hrd_parameters(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint bit_offset)
{
    guint8 cpb_cnt_minus1;
    int    SchedSelIdx;


    /* cpb_cnt_minus1 0 ue(v) */
    cpb_cnt_minus1 = dissect_h264_exp_golomb_code(tree, hf_h264_cpb_cnt_minus1, tvb, &bit_offset, H264_UE_V);

    /* bit_rate_scale 0 u(4) */
    proto_tree_add_bits_item(tree, hf_h264_bit_rate_scale, tvb, bit_offset, 4, ENC_BIG_ENDIAN);
    bit_offset = bit_offset + 4;

    /* cpb_size_scale 0 u(4) */
    proto_tree_add_bits_item(tree, hf_h264_cpb_size_scale, tvb, bit_offset, 4, ENC_BIG_ENDIAN);
    bit_offset = bit_offset + 4;
    /* for (SchedSelIdx = 0; SchedSelIdx <= cpb_cnt_minus1; SchedSelIdx++) { */
    for (SchedSelIdx = 0; SchedSelIdx <= cpb_cnt_minus1; SchedSelIdx++) {

        /* bit_rate_value_minus1[ SchedSelIdx ] 0 ue(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_bit_rate_value_minus1, tvb, &bit_offset, H264_UE_V);

        /* cpb_size_value_minus1[ SchedSelIdx ] 0 ue(v)*/
        dissect_h264_exp_golomb_code(tree, hf_h264_cpb_size_value_minus1, tvb, &bit_offset, H264_UE_V);

        /* cbr_flag[ SchedSelIdx ] 0 u(1) */
        proto_tree_add_bits_item(tree, hf_h264_cbr_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
        bit_offset++;
    }
    /* initial_cpb_removal_delay_length_minus1 0 u(5) */
    proto_tree_add_bits_item(tree, hf_h264_initial_cpb_removal_delay_length_minus1, tvb, bit_offset, 5, ENC_BIG_ENDIAN);
    bit_offset = bit_offset + 5;

    /* cpb_removal_delay_length_minus1 0 u(5) */
    proto_tree_add_bits_item(tree, hf_h264_cpb_removal_delay_length_minus1, tvb, bit_offset, 5, ENC_BIG_ENDIAN);
    bit_offset = bit_offset + 5;

    /* dpb_output_delay_length_minus1 0 u(5) */
    proto_tree_add_bits_item(tree, hf_h264_dpb_output_delay_length_minus11, tvb, bit_offset, 5, ENC_BIG_ENDIAN);
    bit_offset = bit_offset + 5;

    /* time_offset_length 0 u(5) */
    proto_tree_add_bits_item(tree, hf_h264_time_offset_length, tvb, bit_offset, 5, ENC_BIG_ENDIAN);
    bit_offset = bit_offset + 5;

    return bit_offset;
}

#define EXTENDED_SAR 255

/* E.1.1 VUI parameters syntax */

/* Table E-2 - Meaning of video_format */
static const value_string h264_video_format_vals[] = {
    { 22,   "reserved_sei_message)" },
    {  0,   "Component" },
    {  1,   "PAL" },
    {  2,   "NTSC" },
    {  3,   "SECAM" },
    {  4,   "MAC" },
    {  5,   "Unspecified video format" },
    {  6,   "Reserved" },
    {  7,   "Reserved" },
    { 0,    NULL }
};

static int
dissect_h264_vui_parameters(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint bit_offset)
{

    guint8 aspect_ratio_info_present_flag, aspect_ratio_idc, overscan_info_present_flag;
    guint8 video_signal_type_present_flag, colour_description_present_flag, chroma_loc_info_present_flag;
    guint8 timing_info_present_flag, nal_hrd_parameters_present_flag, vcl_hrd_parameters_present_flag;
    guint8 bitstream_restriction_flag;

    /* vui_parameters( ) {
     * aspect_ratio_info_present_flag 0 u(1)
     */
    aspect_ratio_info_present_flag = tvb_get_bits8(tvb, bit_offset, 1);
    proto_tree_add_bits_item(tree, hf_h264_aspect_ratio_info_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    if (aspect_ratio_info_present_flag) {
        /* aspect_ratio_idc 0 u(8) */
        aspect_ratio_idc = tvb_get_bits8(tvb, bit_offset, 8);
        proto_tree_add_bits_item(tree, hf_h264_aspect_ratio_idc, tvb, bit_offset, 8, ENC_BIG_ENDIAN);
        bit_offset = bit_offset + 8;

        if (aspect_ratio_idc == EXTENDED_SAR) {
            /* sar_width 0 u(16) */
            proto_tree_add_bits_item(tree, hf_h264_sar_width, tvb, bit_offset, 16, ENC_BIG_ENDIAN);
            bit_offset = bit_offset + 16;

            /* sar_height 0 u(16) */
            proto_tree_add_bits_item(tree, hf_h264_sar_height, tvb, bit_offset, 16, ENC_BIG_ENDIAN);
            bit_offset = bit_offset + 16;
        }
    }
    /* overscan_info_present_flag 0 u(1) */
    overscan_info_present_flag = tvb_get_bits8(tvb, bit_offset, 1);
    proto_tree_add_bits_item(tree, hf_h264_overscan_info_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    if (overscan_info_present_flag) {
        /* overscan_appropriate_flag 0 u(1) */
        proto_tree_add_bits_item(tree, hf_h264_overscan_appropriate_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
        bit_offset++;
    }

    /* video_signal_type_present_flag 0 u(1) */
    video_signal_type_present_flag = tvb_get_bits8(tvb, bit_offset, 1);
    proto_tree_add_bits_item(tree, hf_h264_video_signal_type_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    if (video_signal_type_present_flag) {
        /* video_format 0 u(3) > */
        proto_tree_add_bits_item(tree, hf_h264_video_format, tvb, bit_offset, 3, ENC_BIG_ENDIAN);
        bit_offset = bit_offset + 3;

        /* video_full_range_flag 0 u(1)*/
        proto_tree_add_bits_item(tree, hf_h264_video_full_range_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
        bit_offset++;

        /* colour_description_present_flag 0 u(1) */
        colour_description_present_flag = tvb_get_bits8(tvb, bit_offset, 1);
        proto_tree_add_bits_item(tree, hf_h264_colour_description_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
        bit_offset++;

        if (colour_description_present_flag) {
            /* colour_primaries 0 u(8) */
            proto_tree_add_bits_item(tree, hf_h264_colour_primaries, tvb, bit_offset, 8, ENC_BIG_ENDIAN);
            bit_offset = bit_offset + 8;

            /* transfer_characteristics 0 u(8) */
            proto_tree_add_bits_item(tree, hf_h264_transfer_characteristics, tvb, bit_offset, 8, ENC_BIG_ENDIAN);
            bit_offset = bit_offset + 8;

            /* matrix_coefficients 0 u(8)*/
            proto_tree_add_bits_item(tree, hf_h264_matrix_coefficients, tvb, bit_offset, 8, ENC_BIG_ENDIAN);
            bit_offset = bit_offset + 8;
        }
    }

    /* chroma_loc_info_present_flag 0 u(1) */
    chroma_loc_info_present_flag = tvb_get_bits8(tvb, bit_offset, 1);
    proto_tree_add_bits_item(tree, hf_h264_chroma_loc_info_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    if (chroma_loc_info_present_flag) {
        /* chroma_sample_loc_type_top_field 0 ue(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_chroma_sample_loc_type_top_field, tvb, &bit_offset, H264_UE_V);

        /* chroma_sample_loc_type_bottom_field 0 ue(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_chroma_sample_loc_type_bottom_field, tvb, &bit_offset, H264_UE_V);
    }

    /* timing_info_present_flag 0 u(1) */
    timing_info_present_flag = tvb_get_bits8(tvb, bit_offset, 1);
    proto_tree_add_bits_item(tree, hf_h264_timing_info_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    if (timing_info_present_flag) {
        /* num_units_in_tick 0 u(32) */
        proto_tree_add_bits_item(tree, hf_h264_num_units_in_tick, tvb, bit_offset, 32, ENC_BIG_ENDIAN);
        bit_offset = bit_offset + 32;

        /* time_scale 0 u(32) */
        proto_tree_add_bits_item(tree, hf_h264_time_scale, tvb, bit_offset, 32, ENC_BIG_ENDIAN);
        bit_offset = bit_offset + 32;

        /* fixed_frame_rate_flag 0 u(1) */
        proto_tree_add_bits_item(tree, hf_h264_fixed_frame_rate_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
        bit_offset++;
    }
    /* nal_hrd_parameters_present_flag 0 u(1) */
    nal_hrd_parameters_present_flag = tvb_get_bits8(tvb, bit_offset, 1);
    proto_tree_add_bits_item(tree, hf_h264_nal_hrd_parameters_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    if (nal_hrd_parameters_present_flag) {
        /* hrd_parameters( ) */
        bit_offset = dissect_h264_hrd_parameters(tree, tvb, pinfo, bit_offset);
    }

    /* vcl_hrd_parameters_present_flag 0 u(1) */
    vcl_hrd_parameters_present_flag = tvb_get_bits8(tvb, bit_offset, 1);
    proto_tree_add_bits_item(tree, hf_h264_vcl_hrd_parameters_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    if (vcl_hrd_parameters_present_flag) {
        /* hrd_parameters( ) */
        bit_offset = dissect_h264_hrd_parameters(tree, tvb, pinfo, bit_offset);
    }
    if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
        /* low_delay_hrd_flag 0 u(1) */
        proto_tree_add_bits_item(tree, hf_h264_low_delay_hrd_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
        bit_offset++;
    }
    /* pic_struct_present_flag 0 u(1) */
    proto_tree_add_bits_item(tree, hf_h264_pic_struct_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    /* bitstream_restriction_flag 0 u(1) */
    bitstream_restriction_flag = tvb_get_bits8(tvb, bit_offset, 1);
    proto_tree_add_bits_item(tree, hf_h264_bitstream_restriction_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    if (bitstream_restriction_flag) {
        /* motion_vectors_over_pic_boundaries_flag 0 u(1) */
        proto_tree_add_bits_item(tree, hf_h264_motion_vectors_over_pic_boundaries_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
        bit_offset++;

        /* max_bytes_per_pic_denom 0 ue(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_max_bytes_per_pic_denom, tvb, &bit_offset, H264_UE_V);

        /* max_bits_per_mb_denom 0 ue(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_max_bits_per_mb_denom, tvb, &bit_offset, H264_UE_V);

        /* log2_max_mv_length_horizontal 0 ue(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_log2_max_mv_length_horizontal, tvb, &bit_offset, H264_UE_V);

        /* log2_max_mv_length_vertical 0 ue(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_log2_max_mv_length_vertical, tvb, &bit_offset, H264_UE_V);

        /* num_reorder_frames 0 ue(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_num_reorder_frames, tvb, &bit_offset, H264_UE_V);

        /* max_dec_frame_buffering 0 ue(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_max_dec_frame_buffering, tvb, &bit_offset, H264_UE_V);
    }

    return bit_offset;
}

/* Used To dissect SDP parameter (H.264)profile */
void
dissect_h264_profile(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
    proto_item *item, *level_item;
    proto_tree *h264_profile_tree;
    gint        offset = 0;
    guint8      constraint_set3_flag;
    guint32     level_idc;

    item = proto_tree_add_item(tree, hf_h264_profile, tvb, offset, -1, ENC_NA);
    h264_profile_tree = proto_item_add_subtree(item, ett_h264_profile);

    proto_tree_add_item(h264_profile_tree, hf_h264_profile_idc, tvb, offset, 1, ENC_BIG_ENDIAN);
    offset++;

    constraint_set3_flag = (tvb_get_guint8(tvb, offset)&0x10)>>4;
    proto_tree_add_item(h264_profile_tree, hf_h264_constraint_set0_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(h264_profile_tree, hf_h264_constraint_set1_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(h264_profile_tree, hf_h264_constraint_set2_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(h264_profile_tree, hf_h264_constraint_set3_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(h264_profile_tree, hf_h264_constraint_set4_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(h264_profile_tree, hf_h264_constraint_set5_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(h264_profile_tree, hf_h264_reserved_zero_2bits, tvb, offset, 1, ENC_BIG_ENDIAN);
    offset++;

    /* A level to which the bitstream conforms shall be indicated by the syntax element level_idc as follows.
     *  - If level_idc is equal to 11 and constraint_set3_flag is equal to 1, the indicated level is level 1b.
     *  - Otherwise (level_idc is not equal to 11 or constraint_set3_flag is not equal to 1), level_idc shall
     *    be set equal to a value of ten times the level number specified in Table A-1 and constraint_set3_flag
     *    shall be set equal to 0.
     */

    level_idc = tvb_get_guint8(tvb, offset);
    level_item = proto_tree_add_item(h264_profile_tree, hf_h264_level_idc, tvb, offset, 1, ENC_BIG_ENDIAN);
    if ((level_idc == 11) && (constraint_set3_flag == 1)) {
        proto_item_append_text(level_item," [Level 1b (128kb/s)]");
    } else {
        proto_item_append_text(level_item," [Level %.1f %s]", ((double)level_idc/10), val_to_str_const(level_idc, h264_level_bitrate_values, "Unknown "));
    }
}

/*
 * 7.3.1 NAL unit syntax
 * Un escape the NAL tvb
 *
 *
 * nal_unit( NumBytesInNALunit ) { C Descriptor
 *   forbidden_zero_bit All f(1)
 *   nal_ref_idc All u(2)
 *   nal_unit_type All u(5)
 *   NumBytesInRBSP = 0
 *   for (i = 1; i < NumBytesInNALunit; i++) {
 *     if (i + 2 < NumBytesInNALunit && next_bits( 24 ) = = 0x000003 ) {
 *       rbsp_byte[ NumBytesInRBSP++ ] All b(8)
 *       rbsp_byte[ NumBytesInRBSP++ ] All b(8)
 *       i += 2
 *       emulation_prevention_three_byte / * equal to 0x03 * / All f(8)
 *     } else
 *       rbsp_byte[ NumBytesInRBSP++ ] All b(8)
 *     }
 *   }
 */

static tvbuff_t *
dissect_h265_unescap_nal_unit(tvbuff_t *tvb, packet_info *pinfo, int offset)
{
    tvbuff_t *tvb_rbsp;
    int       length         = tvb_reported_length_remaining(tvb, offset);
    int       NumBytesInRBSP = 0;
    int       i;
    gchar    *buff;

    buff = (gchar *)wmem_alloc(pinfo->pool, length);
    for (i = 0; i < length; i++) {
        if ((i + 2 < length) && (tvb_get_ntoh24(tvb, offset) == 0x000003)) {
            buff[NumBytesInRBSP++] = tvb_get_guint8(tvb, offset);
            buff[NumBytesInRBSP++] = tvb_get_guint8(tvb, offset+1);
            i += 2;
            offset+=3;
        } else {
            buff[ NumBytesInRBSP++] = tvb_get_guint8(tvb, offset);
            offset++;
        }
    }

    tvb_rbsp = tvb_new_child_real_data(tvb, buff, NumBytesInRBSP, NumBytesInRBSP);
    add_new_data_source(pinfo, tvb_rbsp, "Unescaped RSP Data");

    return tvb_rbsp;
}

/*
 * 7.3.2.8 Slice layer without partitioning RBSP syntax
 * slice_layer_without_partitioning_rbsp( )
 */

static void
dissect_h264_slice_layer_without_partitioning_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
    gint bit_offset;

    bit_offset = offset <<3;

    /* slice_header( ) 2 */
    bit_offset = dissect_h264_slice_header(tree, tvb, pinfo, bit_offset);
    proto_tree_add_expert(tree, pinfo, &ei_h264_undecoded, tvb, bit_offset>>3, -1);
    return;
    /* slice_data( ) * all categories of slice_data( ) syntax * 2 | 3 | 4 */
    /* rbsp_slice_trailing_bits( ) */
}

/*
 * 7.3.2.9.1 Slice data partition A RBSP syntax
 * slice_data_partition_a_layer_rbsp( )
 */
static void
dissect_h264_slice_data_partition_a_layer_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset)
{
    gint bit_offset;

    bit_offset = offset <<3;

    /* slice_header( ) 2 */
    bit_offset = dissect_h264_slice_header(tree, tvb, pinfo, bit_offset);

    /* slice_id All ue(v) */
    dissect_h264_exp_golomb_code(tree, hf_h264_slice_id, tvb, &bit_offset, H264_UE_V);
    proto_tree_add_expert(tree, pinfo, &ei_h264_undecoded, tvb, bit_offset>>3, -1);
    return;
    /* slice_data( ) * only category 2 parts of slice_data( ) syntax * 2*/
    /* rbsp_slice_trailing_bits( )*/
}

/*
 * 7.3.2.9.2 Slice data partition B RBSP syntax
 * slice_data_partition_b_layer_rbsp(
 */
static void
dissect_h264_slice_data_partition_b_layer_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset)
{
    gint bit_offset;

    bit_offset = offset <<3;

    /* slice_id All ue(v) */
    dissect_h264_exp_golomb_code(tree, hf_h264_slice_id, tvb, &bit_offset, H264_UE_V);
    /* if (redundant_pic_cnt_present_flag) */
    /* redundant_pic_cnt All ue(v) */
    /* slice_data( ) * only category 3 parts of slice_data( ) syntax * 3 */
    /* rbsp_slice_trailing_bits( ) 3 */
    proto_tree_add_expert(tree, pinfo, &ei_h264_undecoded, tvb, bit_offset>>3, -1);

}

/*
 * 7.3.2.9.3 Slice data partition C RBSP syntax
 * slice_data_partition_c_layer_rbsp( )
 */
static void
dissect_h264_slice_data_partition_c_layer_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset)
{
    gint bit_offset;

    bit_offset = offset <<3;

    /* slice_id All ue(v) */
    dissect_h264_exp_golomb_code(tree, hf_h264_slice_id, tvb, &bit_offset, H264_UE_V);
    /* if (redundant_pic_cnt_present_flag) */
    /* redundant_pic_cnt All ue(v) */
    /* slice_data( ) * only category 4 parts of slice_data( ) syntax * 4 */
    /* rbsp_slice_trailing_bits( ) 4 */
    proto_tree_add_expert(tree, pinfo, &ei_h264_undecoded, tvb, bit_offset>>3, -1);
}

/* D.1.6 User data unregistered SEI message syntax */

static int
h264_user_data_unregistered(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint bit_offset, guint32 payloadSize)
{
    guint8  i;
    guint8  ld_size;
    guint8  p_flag;
    guint8  desc =0;
    guint8  num_crops;
    gint offset = bit_offset >> 3;
    proto_item *item;
    proto_item *uuid_item;
    proto_tree *h264_ms_layer_desc_tree;
    proto_tree *h264_ms_crop_data_tree;
    e_guid_t   guid;


    /* user_data_unregistered( payloadSize ) { C Descriptor */
    /* uuid_iso_iec_11578 5 u(128)
     * uuid_iso_iec_11578 shall have a value specified as a UUID
     * according to the procedures of ISO/IEC 11578:1996 Annex A.
     */

    uuid_item = proto_tree_add_item (tree, hf_h264_sei_uuid, tvb, offset, 16, ENC_BIG_ENDIAN);
    /* Extract the ISO/IEC value for comparison */
    tvb_get_ntohguid(tvb, offset, &guid);
    offset+=16;

    /* Microsoft MS-H264PF Specification */
    if ( memcmp(&guid, &(ms_guids[MS_LAYOUT]), sizeof(e_guid_t)) == 0)
    {
        col_append_fstr(pinfo->cinfo, COL_INFO, ":MS_Layout");
        proto_item_append_text(uuid_item,"  - Microsoft Stream Layout SEI Message");
        /* Loop through the layer presence bytes 0-7 */
        for (i = 0; i < 8 ; i++)
        {
            item = proto_tree_add_item (tree, hf_h264_sei_ms_lpb, tvb, offset, 1, ENC_BIG_ENDIAN);
            proto_item_append_text (item, "  PRID %2d - %2d", (i+1)*8-1, i*8);
            offset++;
        }
        p_flag = tvb_get_guint8 (tvb, offset);
        proto_tree_add_item (tree, hf_h264_sei_ms_layout_p, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset++;
        if (p_flag == 1)
        {
            ld_size = tvb_get_guint8 (tvb, offset);
            proto_tree_add_item (tree, hf_h264_sei_ms_layout_ldsize, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset++;
            /* MS Errata - Microsoft seems to be setting the LD size to 16 but then including 2 layer descriptions which should be 32
             * To compensate for that, keep decoding layers as long as there are 16 or more bytes left in the SEI message.
             */
            if (tvb_reported_length_remaining (tvb, offset) != ld_size)
            {
                item = proto_tree_add_expert(tree, pinfo, &ei_h264_ms_layout_wrong_length, tvb, offset-1, 1);
                proto_item_append_text(item," Size of %d, remaining size %d",
                        ld_size,
                        tvb_reported_length_remaining (tvb, offset));
            }
            while (tvb_reported_length_remaining (tvb, offset) >= 16)
            {
                h264_ms_layer_desc_tree = proto_tree_add_subtree_format(tree, tvb, offset, 16, ett_h264_ms_layer_description, NULL, "MS Layer Description  #%d", ++desc);

                proto_tree_add_item (h264_ms_layer_desc_tree, hf_h264_sei_ms_layer_desc_coded_width,    tvb, offset, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item (h264_ms_layer_desc_tree, hf_h264_sei_ms_layer_desc_coded_height,   tvb, offset + 2, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item (h264_ms_layer_desc_tree, hf_h264_sei_ms_layer_desc_display_width,  tvb, offset + 4, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item (h264_ms_layer_desc_tree, hf_h264_sei_ms_layer_desc_display_height, tvb, offset + 6, 2, ENC_BIG_ENDIAN);
                proto_tree_add_item (h264_ms_layer_desc_tree, hf_h264_sei_ms_layer_desc_bitrate,        tvb, offset + 8, 4, ENC_BIG_ENDIAN);
                proto_tree_add_item (h264_ms_layer_desc_tree, hf_h264_sei_ms_layer_desc_frame_rate,     tvb, offset + 12, 1, ENC_BIG_ENDIAN);
                proto_tree_add_item (h264_ms_layer_desc_tree, hf_h264_sei_ms_layer_desc_layer_type,     tvb, offset + 12, 1, ENC_BIG_ENDIAN);
                proto_tree_add_item (h264_ms_layer_desc_tree, hf_h264_sei_ms_layer_desc_prid,           tvb, offset + 13, 1, ENC_BIG_ENDIAN);
                proto_tree_add_item (h264_ms_layer_desc_tree, hf_h264_sei_ms_layer_desc_cb,             tvb, offset + 13, 1, ENC_BIG_ENDIAN);
                offset += 16;
            }
        }
    }
    else if ( memcmp(&guid, &(ms_guids[MS_CROPPING]), sizeof(e_guid_t)) == 0)
    {
        col_append_fstr(pinfo->cinfo, COL_INFO, ":MS_Cropping");
        proto_item_append_text(uuid_item,"  - Microsoft Cropping Info SEI Message");
        num_crops = tvb_get_guint8 (tvb, offset);
        proto_tree_add_item (tree, hf_h264_sei_ms_crop_num_data, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset++;
        proto_tree_add_item (tree, hf_h264_sei_ms_crop_info_type, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset++;
        while (num_crops != 0)
        {
            h264_ms_crop_data_tree = proto_tree_add_subtree_format(tree, tvb, offset, 9, ett_h264_ms_crop_data, NULL, "Crop Data #%d", ++desc);
            proto_tree_add_item (h264_ms_crop_data_tree, hf_h264_sei_ms_crop_confidence_level,    tvb, offset,   1, ENC_BIG_ENDIAN);
            proto_tree_add_item (h264_ms_crop_data_tree, hf_h264_sei_ms_crop_frame_left_offset,   tvb, offset+1, 2, ENC_BIG_ENDIAN);
            proto_tree_add_item (h264_ms_crop_data_tree, hf_h264_sei_ms_crop_frame_right_offset,  tvb, offset+3, 2, ENC_BIG_ENDIAN);
            proto_tree_add_item (h264_ms_crop_data_tree, hf_h264_sei_ms_crop_frame_top_offset,    tvb, offset+5, 2, ENC_BIG_ENDIAN);
            proto_tree_add_item (h264_ms_crop_data_tree, hf_h264_sei_ms_crop_frame_bottom_offset, tvb, offset+7, 2, ENC_BIG_ENDIAN);
            num_crops--;
            offset += 9;
        }
    }
    else if ( memcmp(&guid, &(ms_guids[MS_BITSTREAM]), sizeof(e_guid_t)) == 0)
    {
        col_append_fstr(pinfo->cinfo, COL_INFO, ":MS_Bitstream");
        proto_item_append_text(uuid_item,"  - Microsoft Bitstream Info SEI Message");
        proto_tree_add_item (tree, hf_h264_sei_ms_bitstream_ref_frame_cnt, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset++;
        proto_tree_add_item (tree, hf_h264_sei_ms_bitstream_num_nalus, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset++;
    }
    else
    {
        proto_tree_add_item(tree, hf_h264_sei_iso_sec_info, tvb, offset, 16, ENC_NA);
    /*  for (i = 16; i < payloadSize; i++)
     *  user_data_payload_byte 5 b(8)
     */
        if (payloadSize > 16)
        {
            proto_tree_add_expert(tree, pinfo, &ei_h264_undecoded, tvb, offset, payloadSize-16);
            offset+=(payloadSize-16);
        }
    }

    return offset << 3;
}

/* D.1 SEI payload syntax */
static const value_string h264_sei_payload_vals[] = {
    {  0,   "buffering_period" },
    {  1,   "pic_timing" },
    {  2,   "pan_scan_rect" },
    {  3,   "filler_payload" },
    {  4,   "user_data_registered_itu_t_t35" },
    {  5,   "user_data_unregistered" },
    {  6,   "recovery_point" },
    {  7,   "dec_ref_pic_marking_repetition" },
    {  8,   "spare_pic" },
    {  9,   "scene_inf)" },
    { 10,   "sub_seq_info)" },
    { 11,   "sub_seq_layer_characteristics" },
    { 12,   "sub_seq_characteristics" },
    { 13,   "full_frame_freeze_release" },
    { 14,   "full_frame_freeze_release" },
    { 15,   "full_frame_snapshot" },
    { 16,   "progressive_refinement_segment_start" },
    { 17,   "progressive_refinement_segment_end" },
    { 18,   "motion_constrained_slice_group_set" },
    { 19,   "film_grain_characteristics)" },
    { 20,   "deblocking_filter_display_preference)" },
    { 21,   "stereo_video_info)" },
    { 22,   "post_filter_hint" },
    { 23,   "tone_mapping_info" },
    /* Annex G Values */
    { 24,   "scalability_info" },
    { 25,   "sub_pic_scalable_layer" },
    { 26,   "non_required_layer_rep" },
    { 27,   "priority_layer_info" },
    { 28,   "layers_not_present" },
    { 29,   "layer_dependency_change" },
    { 30,   "scalable_nesting" },
    { 31,   "base_layer_temporal_hrd" },
    { 32,   "quality_layer_integrity_check" },
    { 33,   "redundant_pic_property" },
    { 34,   "tl0_dep_rep_index" },
    { 35,   "tl_switching_point" },
    /* Annex H  37 to 46 - Not Decoded*/
    /* Annex I  47 to 53 - Not Decoded*/
    { 0,    NULL }
};

static int
h264_sei_payload(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint bit_offset, guint32 payloadType, guint32 payloadSize)
{
    /* sei_payload( payloadType, payloadSize ) { C Descriptor */
    if (payloadType == 0) {
        /* buffering_period( payloadSize ) 5 */
        bit_offset = bit_offset +(payloadSize<<3);
#if 0
    } else if (payloadType == 1) {
        /* pic_timing( payloadSize ) 5 */
    } else if (payloadType == 2) {
        /* pan_scan_rect( payloadSize ) 5 */
    } else if (payloadType == 3) {
        /* filler_payload( payloadSize ) 5 */
    } else if (payloadType == 4) {
        /* user_data_registered_itu_t_t35( payloadSize ) 5 */
#endif
    } else if (payloadType == 5) {
        /* user_data_unregistered( payloadSize ) 5 */
        bit_offset = h264_user_data_unregistered( tree, tvb, pinfo, bit_offset, payloadSize);
    } else if (payloadType == 6) {
        /* recovery_point( payloadSize ) 5 */
        bit_offset = bit_offset +(payloadSize<<3);
    } else if (payloadType == 7) {
        /* dec_ref_pic_marking_repetition( payloadSize ) 5 */
        bit_offset = bit_offset +(payloadSize<<3);
    }
#if 0
else if (payloadType == 8)
spare_pic( payloadSize ) 5
else if (payloadType == 9)
scene_info( payloadSize ) 5
else if (payloadType == 10)
sub_seq_info( payloadSize ) 5
else if (payloadType == 11)
sub_seq_layer_characteristics( payloadSize ) 5
else if (payloadType == 12)
sub_seq_characteristics( payloadSize ) 5
else if (payloadType == 13)
full_frame_freeze( payloadSize ) 5
else if (payloadType == 14)
full_frame_freeze_release( payloadSize ) 5
else if (payloadType == 15)
full_frame_snapshot( payloadSize ) 5
else if (payloadType == 16)
progressive_refinement_segment_start( payloadSize ) 5
else if (payloadType == 17)
progressive_refinement_segment_end( payloadSize ) 5
else if (payloadType == 18)
motion_constrained_slice_group_set( payloadSize ) 5
else if (payloadType == 19)
film_grain_characteristics( payloadSize ) 5
else if (payloadType == 20)
deblocking_filter_display_preference( payloadSize ) 5
else if (payloadType == 21)
stereo_video_info( payloadSize ) 5
else
reserved_sei_message( payloadSize ) 5
    return bit_offset;
#endif
    if (!h264_byte_aligned(bit_offset)) {
        /* bit_equal_to_one / * equal to 1 * / 5 f(1) */
        /* TODO:Display the filler and, error if not 1 ?? */
        bit_offset++;
        while (!h264_byte_aligned(bit_offset)) {
            /* bit_equal_to_zero / * equal to 0 * / 5 f(1) */
            /* TODO:Display the filler and, error if not 0 ?? */
            bit_offset++;
        }
    }
    return bit_offset;
}

/*
 * 7.3.2.3.1 Supplemental enhancement information message syntax
 */
static gint
dissect_h264_sei_message(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint bit_offset)
{
    /* sei_message( ) { C Descriptor */
    guint32 payloadType = 0, payloadSize;
    gint    start_bit_offset, length;

    start_bit_offset = bit_offset;

    /* while (next_bits( 8 ) == 0xFF) { */
    while (tvb_get_bits8(tvb, bit_offset, 8) == 0xFF) {
        /* ff_byte / * equal to 0xFF * / 5 f(8) */
        payloadType += 255;
        bit_offset+=8;
    }
    /* last_payload_type_byte 5 u(8) */
    payloadType += tvb_get_bits8(tvb, bit_offset, 8);
    bit_offset+=8;
    length = (bit_offset - start_bit_offset)>>3;

    proto_tree_add_uint(tree, hf_h264_payloadtype, tvb, start_bit_offset>>3, length, payloadType);

    payloadSize = 0;
    start_bit_offset = bit_offset;
    /* while (next_bits( 8 ) == 0xFF) { */
    while (tvb_get_bits8(tvb, bit_offset, 8) == 0xFF) {
        /* ff_byte / * equal to 0xFF * / 5 f(8) */
        payloadSize += 255;
        bit_offset+=8;
    }
    /* last_payload_size_byte 5 u(8) */
    /* payloadSize += last_payload_size_byte */
    payloadSize += tvb_get_bits8(tvb, bit_offset, 8);
    bit_offset+=8;
    length = (bit_offset - start_bit_offset)>>3;
    proto_tree_add_uint(tree, hf_h264_payloadsize, tvb, start_bit_offset>>3, length, payloadSize);

    /*sei_payload( payloadType, payloadSize ) 5 */
    bit_offset = h264_sei_payload( tree, tvb, pinfo, bit_offset, payloadType, payloadSize);
    return bit_offset;
}

/*
 * 7.3.2.3 Supplemental enhancement information RBSP syntax
 * sei_rbsp( )
 */
static int
dissect_h264_sei_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset)
{
    gint bit_offset;

    bit_offset = offset <<3;
    /* do */
    /* sei_message( ) 5*/
    bit_offset = dissect_h264_sei_message( tree, tvb, pinfo, bit_offset);

    /* while (more_rbsp_data( ))
     * If there is more data in an RBSP before rbsp_trailing_bits( ),
     * the return value of more_rbsp_data( ) is equal to TRUE.
     */
    /* rbsp_trailing_bits( ) 5 */
    if (tvb_reported_length_remaining (tvb, bit_offset >> 3) != 0 || (bit_offset & 0x7) != 0)
    {
    bit_offset = dissect_h264_rbsp_trailing_bits(tree, tvb, pinfo, bit_offset);
    }

    return bit_offset;
}

/* Ref 7.3.2.1 Sequence parameter set RBSP syntax */
static int
dissect_h264_seq_parameter_set_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
    proto_item *level_item;
    gint        bit_offset;
    guint8      constraint_set3_flag;
    guint32     level_idc;

    gint        i;
    guint8      profile_idc, chroma_format_idc, frame_mbs_only_flag, frame_cropping_flag;
    guint8      pic_order_cnt_type, vui_parameters_present_flag, num_ref_frames_in_pic_order_cnt_cycle;
    guint8      seq_scaling_matrix_present_flag, seq_scaling_list_present_flag;
    int         ScalingList4x4[6][16], ScalingList8x8[2][64];

    /* profile_idc 0 u(8) */
    profile_idc = tvb_get_guint8(tvb, offset);
    proto_tree_add_item(tree, hf_h264_profile_idc, tvb, offset, 1, ENC_BIG_ENDIAN);
    offset++;

    constraint_set3_flag = (tvb_get_guint8(tvb, offset)&0x10)>>4;
    /* constraint_set0_flag 0 u(1) */
    proto_tree_add_item(tree, hf_h264_constraint_set0_flag, tvb, offset, 1, ENC_BIG_ENDIAN);

    /* constraint_set1_flag 0 u(1) */
    proto_tree_add_item(tree, hf_h264_constraint_set1_flag, tvb, offset, 1, ENC_BIG_ENDIAN);

    /* constraint_set2_flag 0 u(1) */
    proto_tree_add_item(tree, hf_h264_constraint_set2_flag, tvb, offset, 1, ENC_BIG_ENDIAN);

    /* constraint_set3_flag 0 u(1) */
    proto_tree_add_item(tree, hf_h264_constraint_set3_flag, tvb, offset, 1, ENC_BIG_ENDIAN);

    /* constraint_set4_flag 0 u(1) */
    proto_tree_add_item(tree, hf_h264_constraint_set4_flag, tvb, offset, 1, ENC_BIG_ENDIAN);

    /* constraint_set5_flag 0 u(1) */
    proto_tree_add_item(tree, hf_h264_constraint_set5_flag, tvb, offset, 1, ENC_BIG_ENDIAN);

    /* reserved_zero_4bits  equal to 0  0 u(4)*/
    proto_tree_add_item(tree, hf_h264_reserved_zero_2bits, tvb, offset, 1, ENC_BIG_ENDIAN);
    offset++;

    /* level_idc 0 u(8) */
    level_idc = tvb_get_guint8(tvb, offset);
    level_item = proto_tree_add_item(tree, hf_h264_level_idc, tvb, offset, 1, ENC_BIG_ENDIAN);
    if ((level_idc == 11) && (constraint_set3_flag == 1)) {
        proto_item_append_text(level_item,"[Level 1b]");
    } else {
        proto_item_append_text(level_item," [Level %.1f %s]", ((double)level_idc/10), val_to_str_const(level_idc, h264_level_bitrate_values, "Unknown "));
    }
    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.
     */
    bit_offset = offset<<3;
    dissect_h264_exp_golomb_code(tree, hf_h264_seq_parameter_set_id, tvb, &bit_offset, H264_UE_V);


    if ((profile_idc == 100) || (profile_idc == 110) ||
        (profile_idc == 122) || (profile_idc == 144) ||
        (profile_idc ==  44) || (profile_idc ==  83) ||
        (profile_idc ==  86) || (profile_idc == 118) ||
        (profile_idc == 128) || (profile_idc == 138))
    {

        /* chroma_format_idc 0 ue(v) */
        chroma_format_idc = dissect_h264_exp_golomb_code(tree, hf_h264_chroma_format_idc, tvb, &bit_offset, H264_UE_V);
        if (chroma_format_idc == 3) {
            /* residual_colour_transform_flag 0 u(1) */
            proto_tree_add_bits_item(tree, hf_h264_residual_colour_transform_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
            bit_offset++;
        }

        /* bit_depth_luma_minus8 0 ue(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_bit_depth_luma_minus8, tvb, &bit_offset, H264_UE_V);

        /* bit_depth_chroma_minus8 0 ue(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_bit_depth_chroma_minus8, tvb, &bit_offset, H264_UE_V);

        /* qpprime_y_zero_transform_bypass_flag 0 u(1) */
        proto_tree_add_bits_item(tree, hf_h264_qpprime_y_zero_transform_bypass_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
        bit_offset++;

        /* seq_scaling_matrix_present_flag 0 u(1) */
        seq_scaling_matrix_present_flag = tvb_get_bits8(tvb, bit_offset, 1);
        proto_tree_add_bits_item(tree, hf_h264_seq_scaling_matrix_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
        bit_offset++;

        if (seq_scaling_matrix_present_flag) {
            for (i = 0; i < 8; i++) {
                /* seq_scaling_list_present_flag[ i ] 0 u(1) */
                seq_scaling_list_present_flag = tvb_get_bits8(tvb, bit_offset, 1);
                proto_tree_add_bits_item(tree, hf_h264_seq_scaling_list_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
                bit_offset++;
                if (seq_scaling_list_present_flag) {
                    if (i < 6)
                        bit_offset = dissect_h264_scaling_list(tree, tvb, bit_offset, ScalingList4x4[ i ], 16);
                    else
                        bit_offset = dissect_h264_scaling_list(tree, tvb, bit_offset, ScalingList8x8[ i - 6 ], 64);
                }
            }
        }

    }

    /* log2_max_frame_num_minus4 0 ue(v) */
    dissect_h264_exp_golomb_code(tree, hf_h264_log2_max_frame_num_minus4, tvb, &bit_offset, H264_UE_V);

    /* pic_order_cnt_type 0 ue(v) */
    pic_order_cnt_type = dissect_h264_exp_golomb_code(tree, hf_h264_pic_order_cnt_type, tvb, &bit_offset, H264_UE_V);

    if (pic_order_cnt_type == 0) {
        /* log2_max_pic_order_cnt_lsb_minus4 0 ue(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_log2_max_pic_order_cnt_lsb_minus4, tvb, &bit_offset, H264_UE_V);
    } else if (pic_order_cnt_type == 1) {
        /* delta_pic_order_always_zero_flag 0 u(1) */
        proto_tree_add_bits_item(tree, hf_h264_delta_pic_order_always_zero_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
        bit_offset++;

        /* offset_for_non_ref_pic 0 se(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_offset_for_non_ref_pic, tvb, &bit_offset, H264_SE_V);

        /* offset_for_top_to_bottom_field 0 se(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_offset_for_top_to_bottom_field, tvb, &bit_offset, H264_SE_V);

        /* num_ref_frames_in_pic_order_cnt_cycle 0 ue(v) */
        num_ref_frames_in_pic_order_cnt_cycle = dissect_h264_exp_golomb_code(tree, hf_h264_num_ref_frames_in_pic_order_cnt_cycle, tvb, &bit_offset, H264_UE_V);
        for (i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) {
            /*offset_for_ref_frame[ i ] 0 se(v)*/
            dissect_h264_exp_golomb_code(tree, hf_h264_offset_for_ref_frame, tvb, &bit_offset, H264_SE_V);
        }
    }
    /* num_ref_frames 0 ue(v) */
    dissect_h264_exp_golomb_code(tree, hf_h264_num_ref_frames, tvb, &bit_offset, H264_UE_V);

    /*  gaps_in_frame_num_value_allowed_flag 0 u(1) */
    proto_tree_add_bits_item(tree, hf_h264_gaps_in_frame_num_value_allowed_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    /*  pic_width_in_mbs_minus1 0 ue(v) */
    dissect_h264_exp_golomb_code(tree, hf_h264_pic_width_in_mbs_minus1, tvb, &bit_offset, H264_UE_V);

    /* pic_height_in_map_units_minus1 0 ue(v) */
    dissect_h264_exp_golomb_code(tree, hf_h264_pic_height_in_map_units_minus1, tvb, &bit_offset, H264_UE_V);

    /* frame_mbs_only_flag 0 u(1) */
    frame_mbs_only_flag = tvb_get_bits8(tvb, bit_offset, 1);
    proto_tree_add_bits_item(tree, hf_h264_frame_mbs_only_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;
    if (!frame_mbs_only_flag) {
        /* mb_adaptive_frame_field_flag 0 u(1) */
        proto_tree_add_bits_item(tree, hf_h264_mb_adaptive_frame_field_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
        bit_offset++;
    }

    /* direct_8x8_inference_flag 0 u(1) */
    proto_tree_add_bits_item(tree, hf_h264_direct_8x8_inference_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    /* frame_cropping_flag 0 u(1) */
    frame_cropping_flag = tvb_get_bits8(tvb, bit_offset, 1);
    proto_tree_add_bits_item(tree, hf_h264_frame_cropping_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    if (frame_cropping_flag) {
        /* frame_crop_left_offset 0 ue(v) */
        dissect_h264_exp_golomb_code(tree, hf_h264_frame_crop_left_offset, tvb, &bit_offset, H264_UE_V);
        dissect_h264_exp_golomb_code(tree, hf_h264_frame_crop_right_offset, tvb, &bit_offset, H264_UE_V);
        dissect_h264_exp_golomb_code(tree, hf_h264_frame_crop_top_offset, tvb, &bit_offset, H264_UE_V);
        dissect_h264_exp_golomb_code(tree, hf_h264_frame_crop_bottom_offset, tvb, &bit_offset, H264_UE_V);

    }

    /*  vui_parameters_present_flag 0 u(1) */
    vui_parameters_present_flag = tvb_get_bits8(tvb, bit_offset, 1);
    proto_tree_add_bits_item(tree, hf_h264_vui_parameters_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;
    if (vui_parameters_present_flag) {
        bit_offset = dissect_h264_vui_parameters(tree, tvb, pinfo, bit_offset);
    }

    /*  rbsp_trailing_bits( ) 0 */
    bit_offset = dissect_h264_rbsp_trailing_bits(tree, tvb, pinfo, bit_offset);

    offset = bit_offset>>3;

    /* TODO - Add dissector of SPS SVC extension from Annex G*/
    return offset;
}

/* 7.3.2.2 Picture parameter set RBSP syntax */

static void
dissect_h264_pic_parameter_set_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
    gint    bit_offset;
    guint32 num_slice_groups_minus1, pic_scaling_matrix_present_flag;

    bit_offset = offset<<3;

    /* pic_parameter_set_id 1 ue(v) */
    dissect_h264_exp_golomb_code(tree, hf_h264_pic_parameter_set_id, tvb, &bit_offset, H264_UE_V);

    /* seq_parameter_set_id 1 ue(v) */
    dissect_h264_exp_golomb_code(tree, hf_h264_seq_parameter_set_id, tvb, &bit_offset, H264_UE_V);

    /* entropy_coding_mode_flag 1 u(1) */
    proto_tree_add_bits_item(tree, hf_h264_entropy_coding_mode_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    /* pic_order_present_flag 1 u(1)*/
    proto_tree_add_bits_item(tree, hf_h264_pic_order_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    /* num_slice_groups_minus1 1 ue(v)*/
    num_slice_groups_minus1 = dissect_h264_exp_golomb_code(tree, hf_h264_num_slice_groups_minus1, tvb, &bit_offset, H264_UE_V);
    if (num_slice_groups_minus1 > 0) {
        /* slice_group_map_type 1 ue(v)*/
        dissect_h264_exp_golomb_code(tree, hf_h264_slice_group_map_type, tvb, &bit_offset, H264_UE_V);
    /*  slice_group_map_type = dissect_h264_exp_golomb_code(tree, hf_h264_slice_group_map_type, tvb, &bit_offset, H264_UE_V);*/
    /* if (slice_group_map_type == 0)*/
    /* for (iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++)*/
    /* run_length_minus1[ iGroup ] 1 ue(v)*/
    /* else if (slice_group_map_type == 2)*/
    /* for (iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++) {*/
    /* top_left[ iGroup ] 1 ue(v)*/
    /* bottom_right[ iGroup ] 1 ue(v)*/
    /* }*/
    /* else if (slice_group_map_type == 3 ||*/
    /* slice_group_map_type == 4 ||*/
    /* slice_group_map_type == 5 ) {*/
    /* slice_group_change_direction_flag 1 u(1)*/
    /* slice_group_change_rate_minus1 1 ue(v)*/
    /* } else if (slice_group_map_type == 6) {*/
    /* pic_size_in_map_units_minus1 1 ue(v)*/
    /* for (i = 0; i <= pic_size_in_map_units_minus1; i++)*/
    /* slice_group_id[ i ] 1 u(v)*/
    /* }*/
    /* }*/
        proto_tree_add_expert(tree, pinfo, &ei_h264_undecoded, tvb, bit_offset>>3, -1);
        return;
    }
    /* num_ref_idx_l0_active_minus1 1 ue(v)*/
    dissect_h264_exp_golomb_code(tree, hf_h264_num_ref_idx_l0_active_minus1, tvb, &bit_offset, H264_UE_V);

    /* num_ref_idx_l1_active_minus1 1 ue(v)*/
    dissect_h264_exp_golomb_code(tree, hf_h264_num_ref_idx_l1_active_minus1, tvb, &bit_offset, H264_UE_V);

    /* weighted_pred_flag 1 u(1)*/
    proto_tree_add_bits_item(tree, hf_h264_weighted_pred_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    /* weighted_bipred_idc 1 u(2)*/
    proto_tree_add_bits_item(tree, hf_h264_weighted_bipred_idc, tvb, bit_offset, 2, ENC_BIG_ENDIAN);
    bit_offset= bit_offset+2;

    /* pic_init_qp_minus26  * relative to 26 * 1 se(v)*/
    dissect_h264_exp_golomb_code(tree, hf_h264_pic_init_qp_minus26, tvb, &bit_offset, H264_SE_V);

    /* pic_init_qs_minus26  * relative to 26 *  1 se(v)*/
    dissect_h264_exp_golomb_code(tree, hf_h264_pic_init_qs_minus26, tvb, &bit_offset, H264_SE_V);

    /* chroma_qp_index_offset 1 se(v)*/
    dissect_h264_exp_golomb_code(tree, hf_h264_chroma_qp_index_offset, tvb, &bit_offset, H264_SE_V);

    /* deblocking_filter_control_present_flag 1 u(1)*/
    proto_tree_add_bits_item(tree, hf_h264_deblocking_filter_control_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    /* constrained_intra_pred_flag 1 u(1)*/
    proto_tree_add_bits_item(tree, hf_h264_constrained_intra_pred_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    /* redundant_pic_cnt_present_flag 1 u(1)*/
    proto_tree_add_bits_item(tree, hf_h264_redundant_pic_cnt_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
    bit_offset++;

    if (more_rbsp_data(tree, tvb, pinfo, bit_offset)) {
        /* transform_8x8_mode_flag 1 u(1)*/
        proto_tree_add_bits_item(tree, hf_h264_transform_8x8_mode_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
        bit_offset++;

        /* pic_scaling_matrix_present_flag 1 u(1)*/
        pic_scaling_matrix_present_flag = tvb_get_bits8(tvb, bit_offset, 1);
        proto_tree_add_bits_item(tree, hf_h264_pic_scaling_matrix_present_flag, tvb, bit_offset, 1, ENC_BIG_ENDIAN);
        bit_offset++;

        if (pic_scaling_matrix_present_flag) {
            proto_tree_add_expert(tree, pinfo, &ei_h264_undecoded, tvb, bit_offset>>3, -1);
            return;
            /* for (i = 0; i < 6 + 2* transform_8x8_mode_flag; i++) {*/
                /* pic_scaling_list_present_flag[ i ] 1 u(1)*/
                /* if (pic_scaling_list_present_flag[ i ])*/
                /* if (i < 6)*/
                    /* scaling_list( ScalingList4x4[ i ], 16, UseDefaultScalingMatrix4x4Flag[ i ] )*/
                /* else*/
                    /* scaling_list( ScalingList8x8[ i - 6 ], 64, UseDefaultScalingMatrix8x8Flag[ i - 6 ] )*/
            /* }*/
            }

        /* second_chroma_qp_index_offset 1 se(v)*/
        dissect_h264_exp_golomb_code(tree, hf_h264_second_chroma_qp_index_offset, tvb, &bit_offset, H264_SE_V);
    }
    dissect_h264_rbsp_trailing_bits(tree, tvb, pinfo, bit_offset);
}

/*
 * 7.3.2.4 Access unit delimiter RBSP syntax
 * access_unit_delimiter_rbsp( )
 */
static void
dissect_h264_access_unit_delimiter_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset)
{
    gint bit_offset = offset << 3;
    /* primary_pic_type 6 u(3) */
    proto_tree_add_bits_item(tree, hf_h264_primary_pic_type, tvb, bit_offset, 3, ENC_BIG_ENDIAN);
    bit_offset += 3;

    /* rbsp_trailing_bits( ) 6 */
    dissect_h264_rbsp_trailing_bits(tree, tvb, pinfo, bit_offset);
}

/*
 * 7.3.2.5 End of sequence RBSP syntax
 * end_of_seq_rbsp( ) {}
 */
static void
dissect_h264_end_of_seq_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset)
{
    proto_tree_add_expert(tree, pinfo, &ei_h264_undecoded, tvb, offset, -1);
}

/*
 * 7.3.2.6 End of stream RBSP syntax
 * end_of_stream_rbsp( ) {}
 */
static void
dissect_h264_end_of_stream_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset)
{
    proto_tree_add_expert(tree, pinfo, &ei_h264_undecoded, tvb, offset, -1);
}

/*
 * 7.3.2.7 Filler data RBSP syntax
 * filler_data_rbsp( )
 */
static void
dissect_h264_filler_data_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset)
{
    /* while (next_bits( 8 ) == 0xFF) */
    /* ff_byte * equal to 0xFF * 9 f(8) */
    /* rbsp_trailing_bits( ) 9 */
    proto_tree_add_expert(tree, pinfo, &ei_h264_undecoded, tvb, offset, -1);
}

/*
 * 7.3.2.1.2 Sequence parameter set extension RBSP syntax
 * seq_parameter_set_extension_rbsp( )
 */
static void
dissect_h264_seq_parameter_set_extension_rbsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset)
{
    /* seq_parameter_set_id 10 ue(v) */
    /* aux_format_idc 10 ue(v) */
    /* if (aux_format_idc != 0 ) { */
    /* bit_depth_aux_minus8 10 ue(v) */
    /* alpha_incr_flag 10 u(1) */
    /* alpha_opaque_value 10 u(v) */
    /* alpha_transparent_value 10 u(v) */
    /* } */
    /* additional_extension_flag 10 u(1) */
    /* rbsp_trailing_bits() 10 */
    proto_tree_add_expert(tree, pinfo, &ei_h264_undecoded, tvb, offset, -1);
}

/* RFC 6190 Section: 1.1.3 - NAL Unit Header Extension - H.264 Annex G*/
static gint
dissect_h264_svc_nal_header_extension(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset)
{
    proto_tree_add_item(tree, hf_h264_nal_hdr_ext_svc,  tvb, offset,     1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_nal_hdr_ext_i,    tvb, offset,     1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_nal_hdr_ext_prid, tvb, offset,     1, ENC_BIG_ENDIAN);

    proto_tree_add_item(tree, hf_h264_nal_hdr_ext_n,    tvb, offset + 1, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_nal_hdr_ext_did,  tvb, offset + 1, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_nal_hdr_ext_qid,  tvb, offset + 1, 1, ENC_BIG_ENDIAN);

    proto_tree_add_item(tree, hf_h264_nal_hdr_ext_tid,  tvb, offset + 2, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_nal_hdr_ext_u,    tvb, offset + 2, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_nal_hdr_ext_d,    tvb, offset + 2, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_nal_hdr_ext_o,    tvb, offset + 2, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_nal_hdr_ext_rr,   tvb, offset + 2, 1, ENC_BIG_ENDIAN);

    return offset + 3;
}
/* H.264 Annex G Prefix NAL Unit */

static int dissect_h264_prefix(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
    guint8  svc_extension_flag;

    svc_extension_flag = tvb_get_bits8(tvb, offset << 3, 1);
    if (svc_extension_flag)
    {
        /* Annex G NAL Unit Header SVC Extension */
        dissect_h264_svc_nal_header_extension (tree, tvb, pinfo, offset);
    }
    else
    {
        /* Annex H NAL Unit Header MVC Extension */
        /* Not Decoded */
        offset +=3;
    }
    return offset;
}

/* RFC 6190 Section: 4.9 - Payload Content Scalability Information (PACSI) */
static void
// NOLINTNEXTLINE(misc-no-recursion)
dissect_h264_pacsi(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
{
    gint8       pacsi_flags;
    guint16     nal_unit_size;
    tvbuff_t    *nalu_tvb;
    gboolean    error = FALSE;
    gboolean    contains_sei = FALSE;

    offset = dissect_h264_svc_nal_header_extension(tree, tvb, pinfo, offset);

    pacsi_flags = tvb_get_guint8(tvb, offset);
    proto_tree_add_item(tree, hf_h264_pacsi_x, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_pacsi_y, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_pacsi_t, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_pacsi_a, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_pacsi_p, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_pacsi_c, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_pacsi_s, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_pacsi_e, tvb, offset, 1, ENC_BIG_ENDIAN);
    offset++;

    if (pacsi_flags & 0x40)
    {
        proto_tree_add_item(tree, hf_h264_pacsi_tl0picidx, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset++;
        proto_tree_add_item(tree, hf_h264_pacsi_idrpicid, tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 2;
    }
    if (pacsi_flags & 0x20)
    {
        proto_tree_add_item(tree, hf_h264_pacsi_donc, tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 2;
    }
    if (tvb_reported_length_remaining(tvb, offset) > 0)
    {
        contains_sei = TRUE;
        col_append_fstr(pinfo->cinfo, COL_INFO, "(");
    }

    /* Decode the SEI units that are in the packet. */
    while (tvb_reported_length_remaining(tvb, offset) > 0 && !error)
    {
        nal_unit_size = tvb_get_ntohs(tvb, offset);
        proto_tree_add_item(tree, hf_h264_nalu_size, tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 2;

        if (nal_unit_size == 0 || nal_unit_size > tvb_reported_length_remaining(tvb, offset))
        {
            proto_tree_add_expert(tree, pinfo, &ei_h264_bad_nal_length, tvb, offset-2, 2);
            error = TRUE;
        }
        else
        {
            /* Make a new subset of the existing buffer for the NAL unit */
            nalu_tvb = tvb_new_subset_length_caplen(tvb, offset, tvb_captured_length_remaining(tvb,offset), nal_unit_size);
            /* Decode the NAL unit */
            dissect_h264(nalu_tvb, pinfo, tree, NULL);
            offset += nal_unit_size;
        }
    }
    if (contains_sei == TRUE)
    {
        col_append_fstr(pinfo->cinfo, COL_INFO, ")");
    }
}

/*
 * RFC 3984 Section 5.7.1 - Single-Time Aggregation Packet (STAP)
 */
static void
// NOLINTNEXTLINE(misc-no-recursion)
dissect_h264_stap(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset, gint8 nal_type)
{
    guint16     nal_unit_size;
    tvbuff_t    *nalu_tvb;
    proto_item  *item;

    /* If it is a STAP-B then the Decoder Order Number if present before the NAL Units */
    if (nal_type == H264_STAP_B)
    {
        proto_tree_add_item(tree, hf_h264_don, tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 2;
    }

    while (tvb_reported_length_remaining(tvb, offset) > 0)
    {
        /* Get the size of the NAL unit and display */
        proto_tree_add_item(tree, hf_h264_nalu_size, tvb, offset, 2, ENC_BIG_ENDIAN);
        nal_unit_size = tvb_get_ntohs(tvb, offset);
        offset += 2;

        /* Do a sanity check on the unit size versus what is left in the packet. */
        if (nal_unit_size == 0 || tvb_reported_length_remaining(tvb, offset) < nal_unit_size)
        {
            /* Throw an exception if the size is wrong and don't try to decode the rest of the packet. */
            col_append_fstr(pinfo->cinfo, COL_INFO, "  [Bad NAL Length]");
            item = proto_tree_add_expert (tree, pinfo, &ei_h264_bad_nal_length, tvb, offset-2, 2);
            proto_item_append_text(item, " Size of %d, Remaining %d",
                    nal_unit_size, tvb_reported_length_remaining(tvb, offset));
            offset += tvb_reported_length_remaining(tvb, offset);
        }
        else
        {
            /* Make a new subset of the existing buffer for the NAL unit */
            nalu_tvb = tvb_new_subset_length_caplen(tvb, offset, tvb_captured_length_remaining(tvb, offset), nal_unit_size);
            /* Decode the NAL unit */
            dissect_h264(nalu_tvb, pinfo, tree, NULL);
            offset += nal_unit_size;
        }
    }
}

/*
 * RFC 3984 Section 5.7.2 Multi-Time Aggregation Packet (MTAP)
 */
static void
// NOLINTNEXTLINE(misc-no-recursion)
dissect_h264_mtap(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset, gint8 nal_type)
{
    gint        size_offset;
    guint16     nal_unit_size;
    tvbuff_t    *nalu_tvb;
    proto_item  *item;

    /* Get the DON base value for type MTAP16 & MTAP24 */
    proto_tree_add_item(tree, hf_h264_don, tvb, offset, 2, ENC_BIG_ENDIAN);
    offset += 2;

    while (tvb_reported_length_remaining(tvb, offset) > 0)
    {
        proto_tree_add_item(tree, hf_h264_nalu_size, tvb, offset, 2, ENC_BIG_ENDIAN);
        nal_unit_size = tvb_get_ntohs(tvb, offset);
        size_offset = offset;
        offset += 2;
        proto_tree_add_item(tree, hf_h264_dond, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset += 1;

        if (nal_type == H264_MTAP16)
        {
            /* Get the 16 bit DOND value */
            proto_tree_add_item(tree, hf_h264_ts_offset16, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
        }
        else
        {
            /* Get the 24 bit DOND value */
            proto_tree_add_item(tree, hf_h264_ts_offset24, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 3;
        }

        if (nal_unit_size == 0 || tvb_reported_length_remaining(tvb, offset) < nal_unit_size)
        {
            /* Throw an exception if the size is wrong and don't try to decode the rest of the packet. */
            col_append_fstr(pinfo->cinfo, COL_INFO, "  [Bad NAL Length]");
            item = proto_tree_add_expert (tree, pinfo, &ei_h264_bad_nal_length, tvb, size_offset, 2);
            proto_item_append_text(item, " Size of %d, Remaining %d",
                    nal_unit_size, tvb_reported_length_remaining(tvb, offset));
            offset += tvb_reported_length_remaining(tvb, offset);
        }
        else
        {
            /* Make a new subset of the existing buffer for the NAL unit */
            nalu_tvb = tvb_new_subset_length_caplen(tvb, offset, tvb_captured_length_remaining(tvb, offset), nal_unit_size);
            /* Decode the NAL unit */
            dissect_h264(nalu_tvb, pinfo, tree, NULL);
            offset += nal_unit_size;
        }
    }
}

/*
 * Dissect NAL Header extension and NI-MTAP Subtype defined in RFC 6190
 */
static void
// NOLINTNEXTLINE(misc-no-recursion)
dissect_h264_nalu_extension (proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset)
{
    gint        size_offset;
    guint16     nal_unit_size;
    tvbuff_t    *nalu_tvb;
    guint8      subtype;
    guint8      j_flag;
    guint8      bit_offset = offset << 3;
    guint8      unit = 1;
    proto_item  *item;
    proto_tree  *nimtap_tree;

    subtype = tvb_get_bits8(tvb, bit_offset, 5);
    j_flag  = tvb_get_bits8(tvb, bit_offset+5, 1);

    /* NAL Header Extension Decoding */
    proto_tree_add_item(tree, hf_h264_nal_extension_subtype, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_h264_nal_extension_j, tvb, offset, 1, ENC_NA);
    proto_tree_add_item(tree, hf_h264_nal_extension_k, tvb, offset, 1, ENC_NA);
    proto_tree_add_item(tree, hf_h264_nal_extension_l, tvb, offset, 1, ENC_NA);
    col_append_fstr(pinfo->cinfo, COL_INFO, "  %s",
                    val_to_str(subtype, h264_subtype_summary_values, "Unknown Subtype (%u)"));
    offset++;

    if (subtype == 2)
    {
        /* Multi-Time Aggregation Packet (NI-MTAP) - RFC 6190 Section 4.7.1 */
        while (tvb_reported_length_remaining(tvb, offset) > 0)
        {
            nimtap_tree = proto_tree_add_subtree_format(tree, tvb, offset, 1, ett_h264_ni_mtap, NULL, "NI-MTAP Unit %d", unit++);
            proto_tree_add_item(nimtap_tree, hf_h264_nalu_size, tvb, offset, 2, ENC_BIG_ENDIAN);
            nal_unit_size = tvb_get_ntohs(tvb, offset);
            size_offset = offset;
            offset += 2;
            proto_tree_add_item(nimtap_tree, hf_h264_ts_offset16, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            /* If J flag is set then DON is present in packet */
            if (j_flag)
            {
                proto_tree_add_item(nimtap_tree, hf_h264_don, tvb, offset, 2, ENC_BIG_ENDIAN);
                offset += 2;
            }
            if (nal_unit_size == 0 || tvb_reported_length_remaining(tvb, offset) < nal_unit_size)
            {
                /* Throw an exception if the size is wrong and don't try to decode the rest of the packet. */
                col_append_fstr(pinfo->cinfo, COL_INFO, "  [Bad NAL Length]");
                item = proto_tree_add_expert (nimtap_tree, pinfo, &ei_h264_bad_nal_length, tvb, size_offset, 2);
                proto_item_append_text(item, " Size of %d, Remaining %d",
                        nal_unit_size, tvb_reported_length_remaining(tvb, offset));
                offset += tvb_reported_length_remaining(tvb, offset);
            }
            else
            {
                /* Make a new subset of the existing buffer for the NAL unit */
                nalu_tvb = tvb_new_subset_length_caplen(tvb, offset, tvb_captured_length_remaining(tvb, offset), nal_unit_size);
                /* Decode the NAL unit */
                dissect_h264(nalu_tvb, pinfo, nimtap_tree, NULL);
                offset += nal_unit_size;
            }
        }
    }
}

/*
 * Dissect NAL unit as received in sprop-parameter-sets of SDP
 * or "DecoderConfiguration parameter in H.245
 */
void
dissect_h264_nal_unit(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
    proto_item *item, *nal_item;
    proto_tree *h264_nal_tree;
    gint        offset = 0;
    guint8      nal_unit_type;
    guint32     dword;

    item          = proto_tree_add_item(tree, hf_h264_nal_unit, tvb, offset, -1, ENC_NA);
    h264_nal_tree = proto_item_add_subtree(item, ett_h264_nal_unit);

startover:
    /* In decoder configuration start code may be pressent
     * B.1.1 Byte stream NAL unit syntax
     */
    if (tvb_reported_length_remaining(tvb, offset<<3) >= 4) {
        dword = tvb_get_bits32(tvb, offset<<3, 32, ENC_BIG_ENDIAN);
        if (dword == 1) {
            /* zero_byte + start_code_prefix_one_3bytes */
            offset+=4;
        } else if ((dword >> 8) == 1) {
            /* start_code_prefix_one_3bytes */
            offset+= 3;
        }
    }
    /* 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, ENC_BIG_ENDIAN);
    /* nal_ref_idc All u(2) */
    proto_tree_add_item(h264_nal_tree, hf_h264_nal_ref_idc, tvb, offset, 1, ENC_BIG_ENDIAN);
    /* nal_unit_type All u(5) */
    nal_item = proto_tree_add_item(h264_nal_tree, hf_h264_nal_unit_type, tvb, offset, 1, ENC_BIG_ENDIAN);
    offset++;

    switch (nal_unit_type) {
    case 1: /* Coded slice of a non-IDR picture */
        dissect_h264_slice_layer_without_partitioning_rbsp(h264_nal_tree, tvb, pinfo, offset);
        break;
    case 2: /* Coded slice data partition A */
        dissect_h264_slice_data_partition_a_layer_rbsp(h264_nal_tree, tvb, pinfo, offset);
        break;
    case 3: /* Coded slice data partition B */
        dissect_h264_slice_data_partition_b_layer_rbsp(h264_nal_tree, tvb, pinfo, offset);
        break;
    case 4: /* Coded slice data partition C */
        dissect_h264_slice_data_partition_c_layer_rbsp(h264_nal_tree, tvb, pinfo, offset);
        break;
    case 5: /* Coded slice of an IDR picture */
        dissect_h264_slice_layer_without_partitioning_rbsp(h264_nal_tree, tvb, pinfo, offset);
        break;
    case 6: /* Supplemental enhancement information (SEI) */
        dissect_h264_sei_rbsp(h264_nal_tree, tvb, pinfo, offset);
        break;
    case H264_SEQ_PAR_SET:  /* 7 Sequence parameter set*/
        offset = dissect_h264_seq_parameter_set_rbsp(h264_nal_tree, tvb, pinfo, offset);
        /* A bit ugly */
        if ((offset != -1) && (tvb_reported_length_remaining(tvb, offset) > 0)) {
            /* In this case length = offset as we start from zero */
            proto_item_set_len(item, offset/*Length */);
            item = proto_tree_add_item(tree, hf_h264_nal_unit, tvb, offset, -1, ENC_NA);
            h264_nal_tree = proto_item_add_subtree(item, ett_h264_nal_unit);
            goto startover;
        }
        break;
    case H264_PIC_PAR_SET:  /* 8 Picture parameter set */
        dissect_h264_pic_parameter_set_rbsp(h264_nal_tree, tvb, pinfo, offset);
        break;
    case 9: /* Access unit delimiter */
        dissect_h264_access_unit_delimiter_rbsp(h264_nal_tree, tvb, pinfo, offset);
        break;
    case 10:    /* End of sequence */
        dissect_h264_end_of_seq_rbsp(h264_nal_tree, tvb, pinfo, offset);
        break;
    case 11:    /* End of stream */
        dissect_h264_end_of_stream_rbsp(h264_nal_tree, tvb, pinfo, offset);
        break;
    case 12:    /* Filler data */
        dissect_h264_filler_data_rbsp(h264_nal_tree, tvb, pinfo, offset);
        break;
    case 13:    /* Sequence parameter set extension */
        dissect_h264_seq_parameter_set_extension_rbsp(h264_nal_tree, tvb, pinfo, offset);
        break;
    case 14:    /* Reserved */
    case 15:    /* Reserved */
    case 16:    /* Reserved */
    case 17:    /* Reserved */
    case 18:    /* Reserved */
        expert_add_info(pinfo, nal_item, &ei_h264_nal_unit_type_reserved);
        break;
    case 19:    /* Coded slice of an auxiliary coded picture without partitioning */
        dissect_h264_slice_layer_without_partitioning_rbsp(tree, tvb, pinfo, offset);
        break;
    case 28:
        dissect_h264_slice_layer_without_partitioning_rbsp(tree, tvb, pinfo, offset);
        break;
    case 0: /* Unspecified */
    default:
        /* 24..31 Unspecified */
        expert_add_info(pinfo, nal_item, &ei_h264_nal_unit_type_unspecified);
        break;
    }
}

/* Annex B "Byte stream format" */
static int
dissect_h264_bytestream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
    proto_tree *h264_tree;
    proto_item *item;

    tvbuff_t *next_tvb, *rbsp_tvb;
    gint offset = 0, end_offset;
    guint32 dword;

    /* Look for the first start word. Assume byte aligned. */
    while (1) {
        if (tvb_reported_length(tvb) < 4) {
            return 0;
        }
        dword = tvb_get_guint32(tvb, offset, ENC_BIG_ENDIAN);
        if ((dword >> 8) == 1 || dword == 1) {
            break;
        } else if (dword != 0) {
            return 0;
        }
        offset += 2;
    }

    col_set_str(pinfo->cinfo, COL_PROTOCOL, "H.264");
    item = proto_tree_add_item(tree, proto_h264, tvb, 0, -1, ENC_NA);
    h264_tree = proto_item_add_subtree(item, ett_h264);

    while (tvb_reported_length_remaining(tvb, offset)) {
        dword = tvb_get_guint32(tvb, offset, ENC_BIG_ENDIAN);
        if ((dword >> 8) != 1) {
            /* zero_byte */
            offset++;
        }
        /* start_code_prefix_one_3bytes */
        offset += 3;
        gint nal_length = tvb_reported_length_remaining(tvb, offset);
        /* Search for either \0\0\1 or \0\0\0\1:
         * Find \0\0 and then check if \0\1 is in the next offset or
         * the one after that. (Note none of this throws exceptions.)
         */
        end_offset = tvb_find_guint16(tvb, offset, -1, 0);
        while (end_offset != -1) {
            if (tvb_find_guint16(tvb, end_offset + 1, 3, 1) != -1) {
                nal_length = end_offset - offset;
                break;
            }
            end_offset = tvb_find_guint16(tvb, end_offset + 1, -1, 0);
        }

        /* If end_offset is -1, we got to the end; assume this is the end
         * of the NAL. To handle a bytestream that fragments NALs across
         * lower level packets (does any implementation do this?), we would
         * need to use epan/stream.h
         */

        /* Unescape NAL unit */
        next_tvb = tvb_new_subset_length(tvb, offset, nal_length);
        rbsp_tvb = dissect_h265_unescap_nal_unit(next_tvb, pinfo, 0);

        dissect_h264_nal_unit(rbsp_tvb, pinfo, h264_tree);
        offset += nal_length;
    }
    return tvb_reported_length(tvb);
}

/* Code to actually dissect the packets */
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_h264(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
    int         offset = 0;
    proto_item *item;
    proto_tree *h264_tree, *h264_nal_tree, *stream_tree, *fua_tree;
    guint8      type;
    tvbuff_t   *rbsp_tvb;


    /* Make entries in Protocol column and Info column on summary display */
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "H.264");

    type = tvb_get_guint8(tvb, offset)&0x1f;

    col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
                    val_to_str(type, h264_type_summary_values, "Unknown Type (%u)"));

    /* if (tree) */ {
        item = proto_tree_add_item(tree, proto_h264, tvb, 0, -1, ENC_NA);
        h264_tree = proto_item_add_subtree(item, ett_h264);

        /* if the type is 28, it would be draw another title */
        if (type == 28)
            h264_nal_tree = proto_tree_add_subtree(h264_tree, tvb, offset, 1, ett_h264_nal, NULL, "FU identifier");
        else
            h264_nal_tree = proto_tree_add_subtree(h264_tree, tvb, offset, 1, ett_h264_nal, NULL, "NAL unit header or first byte of the payload");

        /* +---------------+
         * |0|1|2|3|4|5|6|7|
         * +-+-+-+-+-+-+-+-+
         * |F|NRI|  Type   |
         * +---------------+
         */

        /* F: 1 bit
         * forbidden_zero_bit.  A value of 0 indicates that the NAL unit type
         * octet and payload should not contain bit errors or other syntax
         * violations.  A value of 1 indicates that the NAL unit type octet
         * and payload may contain bit errors or other syntax violations.
         */
        proto_tree_add_item(h264_nal_tree, hf_h264_nal_f_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
        proto_tree_add_item(h264_nal_tree, hf_h264_nal_nri,   tvb, offset, 1, ENC_BIG_ENDIAN);

        proto_tree_add_item(h264_nal_tree, hf_h264_type, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset++;
        if (type == 28) {
            fua_tree = proto_tree_add_subtree(h264_tree, tvb, offset, 1, ett_h264_fua, NULL, "FU Header");
            proto_tree_add_item(fua_tree, hf_h264_start_bit,     tvb, offset, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(fua_tree, hf_h264_end_bit,       tvb, offset, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(fua_tree, hf_h264_forbidden_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(fua_tree, hf_h264_nal_unit_type, tvb, offset, 1, ENC_BIG_ENDIAN);
            if ((tvb_get_guint8(tvb, offset)&0x80) == 0x80) {
                type = tvb_get_guint8(tvb, offset)&0x1f;
                col_append_fstr(pinfo->cinfo, COL_INFO, " Start:%s",
                                val_to_str(type, h264_type_summary_values, "Unknown Type (%u)"));
                offset++;
            }
            else
            {
                if ((tvb_get_guint8(tvb, offset)&0x40) == 0x40) {
                    col_append_fstr(pinfo->cinfo, COL_INFO, " End");
                }
                return offset;
            }
        }

        /* Unescape NAL unit */
        rbsp_tvb = dissect_h265_unescap_nal_unit(tvb, pinfo, offset);

        stream_tree = proto_tree_add_subtree(h264_tree, tvb, offset, -1, ett_h264_stream, NULL, "H264 NAL Unit Payload");
        increment_dissection_depth(pinfo);
        switch (type) {
        case 1:             /* 1 Coded slice of a non-IDR picture */
            dissect_h264_slice_layer_without_partitioning_rbsp(stream_tree, rbsp_tvb, pinfo, 0);
            break;
        case 3: /* Coded slice data partition B */
            dissect_h264_slice_data_partition_b_layer_rbsp(stream_tree, rbsp_tvb, pinfo, 0);
            break;
        case 4: /* Coded slice data partition C */
            dissect_h264_slice_data_partition_c_layer_rbsp(stream_tree, rbsp_tvb, pinfo, 0);
            break;
        case 5: /* Coded slice of an IDR picture */
            dissect_h264_slice_layer_without_partitioning_rbsp(stream_tree, rbsp_tvb, pinfo, 0);
            break;
        case 6: /* Supplemental enhancement information (SEI) */
            dissect_h264_sei_rbsp(stream_tree, tvb, pinfo, offset);
            break;
        case H264_SEQ_PAR_SET:  /* 7 Sequence parameter set*/
            dissect_h264_seq_parameter_set_rbsp(stream_tree, rbsp_tvb, pinfo, 0);
            break;
        case H264_PIC_PAR_SET:  /* 8 Picture parameter set */
            dissect_h264_pic_parameter_set_rbsp(stream_tree, rbsp_tvb, pinfo, 0);
            break;
        case H264_PREFIX:
            dissect_h264_prefix(stream_tree, rbsp_tvb, pinfo, 0);
            break;
        case 19:    /* Coded slice of an auxiliary coded picture without partitioning */
            dissect_h264_slice_layer_without_partitioning_rbsp(stream_tree, rbsp_tvb, pinfo, 0);
            break;
        case H264_STAP_A:       /* STAP-A */
        case H264_STAP_B:       /* STAP-B */
            dissect_h264_stap(stream_tree, tvb, pinfo, offset, type);
            break;
        case H264_MTAP16:       /* MSTAP16 */
        case H264_MTAP24:       /* MSTAP24 */
            dissect_h264_mtap(stream_tree, tvb, pinfo, offset, type);
            break;
        case H264_PACSI:        /* PACSI */
            dissect_h264_pacsi(stream_tree, tvb, pinfo, offset);
            break;
        case H264_EXTENSION:    /* Extension Header */
            dissect_h264_nalu_extension(stream_tree, rbsp_tvb, pinfo, 0);
            break;
        default:
            break;
        }
        decrement_dissection_depth(pinfo);
    } /* if (tree) */
    return tvb_captured_length(tvb);
}


/* Capability */

static int * const profile_fields[] = {
    &hf_h264_par_profile_b,
    &hf_h264_par_profile_m,
    &hf_h264_par_profile_e,
    &hf_h264_par_profile_h,
    &hf_h264_par_profile_h10,
    &hf_h264_par_profile_h4_2_2,
    &hf_h264_par_profile_h4_4_4,
    NULL
};

static int
dissect_h264_par_profile(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
{
    int offset = 0;

    proto_tree_add_bitmask(tree, tvb, offset,
                           hf_h264_par_profile, ett_h264_par_profile,
                           profile_fields, ENC_BIG_ENDIAN);
    offset += 1;
    return offset;
}

static int * const AdditionalModesSupported_fields[] = {
    &hf_h264_par_add_mode_sup_rcdo,
    NULL
};

static int
dissect_h264_par_AdditionalModesSupported(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
{
    int offset = 0;

    proto_tree_add_bitmask(tree, tvb, offset,
                           hf_h264_par_AdditionalModesSupported, ett_h264_par_AdditionalModesSupported,
                           AdditionalModesSupported_fields, ENC_BIG_ENDIAN);
    offset += 1;
    return offset;
}


static int * const ProfileIOP_fields[] = {
    &hf_h264_par_constraint_set0_flag,
    &hf_h264_par_constraint_set1_flag,
    &hf_h264_par_constraint_set2_flag,
    NULL
};


static int
dissect_h264_ProfileIOP(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
{
    int offset = 0;

    proto_tree_add_bitmask(tree, tvb, offset,
                           hf_h264_par_ProfileIOP, ett_h264_par_ProfileIOP,
                           ProfileIOP_fields, ENC_BIG_ENDIAN);
    offset += 1;
    return offset;
}

static const value_string h264_par_level_values[] = {
    {  15,    "1" },
    {  19,    "1b" },
    {  22,    "1.1" },
    {  29,    "1.2" },
    {  36,    "1.3" },
    {  43,    "2" },
    {  50,    "2.1" },
    {  57,    "2.2" },
    {  64,    "3" },
    {  71,    "3.1" },
    {  78,    "3.2" },
    {  85,    "4" },
    {  92,    "4.1" },
    {  99,    "4.2" },
    { 106,    "5" },
    { 113 ,   "5.1" },
    { 0,  NULL }
};

static int
dissect_h264_par_level(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, void *data)
{
    int          offset = 0;
    guint16      lvl;
    const gchar *p;
    asn1_ctx_t  *actx;

    /* Reject the packet if data is NULL */
    if (data == NULL)
        return 0;
    actx = get_asn1_ctx(data);
    DISSECTOR_ASSERT(actx);

    lvl = tvb_get_ntohs(tvb, offset);
    p = try_val_to_str(lvl, VALS(h264_par_level_values));
    if (p) {
        proto_item_append_text(actx->created_item, " - Level %s", p);
    }
    offset += 2;
    return offset;
}

static int
dissect_h264_par_DecoderConfigurationInformation(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
    asn1_ctx_t *actx;

    /* Reject the packet if data is NULL */
    if (data == NULL)
        return 0;
    actx = get_asn1_ctx(data);
    DISSECTOR_ASSERT(actx);

    dissect_h264_nal_unit(tvb, pinfo, tree);

    return tvb_reported_length(tvb);
}

typedef struct _h264_capability_t {
    const gchar *id;
    const gchar *name;
    dissector_t content_pdu;
} h264_capability_t;

static h264_capability_t h264_capability_tab[] = {
    /* ITU-T H.241 (05/2006), 8.3 H.264 capabilities */
    { "GenericCapability/0.0.8.241.0.0.1", "ITU-T Rec. H.241 H.264 Video Capabilities", NULL },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/41", "Profile", dissect_h264_par_profile },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/42", "Level", dissect_h264_par_level },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/3" , "CustomMaxMBPS", NULL },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/4" , "CustomMaxFS", NULL },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/5" , "CustomMaxDPB", NULL },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/6" , "CustomMaxBRandCPB", NULL },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/7" , "MaxStaticMBPS", NULL },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/8" , "max-rcmd-nal-unit-size", NULL },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/9" , "max-nal-unit-size", NULL },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/10", "SampleAspectRatiosSupported", NULL },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/11", "AdditionalModesSupported", dissect_h264_par_AdditionalModesSupported },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/12", "AdditionalDisplayCapabilities", NULL },
    /* TS 26.111  H.264 */
    { "GenericCapability/0.0.8.241.0.0.1/nonCollapsing/43" , "DecoderConfigurationInformation", dissect_h264_par_DecoderConfigurationInformation },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/44" , "AcceptRedundantSlices", NULL },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/45" , "NalAlignedMode", NULL },
    { "GenericCapability/0.0.8.241.0.0.1/collapsing/46" , "ProfileIOP", dissect_h264_ProfileIOP },
    { NULL, NULL, NULL },
};

static h264_capability_t *find_cap(const gchar *id) {
    h264_capability_t *ftr = NULL;
    h264_capability_t *f;

    for (f=h264_capability_tab; f->id; f++) {
        if (!strcmp(id, f->id)) { ftr = f; break; }
    }
    return ftr;
}

static int
dissect_h264_name(tvbuff_t *tvb _U_, packet_info *pinfo, proto_tree *tree, void* data)
{
    asn1_ctx_t *actx;

    /* Reject the packet if data is NULL */
    if (data == NULL)
        return 0;
    actx = get_asn1_ctx(data);
    DISSECTOR_ASSERT(actx);

    if (tree) {
        h264_capability_t *ftr;
        ftr = find_cap(pinfo->match_string);
        if (ftr) {
            proto_item_append_text(actx->created_item, " - %s", ftr->name);
            proto_item_append_text(proto_item_get_parent(proto_tree_get_parent(tree)), ": %s", ftr->name);
        } else {
            proto_item_append_text(actx->created_item, " - unknown(%s)", pinfo->match_string);
        }
    }

    return tvb_reported_length(tvb);
}


void
proto_register_h264(void)
{
    module_t *h264_module;
    expert_module_t* expert_h264;

/* Setup list of header fields  See Section 1.6.1 for details*/
    static hf_register_info hf[] = {
        { &hf_h264_nal_f_bit,
            { "F bit",           "h264.f",
            FT_BOOLEAN, 8, TFS(&h264_f_bit_vals), 0x80,
            NULL, HFILL }
        },
        { &hf_h264_nal_nri,
            { "Nal_ref_idc (NRI)",           "h264.nal_nri",
            FT_UINT8, BASE_DEC, NULL, 0x60,
            NULL, HFILL }
        },
        { &hf_h264_type,
            { "Type",           "h264.nal_unit_hdr",
            FT_UINT8, BASE_DEC, VALS(h264_type_values), 0x1f,
            NULL, HFILL }
        },
        { &hf_h264_start_bit,
            { "Start bit", "h264.start.bit",
            FT_BOOLEAN, 8, TFS(&h264_start_bit_vals), 0x80,
            NULL, HFILL }
        },
        { &hf_h264_end_bit,
            { "End bit", "h264.end.bit",
            FT_BOOLEAN, 8, TFS(&h264_end_bit_vals), 0x40,
            NULL, HFILL }
        },
        { &hf_h264_forbidden_bit,
            { "Forbidden bit", "h264.forbidden.bit",
            FT_UINT8, BASE_DEC, NULL, 0x20,
            NULL, HFILL }
        },
        { &hf_h264_profile,
            { "Profile",           "h264.profile",
            FT_BYTES, BASE_NONE, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_profile_idc,
            { "Profile_idc",           "h264.profile_idc",
            FT_UINT8, BASE_DEC, VALS(h264_profile_idc_values), 0x0,
            NULL, HFILL }
        },
        { &hf_h264_rbsp_stop_bit,
            { "rbsp_stop_bit",           "h264.rbsp_stop_bit",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_rbsp_trailing_bits,
            { "rbsp_trailing_bits",           "h264.rbsp_trailing_bits",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_constraint_set0_flag,
            { "Constraint_set0_flag",           "h264.constraint_set0_flag",
            FT_UINT8, BASE_DEC, NULL, 0x80,
            NULL, HFILL }
        },
        { &hf_h264_constraint_set1_flag,
            { "Constraint_set1_flag",           "h264.constraint_set1_flag",
            FT_UINT8, BASE_DEC, NULL, 0x40,
            NULL, HFILL }
        },
        { &hf_h264_constraint_set2_flag,
            { "Constraint_set2_flag",           "h264.constraint_set2_flag",
            FT_UINT8, BASE_DEC, NULL, 0x20,
            NULL, HFILL }
        },
        { &hf_h264_constraint_set3_flag,
            { "Constraint_set3_flag",           "h264.constraint_set3_flag",
            FT_UINT8, BASE_DEC, NULL, 0x10,
            NULL, HFILL }
        },
        { &hf_h264_constraint_set4_flag,
            { "Constraint_set4_flag",           "h264.constraint_set4_flag",
            FT_UINT8, BASE_DEC, NULL, 0x08,
            NULL, HFILL }
        },
        { &hf_h264_constraint_set5_flag,
            { "Constraint_set5_flag",           "h264.constraint_set5_flag",
            FT_UINT8, BASE_DEC, NULL, 0x04,
            NULL, HFILL }
        },
        { &hf_h264_reserved_zero_2bits,
            { "Reserved_zero_2bits",           "h264.reserved_zero_2bits",
            FT_UINT8, BASE_DEC, NULL, 0x03,
            NULL, HFILL }
        },
        { &hf_h264_level_idc,
            { "Level_id",           "h264.level_id",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_nal_unit,
            { "NAL unit",           "h264.nal_unit",
            FT_BYTES, BASE_NONE, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_forbidden_zero_bit,
            { "Forbidden_zero_bit",           "h264.forbidden_zero_bit",
            FT_UINT8, BASE_DEC, NULL, 0x80,
            NULL, HFILL }
        },
        { &hf_h264_nal_ref_idc,
            { "Nal_ref_idc",           "h264.nal_ref_idc",
            FT_UINT8, BASE_DEC, NULL, 0x60,
            NULL, HFILL }
        },
        {&hf_h264_nal_unit_type,
            { "Nal_unit_type",           "h264.nal_unit_type",
            FT_UINT8, BASE_DEC, VALS(h264_nal_unit_type_vals), 0x1f,
            NULL, HFILL }
        },
        { &hf_h264_seq_parameter_set_id,
            { "seq_parameter_set_id",           "h264.seq_parameter_set_id",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_chroma_format_idc,
            { "chroma_format_id",           "h264.chroma_format_id",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_residual_colour_transform_flag,
            { "residual_colour_transform_flag",           "h264.residual_colour_transform_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_bit_depth_luma_minus8,
            { "bit_depth_luma_minus8",           "h264.bit_depth_luma_minus8",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_bit_depth_chroma_minus8,
            { "bit_depth_chroma_minus8",           "h264.bit_depth_chroma_minus8",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_qpprime_y_zero_transform_bypass_flag,
            { "qpprime_y_zero_transform_bypass_flag",           "h264.qpprime_y_zero_transform_bypass_flag",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_seq_scaling_matrix_present_flag,
            { "seq_scaling_matrix_present_flag",           "h264.seq_scaling_matrix_present_flag",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_seq_scaling_list_present_flag,
            { "seq_scaling_list_present_flag",           "h264.seq_scaling_list_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_delta_scale,
            { "delta_scale",           "h264.delta_scale",
            FT_INT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_log2_max_frame_num_minus4,
            { "log2_max_frame_num_minus4",           "h264.log2_max_frame_num_minus4",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_pic_order_cnt_type,
            { "pic_order_cnt_type",           "h264.pic_order_cnt_type",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_log2_max_pic_order_cnt_lsb_minus4,
            { "log2_max_pic_order_cnt_lsb_minus4",           "h264.log2_max_pic_order_cnt_lsb_minus4",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_delta_pic_order_always_zero_flag,
            { "delta_pic_order_always_zero_flag",           "h264.delta_pic_order_always_zero_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_offset_for_non_ref_pic,
            { "offset_for_non_ref_pic",           "h264.offset_for_non_ref_pic",
            FT_INT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_offset_for_top_to_bottom_field,
            { "offset_for_top_to_bottom_field",           "h264.offset_for_top_to_bottom_field",
            FT_INT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_num_ref_frames_in_pic_order_cnt_cycle,
            { "num_ref_frames_in_pic_order_cnt_cycle",           "h264.num_ref_frames_in_pic_order_cnt_cycle",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_offset_for_ref_frame,
            { "offset_for_ref_frame",           "h264.offset_for_ref_frame",
            FT_INT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_num_ref_frames,
            { "num_ref_frames",           "h264.num_ref_frames",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_gaps_in_frame_num_value_allowed_flag,
            { "gaps_in_frame_num_value_allowed_flag",           "h264.gaps_in_frame_num_value_allowed_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_pic_width_in_mbs_minus1,
            { "pic_width_in_mbs_minus1",           "h264.pic_width_in_mbs_minus1",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_pic_height_in_map_units_minus1,
            { "pic_height_in_map_units_minus1",           "h264.pic_height_in_map_units_minus1",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_frame_mbs_only_flag,
            { "frame_mbs_only_flag",           "h264.frame_mbs_only_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_mb_adaptive_frame_field_flag,
            { "mb_adaptive_frame_field_flag",           "h264.mb_adaptive_frame_field_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_direct_8x8_inference_flag,
            { "direct_8x8_inference_flag",           "h264.direct_8x8_inference_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_frame_cropping_flag,
            { "frame_cropping_flag",           "h264.frame_cropping_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_frame_crop_left_offset,
            { "frame_crop_left_offset",           "h264.frame_crop_left_offset",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_frame_crop_right_offset,
            { "frame_crop_right_offset",           "h264.frame_crop_right_offset",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_frame_crop_top_offset,
            { "frame_crop_top_offset",           "h264.frame_crop_top_offset",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_frame_crop_bottom_offset,
            { "frame_crop_bottom_offset",           "h264.frame_crop_bottom_offset",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_vui_parameters_present_flag,
            { "vui_parameters_present_flag",           "h264.vui_parameters_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_pic_parameter_set_id,
            { "pic_parameter_set_id",           "h264.pic_parameter_set_id",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_entropy_coding_mode_flag,
            { "entropy_coding_mode_flag",           "h264.entropy_coding_mode_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_pic_order_present_flag,
            { "pic_order_present_flag",           "h264.pic_order_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_num_slice_groups_minus1,
            { "num_slice_groups_minus1",           "h264.num_slice_groups_minus1",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_slice_group_map_type,
            { "slice_group_map_type",           "h264.slice_group_map_type",
            FT_UINT32, BASE_DEC, VALS(h264_slice_group_map_type_vals), 0x0,
            NULL, HFILL }
        },
        { &hf_h264_num_ref_idx_l0_active_minus1,
            { "num_ref_idx_l0_active_minus1",           "h264.num_ref_idx_l0_active_minus1",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_num_ref_idx_l1_active_minus1,
            { "num_ref_idx_l1_active_minus1",           "h264.num_ref_idx_l1_active_minus1",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_weighted_pred_flag,
            { "weighted_pred_flag",           "h264.weighted_pred_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_weighted_bipred_idc,
            { "weighted_bipred_idc",           "h264.weighted_bipred_idc",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_pic_init_qp_minus26,
            { "pic_init_qp_minus26",           "h264.pic_init_qp_minus26",
            FT_INT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_pic_init_qs_minus26,
            { "pic_init_qs_minus26",           "h264.pic_init_qs_minus26",
            FT_INT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_chroma_qp_index_offset,
            { "chroma_qp_index_offset",           "h264.chroma_qp_index_offset",
            FT_INT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_deblocking_filter_control_present_flag,
            { "deblocking_filter_control_present_flag",           "h264.deblocking_filter_control_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_constrained_intra_pred_flag,
            { "constrained_intra_pred_flag",           "h264.constrained_intra_pred_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_redundant_pic_cnt_present_flag,
            { "redundant_pic_cnt_present_flag",           "h264.redundant_pic_cnt_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_transform_8x8_mode_flag,
            { "transform_8x8_mode_flag",           "h264.transform_8x8_mode_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_pic_scaling_matrix_present_flag,
            { "pic_scaling_matrix_present_flag",           "h264.pic_scaling_matrix_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_second_chroma_qp_index_offset,
            { "second_chroma_qp_index_offset",           "h264.second_chroma_qp_index_offset",
            FT_INT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },

        { &hf_h264_primary_pic_type,
            { "primary_pic_type",           "h264.primary_pic_type",
            FT_INT8, BASE_DEC, VALS(h264_primary_pic_type_vals), 0x0,
            "slice_type values that may be present in the primary coded picture", HFILL }
        },

        { &hf_h264_aspect_ratio_info_present_flag,
            { "aspect_ratio_info_present_flag",           "h264.aspect_ratio_info_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_aspect_ratio_idc,
            { "aspect_ratio_idc",           "h264.aspect_ratio_idc",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sar_width,
            { "sar_width",           "h264.sar_width",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sar_height,
            { "sar_height",           "h264.sar_height",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_overscan_info_present_flag,
            { "overscan_info_present_flag",           "h264.overscan_info_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_overscan_appropriate_flag,
            { "overscan_appropriate_flag",           "h264.overscan_appropriate_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_video_signal_type_present_flag,
            { "video_signal_type_present_flag",           "h264.video_signal_type_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_video_format,
            { "video_format",           "h264.video_format",
            FT_UINT8, BASE_DEC, VALS(h264_video_format_vals), 0x0,
            NULL, HFILL }
        },
        { &hf_h264_video_full_range_flag,
            { "video_full_range_flag",           "h264.video_full_range_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_colour_description_present_flag,
            { "colour_description_present_flag",           "h264.colour_description_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_colour_primaries,
            { "colour_primaries",           "h264.colour_primaries",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_transfer_characteristics,
            { "transfer_characteristics",           "h264.transfer_characteristics",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_matrix_coefficients,
            { "matrix_coefficients",           "h264.matrix_coefficients",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_chroma_loc_info_present_flag,
            { "chroma_loc_info_present_flag",           "h264.chroma_loc_info_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_chroma_sample_loc_type_top_field,
            { "chroma_sample_loc_type_top_field",           "h264.chroma_sample_loc_type_top_field",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_chroma_sample_loc_type_bottom_field,
            { "chroma_sample_loc_type_bottom_field",           "h264.chroma_sample_loc_type_bottom_field",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_timing_info_present_flag,
            { "timing_info_present_flag",           "h264.timing_info_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_num_units_in_tick,
            { "num_units_in_tick",           "h264.num_units_in_tick",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_time_scale,
            { "time_scale",           "h264.time_scale",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_fixed_frame_rate_flag,
            { "fixed_frame_rate_flag",           "h264.fixed_frame_rate_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_nal_hrd_parameters_present_flag,
            { "nal_hrd_parameters_present_flag",           "h264.nal_hrd_parameters_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_vcl_hrd_parameters_present_flag,
            { "vcl_hrd_parameters_present_flag",           "h264.vcl_hrd_parameters_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_low_delay_hrd_flag,
            { "low_delay_hrd_flag",           "h264.low_delay_hrd_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_pic_struct_present_flag,
            { "pic_struct_present_flag",           "h264.pic_struct_present_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_bitstream_restriction_flag,
            { "bitstream_restriction_flag",           "h264.bitstream_restriction_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_motion_vectors_over_pic_boundaries_flag,
            { "motion_vectors_over_pic_boundaries_flag",           "h264.motion_vectors_over_pic_boundaries_flag",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_max_bytes_per_pic_denom,
            { "max_bytes_per_pic_denom",           "h264.max_bytes_per_pic_denom",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_max_bits_per_mb_denom,
            { "max_bits_per_mb_denom",           "h264.max_bits_per_mb_denom",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_log2_max_mv_length_horizontal,
            { "max_mv_length_horizontal",           "h264.max_mv_length_horizontal",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_log2_max_mv_length_vertical,
            { "log2_max_mv_length_vertical",           "h264.log2_max_mv_length_vertical",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_num_reorder_frames,
            { "num_reorder_frames",           "h264.num_reorder_frames",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_max_dec_frame_buffering,
            { "max_dec_frame_buffering",           "h264.max_dec_frame_buffering",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_cpb_cnt_minus1,
            { "cpb_cnt_minus1",           "h264.cpb_cnt_minus1",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_bit_rate_scale,
            { "bit_rate_scale",           "h264.bit_rate_scale",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_cpb_size_scale,
            { "cpb_size_scale",           "h264.cpb_size_scale",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_bit_rate_value_minus1,
            { "bit_rate_value_minus1",           "h264.bit_rate_value_minus1",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_cpb_size_value_minus1,
            { "cpb_size_value_minus1",           "h264.cpb_size_value_minus1",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_cbr_flag,
            { "cbr_flag",           "h264.cbr_flag",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_initial_cpb_removal_delay_length_minus1,
            { "initial_cpb_removal_delay_length_minus1",           "h264.initial_cpb_removal_delay_length_minus1",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_cpb_removal_delay_length_minus1,
            { "cpb_removal_delay_length_minus1",           "h264.cpb_removal_delay_length_minus1",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_dpb_output_delay_length_minus11,
            { "dpb_output_delay_length_minus11",           "h264.dpb_output_delay_length_minus11",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_time_offset_length,
            { "time_offset_length",           "h264.time_offset_length",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_first_mb_in_slice,
            { "first_mb_in_slice",           "h264.first_mb_in_slice",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_slice_type,
            { "slice_type",           "h264.slice_type",
            FT_UINT32, BASE_DEC, VALS(h264_slice_type_vals), 0x0,
            NULL, HFILL }
        },
        { &hf_h264_slice_id,
            { "slice_id",           "h264.slice_id",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_payloadsize,
            { "PayloadSize",           "h264.payloadsize",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_payloadtype,
            { "payloadType",           "h264.payloadtype",
            FT_UINT32, BASE_DEC, VALS(h264_sei_payload_vals), 0x0,
            NULL, HFILL }
        },
#if 0
        { &hf_h264_frame_num,
            { "frame_num",           "h264.frame_num",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
#endif
        { &hf_h264_par_profile,
                { "Profile", "h264.par_profile",
                FT_UINT8, BASE_HEX, NULL, 0x00,
            NULL, HFILL}},
        { &hf_h264_par_profile_b,
                { "Baseline Profile", "h264.par_profile.base",
            FT_BOOLEAN, 8, NULL, 0x40,
            NULL, HFILL}},
        { &hf_h264_par_profile_m,
                { "Main Profile", "h264.par_profile.main",
            FT_BOOLEAN, 8, NULL, 0x20,
            NULL, HFILL}},
        { &hf_h264_par_profile_e,
                { "Extended Profile.", "h264.par_profile.ext",
            FT_BOOLEAN, 8, NULL, 0x10,
            NULL, HFILL}},
        { &hf_h264_par_profile_h,
                { "High Profile", "h264.par_profile.high",
            FT_BOOLEAN, 8, NULL, 0x08,
            NULL, HFILL}},
        { &hf_h264_par_profile_h10,
                { "High 10 Profile", "h264.par_profile.high10",
            FT_BOOLEAN, 8, NULL, 0x04,
            NULL, HFILL}},
        { &hf_h264_par_profile_h4_2_2,
                { "High 4:2:2 Profile", "h264.par_profile.high4_2_2",
            FT_BOOLEAN, 8, NULL, 0x02,
            NULL, HFILL}},
        { &hf_h264_par_profile_h4_4_4,
                { "High 4:4:4 Profile", "h264.par_profile.high4_4_4",
            FT_BOOLEAN, 8, NULL, 0x01,
            NULL, HFILL}},
        { &hf_h264_par_AdditionalModesSupported,
                { "AdditionalModesSupported", "h264.AdditionalModesSupported",
            FT_UINT8, BASE_HEX, NULL, 0x00,
            NULL, HFILL}},
#if 0
        { &hf_h264_par_add_mode_sup,
                { "Additional Modes Supported", "h264.add_mode_sup",
            FT_UINT8, BASE_HEX, NULL, 0x00,
            NULL, HFILL}},
#endif
        { &hf_h264_par_add_mode_sup_rcdo,
                { "Reduced Complexity Decoding Operation (RCDO) support", "h264.add_mode_sup.rcdo",
            FT_BOOLEAN, 8, NULL, 0x40,
            NULL, HFILL}},
        { &hf_h264_par_ProfileIOP,
                { "ProfileIOP", "h264.ProfileIOP",
            FT_UINT8, BASE_HEX, NULL, 0x00,
            NULL, HFILL}},
        { &hf_h264_par_constraint_set0_flag,
                { "constraint_set0_flag", "h264.par.constraint_set0_flag",
            FT_BOOLEAN, 8, NULL, 0x80,
            NULL, HFILL}},
        { &hf_h264_par_constraint_set1_flag,
                { "constraint_set1_flag", "h264.par.constraint_set1_flag",
            FT_BOOLEAN, 8, NULL, 0x40,
            NULL, HFILL}},
        { &hf_h264_par_constraint_set2_flag,
                { "constraint_set2_flag", "h264.par.constraint_set2_flag",
            FT_BOOLEAN, 8, NULL, 0x20,
            NULL, HFILL}},
        /* Packization Values */
        { &hf_h264_nalu_size,
            { "NAL Unit Size", "h264.nalu_size",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_don,
            { "Decoder Order Number", "h264.don",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_dond,
            { "MTAP Decoder Order Number Delta", "h264.don_delta",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_ts_offset16,
            { "MTAP TS Offset", "h264.ts_offset16",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_ts_offset24,
            { "MTAP TS Offset", "h264.ts_offset24",
            FT_UINT24, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_nal_extension_subtype,
            { "Extension Header Subtype", "h264.nal_hdr_extension.subtype",
            FT_UINT8, BASE_DEC, VALS(h264_subtype_values), 0xF8,
            NULL, HFILL }
        },
        { &hf_h264_nal_extension_j,
            { "Extension Header J - DON Present Indicator", "h264.nal_hdr_extension.j",
            FT_BOOLEAN, 8, NULL, 0x4,
            NULL, HFILL }
        },
        { &hf_h264_nal_extension_k,
            { "Extension Header K", "h264.nal_hdr_extension.k",
            FT_BOOLEAN, 8, NULL, 0x2,
            NULL, HFILL }
        },
        { &hf_h264_nal_extension_l,
            { "Extension Header L", "h264.nal_hdr_extension.l",
            FT_BOOLEAN, 8, NULL, 0x1,
            NULL, HFILL }
        },

        /* SEI Parsing values */
        { &hf_h264_sei_uuid,
            { "UUID", "h264.sei.uuid",
            FT_GUID, BASE_NONE, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_lpb,
            { "Layer Presence", "h264.sei.ms.layout.lpb",
            FT_UINT8, BASE_HEX, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_layout_p,
            { "Layer Description Present", "h264.sei.ms.layout.p",
            FT_BOOLEAN, 8, NULL, 0x01,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_layout_ldsize,
            { "Layer Description Size", "h264.sei.ms.layout.desc.ldsize",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_layer_desc_coded_width,
            { "Coded Width", "h264.sei.ms.layout.desc.coded_width",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_layer_desc_coded_height,
            { "Coded Height", "h264.sei.ms.layout.desc.coded_height",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_layer_desc_display_width,
            { "Display Width", "h264.sei.ms.layout.desc.display_width",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_layer_desc_display_height,
            { "Display Height", "h264.sei.ms.layout.desc.display_height",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_layer_desc_bitrate,
            { "Bitrate", "h264.sei.ms.layout.desc.bitrate",
            FT_UINT32, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_layer_desc_frame_rate,
            { "Frame Rate Index", "h264.sei.ms.layout.desc.frame_rate",
            FT_UINT8, BASE_DEC, VALS(h264_sei_ms_frame_values), 0xF8,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_layer_desc_layer_type,
            { "Layer Type", "h264.sei.ms.layout.desc.layer_type",
            FT_UINT8, BASE_DEC, NULL, 0x07,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_layer_desc_prid,
            { "Priority ID", "h264.sei.ms.layout.desc.prid",
            FT_UINT8, BASE_DEC, NULL, 0xFC,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_layer_desc_cb,
            { "Constrained Baseline", "h264.sei.ms.layout.desc.constrained_baseline",
            FT_BOOLEAN, 8, NULL, 0x02,
            NULL, HFILL }
        },
        /* MS Bitstream SEI */
        { &hf_h264_sei_ms_bitstream_ref_frame_cnt,
            { "Reference Frame Count", "h264.sei.ms.bitstream_info.ref_frm_cnt",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_bitstream_num_nalus,
            { "Number of NAL units", "h264.sei.ms.bitstrea3416m_info.num_nalus",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_iso_sec_info,
            { "Unparsed iso_iec information", "h264.sei.iso_sec_info",
            FT_BYTES, BASE_NONE, NULL, 0x0,
            NULL, HFILL }
        },
        /* MS Crop SEI */
        { &hf_h264_sei_ms_crop_num_data,
            { "Number of Data Entries", "h264.sei.ms.crop.num_data",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_crop_info_type,
            { "Info Type", "h264.sei.ms.crop.info_type",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_crop_confidence_level,
            { "Confidence Level", "h264.sei.ms.crop.confidence_level",
            FT_UINT8, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_crop_frame_left_offset,
            { "Left Offset", "h264.sei.ms.crop.left_offset",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_crop_frame_right_offset,
            { "Right Offset", "h264.sei.ms.crop.right_offset",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_crop_frame_top_offset,
            { "Top Offset", "h264.sei.ms.crop.top_offset",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_sei_ms_crop_frame_bottom_offset,
            { "Bottom Offset", "h264.sei.ms.crop.bottom_offset",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        /* NALU Header Extension */
        /* Annex G NAL Unit Header SVC Extension */
        { &hf_h264_nal_hdr_ext_svc,
            { "SVC Extension / Reserved", "h264.nal_hdr_ext.r",
            FT_BOOLEAN, 8, NULL, 0x80,
            NULL, HFILL }
        },
        { &hf_h264_nal_hdr_ext_i,
            { "IDR Picture", "h264.nal_hdr_ext.i",
            FT_BOOLEAN, 8, NULL, 0x40,
            NULL, HFILL }
        },
        { &hf_h264_nal_hdr_ext_prid,
            { "Priority ID", "h264.nal_hdr_ext.prid",
            FT_UINT8, BASE_DEC, NULL, 0x3f,
            NULL, HFILL }
        },
        { &hf_h264_nal_hdr_ext_n,
            { "No Inter Layer Prediction", "h264.nal_hdr_ext.n",
            FT_BOOLEAN, 8, NULL, 0x80,
            NULL, HFILL }
        },
        { &hf_h264_nal_hdr_ext_did,
            { "Dependency ID", "h264.nal_hdr_ext.did",
            FT_UINT8, BASE_DEC, NULL, 0x70,
            NULL, HFILL }
        },
        { &hf_h264_nal_hdr_ext_qid,
            { "Quality ID", "h264.nal_hdr_ext.qid",
            FT_UINT8, BASE_DEC, NULL, 0x0f,
            NULL, HFILL }
        },
        { &hf_h264_nal_hdr_ext_tid,
            { "Temporal ID", "h264.nal_hdr_ext.tid",
            FT_UINT8, BASE_DEC, NULL, 0xe0,
            NULL, HFILL }
        },
        { &hf_h264_nal_hdr_ext_u,
            { "Use Ref Base Picture", "h264.nal_hdr_ext.u",
            FT_BOOLEAN, 8, NULL, 0x10,
            NULL, HFILL }
        },
        { &hf_h264_nal_hdr_ext_d,
            { "Discardable", "h264.nal_hdr_ext.d",
            FT_BOOLEAN, 8, NULL, 0x08,
            NULL, HFILL }
        },
        { &hf_h264_nal_hdr_ext_o,
            { "Output", "h264.nal_hdr_ext.o",
            FT_BOOLEAN, 8, NULL, 0x04,
            NULL, HFILL }
        },
        { &hf_h264_nal_hdr_ext_rr,
            { "Reserved", "h264.nal_hdr_ext.rr",
            FT_UINT8, BASE_HEX, NULL, 0x03,
            NULL, HFILL }
        },
        /* PACSI Values */
        { &hf_h264_pacsi_x,
            { "X - A,P,C Field Indicator", "h264.pacsi.x",
            FT_BOOLEAN, 8, NULL, 0x80,
            NULL, HFILL }
        },
        { &hf_h264_pacsi_y,
            { "Y - Pic Fields Indicator", "h264.pacsi.y",
            FT_BOOLEAN, 8, NULL, 0x40,
            NULL, HFILL }
        },
        { &hf_h264_pacsi_t,
            { "T - DONC Field Indicator", "h264.pacsi.t",
            FT_BOOLEAN, 8, NULL, 0x20,
            NULL, HFILL }
        },
        { &hf_h264_pacsi_a,
            { "A - Anchor Layer", "h264.pacsi.a",
            FT_BOOLEAN, 8, NULL, 0x10,
            NULL, HFILL }
        },
        { &hf_h264_pacsi_p,
            { "P - Redundant Slice", "h264.pacsi.p",
            FT_BOOLEAN, 8, NULL, 0x08,
            NULL, HFILL }
        },
        { &hf_h264_pacsi_c,
            { "C - Intra Slice", "h264.pacsi.c",
            FT_BOOLEAN, 8, NULL, 0x04,
            NULL, HFILL }
        },
        { &hf_h264_pacsi_s,
            { "S - First Nal Unit of Layer", "h264.pacsi.s",
            FT_BOOLEAN, 8, NULL, 0x02,
            NULL, HFILL }
        },
        { &hf_h264_pacsi_e,
            { "E - Last Nal Unit of Layer", "h264.pacsi.e",
            FT_BOOLEAN, 8, NULL, 0x01,
            NULL, HFILL }
        },
        { &hf_h264_pacsi_tl0picidx,
            { "TL0PICIDX", "h264.pacsi.tl0picidx",
            FT_UINT8, BASE_DEC, NULL, 0xff,
            NULL, HFILL }
        },
        { &hf_h264_pacsi_idrpicid,
            { "IDRPICID - IDR Picture ID", "h264.pacsi.idrpicid",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },
        { &hf_h264_pacsi_donc,
            { "DONC - Cross Session Decoder Order Number", "h264.pacsi.donc",
            FT_UINT16, BASE_DEC, NULL, 0x0,
            NULL, HFILL }
        },

    };

/* Setup protocol subtree array */
    static gint *ett[] = {
        &ett_h264,
        &ett_h264_profile,
        &ett_h264_nal,
        &ett_h264_fua,
        &ett_h264_stream,
        &ett_h264_nal_unit,
        &ett_h264_par_profile,
        &ett_h264_par_AdditionalModesSupported,
        &ett_h264_par_ProfileIOP,
        &ett_h264_ms_layer_description,
        &ett_h264_ms_crop_data,
        &ett_h264_ni_mtap
    };

    static ei_register_info ei[] = {
        { &ei_h264_undecoded, { "h264.undecoded", PI_UNDECODED, PI_WARN, "[Not decoded yet]", EXPFILL }},
        { &ei_h264_ms_layout_wrong_length, { "h264.ms_layout.wrong_length", PI_PROTOCOL, PI_WARN, "[Wrong Layer Description Table Length]", EXPFILL }},
        { &ei_h264_oversized_exp_golomb_code, {"h264.oversized_exp_golomb_code", PI_MALFORMED, PI_ERROR, "Exponential Golomb encoded value greater than 32 bit integer, clamped", EXPFILL }},
        { &ei_h264_bad_nal_length, { "h264.bad_nalu_length", PI_MALFORMED, PI_ERROR, "[Bad NAL Unit Length]", EXPFILL }},
        { &ei_h264_nal_unit_type_reserved, { "h264.nal_unit_type.reserved", PI_PROTOCOL, PI_WARN, "Reserved NAL unit type", EXPFILL }},
        { &ei_h264_nal_unit_type_unspecified, { "h264.nal_unit_type.unspecified", PI_PROTOCOL, PI_WARN, "Unspecified NAL unit type", EXPFILL }},
    };

/* Register the protocol name and description */
    proto_h264 = proto_register_protocol("H.264", "H.264", "h264");

/* Required function calls to register the header fields and subtrees used */
    proto_register_field_array(proto_h264, hf, array_length(hf));
    proto_register_subtree_array(ett, array_length(ett));
    expert_h264 = expert_register_protocol(proto_h264);
    expert_register_field_array(expert_h264, ei, array_length(ei));
    /* Register a configuration option for port */


    h264_module = prefs_register_protocol(proto_h264, NULL);

    prefs_register_obsolete_preference(h264_module, "dynamic.payload.type");

    h264_handle = register_dissector("h264", dissect_h264, proto_h264);
    register_dissector_with_description("h264_bytestream", "H.264 Annex B Byte stream format", dissect_h264_bytestream, proto_h264);
}


/* Register the protocol with Wireshark */
void
proto_reg_handoff_h264(void)
{
    h264_capability_t *ftr;

    dissector_add_string("rtp_dyn_payload_type","H264", h264_handle);
    dissector_add_string("rtp_dyn_payload_type","H264-SVC", h264_handle);
    dissector_add_string("rtp_dyn_payload_type","X-H264UC", h264_handle);

    h264_name_handle = create_dissector_handle(dissect_h264_name, proto_h264);
    for (ftr=h264_capability_tab; ftr->id; ftr++) {
        if (ftr->name)
            dissector_add_string("h245.gef.name", ftr->id, h264_name_handle);
        if (ftr->content_pdu)
            dissector_add_string("h245.gef.content", ftr->id, create_dissector_handle(ftr->content_pdu, proto_h264));
    }

    dissector_add_uint_range_with_preference("rtp.pt", "", h264_handle);

}

/*
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
 *
 * Local variables:
 * c-basic-offset: 4
 * tab-width: 8
 * indent-tabs-mode: nil
 * End:
 *
 * vi: set shiftwidth=4 tabstop=8 expandtab:
 * :indentSize=4:tabSize=8:noTabs=true:
 */
