de265_error seq_parameter_set::compute_derived_values(bool sanitize_values)
{
  // --- compute derived values ---

  SubWidthC  = SubWidthC_tab [chroma_format_idc];
  SubHeightC = SubHeightC_tab[chroma_format_idc];

  if (separate_colour_plane_flag) {
    ChromaArrayType = 0;
  }
  else {
    ChromaArrayType = chroma_format_idc;
  }

  if (ChromaArrayType==0) {
    WinUnitX = 1;
    WinUnitY = 1;
  }
  else {
    WinUnitX = SubWidthC_tab [chroma_format_idc];
    WinUnitY = SubHeightC_tab[chroma_format_idc];
  }



  BitDepth_Y   = bit_depth_luma;
  QpBdOffset_Y = 6*(bit_depth_luma-8);
  BitDepth_C   = bit_depth_chroma;
  QpBdOffset_C = 6*(bit_depth_chroma-8);

  Log2MinCbSizeY = log2_min_luma_coding_block_size;
  Log2CtbSizeY = Log2MinCbSizeY + log2_diff_max_min_luma_coding_block_size;
  MinCbSizeY = 1 << Log2MinCbSizeY;
  CtbSizeY = 1 << Log2CtbSizeY;

  PicWidthInMinCbsY = ceil_div(pic_width_in_luma_samples, MinCbSizeY);
  PicWidthInCtbsY   = ceil_div(pic_width_in_luma_samples, CtbSizeY);
  PicHeightInMinCbsY = ceil_div(pic_height_in_luma_samples, MinCbSizeY);
  PicHeightInCtbsY   = ceil_div(pic_height_in_luma_samples,CtbSizeY);
  PicSizeInMinCbsY   = PicWidthInMinCbsY * PicHeightInMinCbsY;
  PicSizeInCtbsY = PicWidthInCtbsY * PicHeightInCtbsY;
  PicSizeInSamplesY = pic_width_in_luma_samples * pic_height_in_luma_samples;

  if (chroma_format_idc==0 || separate_colour_plane_flag) {
    CtbWidthC  = 0;
    CtbHeightC = 0;
  }
  else {
    CtbWidthC  = CtbSizeY / SubWidthC;
    CtbHeightC = CtbSizeY / SubHeightC;
  }

  Log2MinTrafoSize = log2_min_transform_block_size;
  Log2MaxTrafoSize = log2_min_transform_block_size + log2_diff_max_min_transform_block_size;

  if (max_transform_hierarchy_depth_inter > Log2CtbSizeY - Log2MinTrafoSize) {
    if (sanitize_values) {
      max_transform_hierarchy_depth_inter = Log2CtbSizeY - Log2MinTrafoSize;
    } else {
      fprintf(stderr,"SPS error: transform hierarchy depth (inter) > CTB size - min TB size\n");
      return DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE;
    }
  }

  if (max_transform_hierarchy_depth_intra > Log2CtbSizeY - Log2MinTrafoSize) {
    if (sanitize_values) {
      max_transform_hierarchy_depth_intra = Log2CtbSizeY - Log2MinTrafoSize;
    } else {
      fprintf(stderr,"SPS error: transform hierarchy depth (intra) > CTB size - min TB size\n");
      return DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE;
    }
  }


  if (sanitize_values) {
    if (max_transform_hierarchy_depth_inter < Log2CtbSizeY - Log2MaxTrafoSize) {
      max_transform_hierarchy_depth_inter = Log2CtbSizeY - Log2MaxTrafoSize;
    }

    if (max_transform_hierarchy_depth_intra < Log2CtbSizeY - Log2MaxTrafoSize) {
      max_transform_hierarchy_depth_intra = Log2CtbSizeY - Log2MaxTrafoSize;
    }
  }


  Log2MinPUSize = Log2MinCbSizeY-1;
  PicWidthInMinPUs  = PicWidthInCtbsY  << (Log2CtbSizeY - Log2MinPUSize);
  PicHeightInMinPUs = PicHeightInCtbsY << (Log2CtbSizeY - Log2MinPUSize);

  Log2MinIpcmCbSizeY = log2_min_pcm_luma_coding_block_size;
  Log2MaxIpcmCbSizeY = (log2_min_pcm_luma_coding_block_size +
                        log2_diff_max_min_pcm_luma_coding_block_size);

  // the following are not in the standard
  PicWidthInTbsY  = PicWidthInCtbsY  << (Log2CtbSizeY - Log2MinTrafoSize);
  PicHeightInTbsY = PicHeightInCtbsY << (Log2CtbSizeY - Log2MinTrafoSize);
  PicSizeInTbsY = PicWidthInTbsY * PicHeightInTbsY;


  if (range_extension.high_precision_offsets_enabled_flag) {
    WpOffsetBdShiftY = 0;
    WpOffsetBdShiftC = 0;
    WpOffsetHalfRangeY = 1 << (BitDepth_Y - 1);
    WpOffsetHalfRangeC = 1 << (BitDepth_C - 1);
  }
  else {
    WpOffsetBdShiftY = ( BitDepth_Y - 8 );
    WpOffsetBdShiftC = ( BitDepth_C - 8 );
    WpOffsetHalfRangeY = 1 << 7;
    WpOffsetHalfRangeC = 1 << 7;
  }


  // --- check SPS sanity ---

  if (pic_width_in_luma_samples  % MinCbSizeY != 0 ||
      pic_height_in_luma_samples % MinCbSizeY != 0) {
    // TODO: warn that image size is coded wrong in bitstream (must be multiple of MinCbSizeY)
    fprintf(stderr,"SPS error: CB alignment\n");
    return DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE;
  }

  if (Log2MinTrafoSize > Log2MinCbSizeY) {
    fprintf(stderr,"SPS error: TB > CB\n");
    return DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE;
  }

  if (Log2MaxTrafoSize > libde265_min(Log2CtbSizeY,5)) {
    fprintf(stderr,"SPS error: TB_max > 32 or CTB\n");
    return DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE;
  }


  if (BitDepth_Y < 8 || BitDepth_Y > 16) {
    fprintf(stderr,"SPS error: bitdepth Y not in [8;16]\n");
    return DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE;
  }

  if (BitDepth_C < 8 || BitDepth_C > 16) {
    fprintf(stderr,"SPS error: bitdepth C not in [8;16]\n");
    return DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE;
  }


  sps_read = true;

  return DE265_OK;
}