void H264VideoStreamParser
::analyze_seq_parameter_set_data(unsigned& num_units_in_tick, unsigned& time_scale, unsigned& fixed_frame_rate_flag) {
  num_units_in_tick = time_scale = fixed_frame_rate_flag = 0; // default values

  // Begin by making a copy of the NAL unit data, removing any 'emulation prevention' bytes:
  u_int8_t sps[SPS_MAX_SIZE];
  unsigned spsSize;
  removeEmulationBytes(sps, sizeof sps, spsSize);

  BitVector bv(sps, 0, 8*spsSize);

  bv.skipBits(8); // forbidden_zero_bit; nal_ref_idc; nal_unit_type
  unsigned profile_idc = bv.getBits(8);
  DEBUG_PRINT(profile_idc);
  unsigned constraint_setN_flag = bv.getBits(8); // also "reserved_zero_2bits" at end
  DEBUG_PRINT(constraint_setN_flag);
  unsigned level_idc = bv.getBits(8);
  DEBUG_PRINT(level_idc);
  unsigned seq_parameter_set_id = bv.get_expGolomb();
  DEBUG_PRINT(seq_parameter_set_id);
  if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || profile_idc == 86 || profile_idc == 118 || profile_idc == 128 ) {
    DEBUG_TAB;
    unsigned chroma_format_idc = bv.get_expGolomb();
    DEBUG_PRINT(chroma_format_idc);
    if (chroma_format_idc == 3) {
      DEBUG_TAB;
      separate_colour_plane_flag = bv.get1BitBoolean();
      DEBUG_PRINT(separate_colour_plane_flag);
    }
    (void)bv.get_expGolomb(); // bit_depth_luma_minus8
    (void)bv.get_expGolomb(); // bit_depth_chroma_minus8
    bv.skipBits(1); // qpprime_y_zero_transform_bypass_flag
    unsigned seq_scaling_matrix_present_flag = bv.get1Bit();
    DEBUG_PRINT(seq_scaling_matrix_present_flag);
    if (seq_scaling_matrix_present_flag) {
      for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); ++i) {
	DEBUG_TAB;
	DEBUG_PRINT(i);
	unsigned seq_scaling_list_present_flag = bv.get1Bit();
	DEBUG_PRINT(seq_scaling_list_present_flag);
	if (seq_scaling_list_present_flag) {
	  DEBUG_TAB;
	  unsigned sizeOfScalingList = i < 6 ? 16 : 64;
	  unsigned lastScale = 8;
	  unsigned nextScale = 8;
	  for (unsigned j = 0; j < sizeOfScalingList; ++j) {
	    DEBUG_TAB;
	    DEBUG_PRINT(j);
	    DEBUG_PRINT(nextScale);
	    if (nextScale != 0) {
	      DEBUG_TAB;
	      unsigned delta_scale = bv.get_expGolomb();
	      DEBUG_PRINT(delta_scale);
	      nextScale = (lastScale + delta_scale + 256) % 256;
	    }
	    lastScale = (nextScale == 0) ? lastScale : nextScale;
	    DEBUG_PRINT(lastScale);
	  }
	}
      }
    }
  }
  unsigned log2_max_frame_num_minus4 = bv.get_expGolomb();
  DEBUG_PRINT(log2_max_frame_num_minus4);
  log2_max_frame_num = log2_max_frame_num_minus4 + 4;
  unsigned pic_order_cnt_type = bv.get_expGolomb();
  DEBUG_PRINT(pic_order_cnt_type);
  if (pic_order_cnt_type == 0) {
    DEBUG_TAB;
    unsigned log2_max_pic_order_cnt_lsb_minus4 = bv.get_expGolomb();
    DEBUG_PRINT(log2_max_pic_order_cnt_lsb_minus4);
  } else if (pic_order_cnt_type == 1) {
    DEBUG_TAB;
    bv.skipBits(1); // delta_pic_order_always_zero_flag
    (void)bv.get_expGolomb(); // offset_for_non_ref_pic
    (void)bv.get_expGolomb(); // offset_for_top_to_bottom_field
    unsigned num_ref_frames_in_pic_order_cnt_cycle = bv.get_expGolomb();
    DEBUG_PRINT(num_ref_frames_in_pic_order_cnt_cycle);
    for (unsigned i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) {
      (void)bv.get_expGolomb(); // offset_for_ref_frame[i]
    }
  }
  unsigned max_num_ref_frames = bv.get_expGolomb();
  DEBUG_PRINT(max_num_ref_frames);
  unsigned gaps_in_frame_num_value_allowed_flag = bv.get1Bit();
  DEBUG_PRINT(gaps_in_frame_num_value_allowed_flag);
  unsigned pic_width_in_mbs_minus1 = bv.get_expGolomb();
  DEBUG_PRINT(pic_width_in_mbs_minus1);
  unsigned pic_height_in_map_units_minus1 = bv.get_expGolomb();
  DEBUG_PRINT(pic_height_in_map_units_minus1);
  frame_mbs_only_flag = bv.get1BitBoolean();
  DEBUG_PRINT(frame_mbs_only_flag);
  if (!frame_mbs_only_flag) {
    bv.skipBits(1); // mb_adaptive_frame_field_flag
  }
  bv.skipBits(1); // direct_8x8_inference_flag
  unsigned frame_cropping_flag = bv.get1Bit();
  DEBUG_PRINT(frame_cropping_flag);
  if (frame_cropping_flag) {
    (void)bv.get_expGolomb(); // frame_crop_left_offset
    (void)bv.get_expGolomb(); // frame_crop_right_offset
    (void)bv.get_expGolomb(); // frame_crop_top_offset
    (void)bv.get_expGolomb(); // frame_crop_bottom_offset
  }
  unsigned vui_parameters_present_flag = bv.get1Bit();
  DEBUG_PRINT(vui_parameters_present_flag);
  if (vui_parameters_present_flag) {
    DEBUG_TAB;
    analyze_vui_parameters(bv,num_units_in_tick, time_scale, fixed_frame_rate_flag);
  }
}
void H264or5VideoStreamParser
::analyze_seq_parameter_set_data(unsigned& num_units_in_tick, unsigned& time_scale) {
  num_units_in_tick = time_scale = 0; // default values

  // Begin by making a copy of the NAL unit data, removing any 'emulation prevention' bytes:
  u_int8_t sps[SPS_MAX_SIZE];
  unsigned spsSize;
  removeEmulationBytes(sps, sizeof sps, spsSize);

  BitVector bv(sps, 0, 8*spsSize);

  if (fHNumber == 264) {
    bv.skipBits(8); // forbidden_zero_bit; nal_ref_idc; nal_unit_type
    unsigned profile_idc = bv.getBits(8);
    DEBUG_PRINT(profile_idc);
    unsigned constraint_setN_flag = bv.getBits(8); // also "reserved_zero_2bits" at end
    DEBUG_PRINT(constraint_setN_flag);
    unsigned level_idc = bv.getBits(8);
    DEBUG_PRINT(level_idc);
    unsigned seq_parameter_set_id = bv.get_expGolomb();
    DEBUG_PRINT(seq_parameter_set_id);
    if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || profile_idc == 86 || profile_idc == 118 || profile_idc == 128 ) {
      DEBUG_TAB;
      unsigned chroma_format_idc = bv.get_expGolomb();
      DEBUG_PRINT(chroma_format_idc);
      if (chroma_format_idc == 3) {
	DEBUG_TAB;
	Boolean separate_colour_plane_flag = bv.get1BitBoolean();
	DEBUG_PRINT(separate_colour_plane_flag);
      }
      (void)bv.get_expGolomb(); // bit_depth_luma_minus8
      (void)bv.get_expGolomb(); // bit_depth_chroma_minus8
      bv.skipBits(1); // qpprime_y_zero_transform_bypass_flag
      Boolean seq_scaling_matrix_present_flag = bv.get1BitBoolean();
      DEBUG_PRINT(seq_scaling_matrix_present_flag);
      if (seq_scaling_matrix_present_flag) {
	for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); ++i) {
	  DEBUG_TAB;
	  DEBUG_PRINT(i);
	  Boolean seq_scaling_list_present_flag = bv.get1BitBoolean();
	  DEBUG_PRINT(seq_scaling_list_present_flag);
	  if (seq_scaling_list_present_flag) {
	    DEBUG_TAB;
	    unsigned sizeOfScalingList = i < 6 ? 16 : 64;
	    unsigned lastScale = 8;
	    unsigned nextScale = 8;
	    for (unsigned j = 0; j < sizeOfScalingList; ++j) {
	      DEBUG_TAB;
	      DEBUG_PRINT(j);
	      DEBUG_PRINT(nextScale);
	      if (nextScale != 0) {
		DEBUG_TAB;
		unsigned delta_scale = bv.get_expGolomb();
		DEBUG_PRINT(delta_scale);
		nextScale = (lastScale + delta_scale + 256) % 256;
	      }
	      lastScale = (nextScale == 0) ? lastScale : nextScale;
	      DEBUG_PRINT(lastScale);
	    }
	  }
	}
      }
    }
    unsigned log2_max_frame_num_minus4 = bv.get_expGolomb();
    DEBUG_PRINT(log2_max_frame_num_minus4);
    unsigned pic_order_cnt_type = bv.get_expGolomb();
    DEBUG_PRINT(pic_order_cnt_type);
    if (pic_order_cnt_type == 0) {
      DEBUG_TAB;
      unsigned log2_max_pic_order_cnt_lsb_minus4 = bv.get_expGolomb();
      DEBUG_PRINT(log2_max_pic_order_cnt_lsb_minus4);
    } else if (pic_order_cnt_type == 1) {
      DEBUG_TAB;
      bv.skipBits(1); // delta_pic_order_always_zero_flag
      (void)bv.get_expGolomb(); // offset_for_non_ref_pic
      (void)bv.get_expGolomb(); // offset_for_top_to_bottom_field
      unsigned num_ref_frames_in_pic_order_cnt_cycle = bv.get_expGolomb();
      DEBUG_PRINT(num_ref_frames_in_pic_order_cnt_cycle);
      for (unsigned i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) {
	(void)bv.get_expGolomb(); // offset_for_ref_frame[i]
      }
    }
    unsigned max_num_ref_frames = bv.get_expGolomb();
    DEBUG_PRINT(max_num_ref_frames);
    Boolean gaps_in_frame_num_value_allowed_flag = bv.get1BitBoolean();
    DEBUG_PRINT(gaps_in_frame_num_value_allowed_flag);
    unsigned pic_width_in_mbs_minus1 = bv.get_expGolomb();
    DEBUG_PRINT(pic_width_in_mbs_minus1);
    unsigned pic_height_in_map_units_minus1 = bv.get_expGolomb();
    DEBUG_PRINT(pic_height_in_map_units_minus1);
    Boolean frame_mbs_only_flag = bv.get1BitBoolean();
    DEBUG_PRINT(frame_mbs_only_flag);
    if (!frame_mbs_only_flag) {
      bv.skipBits(1); // mb_adaptive_frame_field_flag
    }
    bv.skipBits(1); // direct_8x8_inference_flag
    Boolean frame_cropping_flag = bv.get1BitBoolean();
    DEBUG_PRINT(frame_cropping_flag);
    if (frame_cropping_flag) {
      (void)bv.get_expGolomb(); // frame_crop_left_offset
      (void)bv.get_expGolomb(); // frame_crop_right_offset
      (void)bv.get_expGolomb(); // frame_crop_top_offset
      (void)bv.get_expGolomb(); // frame_crop_bottom_offset
    }
    Boolean vui_parameters_present_flag = bv.get1BitBoolean();
    DEBUG_PRINT(vui_parameters_present_flag);
    if (vui_parameters_present_flag) {
      DEBUG_TAB;
      analyze_vui_parameters(bv, num_units_in_tick, time_scale);
    }
  } else { // 265
    unsigned i;

    bv.skipBits(16); // nal_unit_header
    bv.skipBits(4); // sps_video_parameter_set_id
    unsigned sps_max_sub_layers_minus1 = bv.getBits(3);
    DEBUG_PRINT(sps_max_sub_layers_minus1);
    bv.skipBits(1); // sps_temporal_id_nesting_flag
    profile_tier_level(bv, sps_max_sub_layers_minus1);
    (void)bv.get_expGolomb(); // sps_seq_parameter_set_id
    unsigned chroma_format_idc = bv.get_expGolomb();
    DEBUG_PRINT(chroma_format_idc);
    if (chroma_format_idc == 3) bv.skipBits(1); // separate_colour_plane_flag
    unsigned pic_width_in_luma_samples = bv.get_expGolomb();
    DEBUG_PRINT(pic_width_in_luma_samples);
    unsigned pic_height_in_luma_samples = bv.get_expGolomb();
    DEBUG_PRINT(pic_height_in_luma_samples);
    Boolean conformance_window_flag = bv.get1BitBoolean();
    DEBUG_PRINT(conformance_window_flag);
    if (conformance_window_flag) {
      DEBUG_TAB;
      unsigned conf_win_left_offset = bv.get_expGolomb();
      DEBUG_PRINT(conf_win_left_offset);
      unsigned conf_win_right_offset = bv.get_expGolomb();
      DEBUG_PRINT(conf_win_right_offset);
      unsigned conf_win_top_offset = bv.get_expGolomb();
      DEBUG_PRINT(conf_win_top_offset);
      unsigned conf_win_bottom_offset = bv.get_expGolomb();
      DEBUG_PRINT(conf_win_bottom_offset);
    }
    (void)bv.get_expGolomb(); // bit_depth_luma_minus8
    (void)bv.get_expGolomb(); // bit_depth_chroma_minus8
    unsigned log2_max_pic_order_cnt_lsb_minus4 = bv.get_expGolomb();
    Boolean sps_sub_layer_ordering_info_present_flag = bv.get1BitBoolean();
    DEBUG_PRINT(sps_sub_layer_ordering_info_present_flag);
    for (i = (sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1);
	 i <= sps_max_sub_layers_minus1; ++i) {
      (void)bv.get_expGolomb(); // sps_max_dec_pic_buffering_minus1[i]
      (void)bv.get_expGolomb(); // sps_max_num_reorder_pics[i]
      (void)bv.get_expGolomb(); // sps_max_latency_increase[i]
    }
    (void)bv.get_expGolomb(); // log2_min_luma_coding_block_size_minus3
    (void)bv.get_expGolomb(); // log2_diff_max_min_luma_coding_block_size
    (void)bv.get_expGolomb(); // log2_min_transform_block_size_minus2
    (void)bv.get_expGolomb(); // log2_diff_max_min_transform_block_size
    (void)bv.get_expGolomb(); // max_transform_hierarchy_depth_inter
    (void)bv.get_expGolomb(); // max_transform_hierarchy_depth_intra
    Boolean scaling_list_enabled_flag = bv.get1BitBoolean();
    DEBUG_PRINT(scaling_list_enabled_flag);
    if (scaling_list_enabled_flag) {
      DEBUG_TAB;
      Boolean sps_scaling_list_data_present_flag = bv.get1BitBoolean();
      DEBUG_PRINT(sps_scaling_list_data_present_flag);
      if (sps_scaling_list_data_present_flag) {
	// scaling_list_data()
	DEBUG_TAB;
	for (unsigned sizeId = 0; sizeId < 4; ++sizeId) {
	  DEBUG_PRINT(sizeId);
	  for (unsigned matrixId = 0; matrixId < (sizeId == 3 ? 2 : 6); ++matrixId) {
	    DEBUG_TAB;
	    DEBUG_PRINT(matrixId);
	    Boolean scaling_list_pred_mode_flag = bv.get1BitBoolean();
	    DEBUG_PRINT(scaling_list_pred_mode_flag);
	    if (!scaling_list_pred_mode_flag) {
	      (void)bv.get_expGolomb(); // scaling_list_pred_matrix_id_delta[sizeId][matrixId]
	    } else {
	      unsigned const c = 1 << (4+(sizeId<<1));
	      unsigned coefNum = c < 64 ? c : 64;
	      if (sizeId > 1) {
		(void)bv.get_expGolomb(); // scaling_list_dc_coef_minus8[sizeId][matrixId]
	      }
	      for (i = 0; i < coefNum; ++i) {
		(void)bv.get_expGolomb(); // scaling_list_delta_coef
	      }
	    }
	  } 
	}
      }
    }
    bv.skipBits(2); // amp_enabled_flag, sample_adaptive_offset_enabled_flag
    Boolean pcm_enabled_flag = bv.get1BitBoolean();
    DEBUG_PRINT(pcm_enabled_flag);
    if (pcm_enabled_flag) {
      bv.skipBits(8); // pcm_sample_bit_depth_luma_minus1, pcm_sample_bit_depth_chroma_minus1
      (void)bv.get_expGolomb(); // log2_min_pcm_luma_coding_block_size_minus3
      (void)bv.get_expGolomb(); // log2_diff_max_min_pcm_luma_coding_block_size
      bv.skipBits(1); // pcm_loop_filter_disabled_flag
    }
    unsigned num_short_term_ref_pic_sets = bv.get_expGolomb();
    DEBUG_PRINT(num_short_term_ref_pic_sets);
    unsigned num_negative_pics = 0, prev_num_negative_pics = 0;
    unsigned num_positive_pics = 0, prev_num_positive_pics = 0;
    for (i = 0; i < num_short_term_ref_pic_sets; ++i) {
      // short_term_ref_pic_set(i):
      DEBUG_TAB;
      DEBUG_PRINT(i);
      Boolean inter_ref_pic_set_prediction_flag = False;
      if (i != 0) {
	inter_ref_pic_set_prediction_flag = bv.get1BitBoolean();
      }
      DEBUG_PRINT(inter_ref_pic_set_prediction_flag);
      if (inter_ref_pic_set_prediction_flag) {
	DEBUG_TAB;
	if (i == num_short_term_ref_pic_sets) {
	  // This can't happen here, but it's in the spec, so we include it for completeness
	  (void)bv.get_expGolomb(); // delta_idx_minus1
	}
	bv.skipBits(1); // delta_rps_sign
	(void)bv.get_expGolomb(); // abs_delta_rps_minus1
	unsigned NumDeltaPocs = prev_num_negative_pics + prev_num_positive_pics; // correct???
	for (unsigned j = 0; j < NumDeltaPocs; ++j) {
	  DEBUG_PRINT(j);
	  Boolean used_by_curr_pic_flag = bv.get1BitBoolean();
	  DEBUG_PRINT(used_by_curr_pic_flag);
	  if (!used_by_curr_pic_flag) bv.skipBits(1); // use_delta_flag[j]
	}
      } else {
	prev_num_negative_pics = num_negative_pics;
	num_negative_pics = bv.get_expGolomb();
	DEBUG_PRINT(num_negative_pics);
	prev_num_positive_pics = num_positive_pics;
	num_positive_pics = bv.get_expGolomb();
	DEBUG_PRINT(num_positive_pics);
	unsigned k;
	for (k = 0; k < num_negative_pics; ++k) {
	  (void)bv.get_expGolomb(); // delta_poc_s0_minus1[k]
	  bv.skipBits(1); // used_by_curr_pic_s0_flag[k]
	}
	for (k = 0; k < num_positive_pics; ++k) {
	  (void)bv.get_expGolomb(); // delta_poc_s1_minus1[k]
	  bv.skipBits(1); // used_by_curr_pic_s1_flag[k]
	}
      }
    }
    Boolean long_term_ref_pics_present_flag = bv.get1BitBoolean();
    DEBUG_PRINT(long_term_ref_pics_present_flag);
    if (long_term_ref_pics_present_flag) {
      DEBUG_TAB;
      unsigned num_long_term_ref_pics_sps = bv.get_expGolomb();
      DEBUG_PRINT(num_long_term_ref_pics_sps);
      for (i = 0; i < num_long_term_ref_pics_sps; ++i) {
	bv.skipBits(log2_max_pic_order_cnt_lsb_minus4); // lt_ref_pic_poc_lsb_sps[i]
	bv.skipBits(1); // used_by_curr_pic_lt_sps_flag[1]
      }
    }
    bv.skipBits(2); // sps_temporal_mvp_enabled_flag, strong_intra_smoothing_enabled_flag
    Boolean vui_parameters_present_flag = bv.get1BitBoolean();
    DEBUG_PRINT(vui_parameters_present_flag);
    if (vui_parameters_present_flag) {
      DEBUG_TAB;
      analyze_vui_parameters(bv, num_units_in_tick, time_scale);
    }
    Boolean sps_extension_flag = bv.get1BitBoolean();
    DEBUG_PRINT(sps_extension_flag);
  }
}